Context.startForegroundService()没有在Android 11三星设备上调用Service.startForeground()函数。

10
我只在运行Android 11的三星设备上遇到了崩溃问题。显然,应用程序正在调用startForegroundService(intent),要求我发布通知以让用户知道我正在运行前台服务,但是应用程序源代码中从未调用过startForegroundService(intent)。难道三星对Android 11进行了定制实现,每当我调用startService(intent)时就会自动调用startForegroundService(intent)吗? 堆栈跟踪
Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{4ab4323 u0 {app package name}/{library package name}.player.PlayerService}
android.app.ActivityThread$H.handleMessage (ActivityThread.java:2240)
android.os.Handler.dispatchMessage (Handler.java:106)
android.os.Looper.loop (Looper.java:246)
android.app.ActivityThread.main (ActivityThread.java:8506)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:602)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1130)

我在应用程序的OnResume中使用context.startService(intent)来启动服务,上下文是应用程序上下文。

此外,以下是服务在清单文件中的声明方式:

 <service
            android:name=".player.PlayerService"
            android:exported="false"
            android:foregroundServiceType="mediaPlayback"
            android:stopWithTask="false">
            <intent-filter>
                <action android:name="android.intent.action.MEDIA_BUTTON" />
            </intent-filter>
  </service>

更新:我找到了调用 startForegroundService(Intent) 的原因。我使用了来自Android的以下接收器来帮助处理操作控制设备,比如耳机按钮。因此,由于我将应用程序转换为androidx,它开始使用新的MediaButtonReceiver

 <receiver android:name="androidx.media.session.MediaButtonReceiver">
            <intent-filter>
                <action android:name="android.intent.action.MEDIA_BUTTON" />
            </intent-filter>
 </receiver>

这是接收器接收事件时执行的代码。
@Override
    public void onReceive(Context context, Intent intent) {
        if (intent == null
                || !Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())
                || !intent.hasExtra(Intent.EXTRA_KEY_EVENT)) {
            Log.d(TAG, "Ignore unsupported intent: " + intent);
            return;
        }
        ComponentName mediaButtonServiceComponentName =
                getServiceComponentByAction(context, Intent.ACTION_MEDIA_BUTTON);
        if (mediaButtonServiceComponentName != null) {
            intent.setComponent(mediaButtonServiceComponentName);
            startForegroundService(context, intent);
            return;
        }
        ComponentName mediaBrowserServiceComponentName = getServiceComponentByAction(context,
                MediaBrowserServiceCompat.SERVICE_INTERFACE);
        if (mediaBrowserServiceComponentName != null) {
            PendingResult pendingResult = goAsync();
            Context applicationContext = context.getApplicationContext();
            MediaButtonConnectionCallback connectionCallback =
                    new MediaButtonConnectionCallback(applicationContext, intent, pendingResult);
            MediaBrowserCompat mediaBrowser = new MediaBrowserCompat(applicationContext,
                    mediaBrowserServiceComponentName, connectionCallback, null);
            connectionCallback.setMediaBrowser(mediaBrowser);
            mediaBrowser.connect();
            return;
        }
        throw new IllegalStateException("Could not find any Service that handles "
                + Intent.ACTION_MEDIA_BUTTON + " or implements a media browser service.");
    }

您可以看到,它实际上启动了一个前台服务,我仍在调查崩溃,但至少我知道应用程序中启动了前台服务。

此外,这个崩溃不仅发生在三星手机上,我之前认为Crashlytics报告将三星的崩溃分组在一起是因为它是来自Android平台的崩溃,其他相同崩溃的实例发生频率较低,所以它们在Firebase的崩溃列表中排名靠后。


嗨,我也遇到了同样的问题。你有找到任何解决方案吗? - vishu srivastava
@vishusrivastava,你在开发一个媒体播放器应用程序吗? - oziomajnr
是的,应用程序中有播客功能。 - vishu srivastava
你只需要确保在前台服务启动时,你的应用程序发布一个通知。就像大多数答案所述。 - oziomajnr
我的情况有点不同,因为我没有在应用程序中启动前台服务,但是当从耳机点击播放按钮并且我的应用程序是最后一个播放音频的应用时,androidx.media.session.MediaButtonReceiver会调用前台。 - oziomajnr
2个回答

3

更新

可能的原因

在您提供了更多的代码之后,仍然不清楚您是否在PlayerService中调用了startForeground()。看起来您没有这样做,这就是为什么会发生崩溃的原因。另一方面,如果此崩溃仅发生在Android 11上,则您可能还有其他问题。

示例代码

我刚刚创建了一个简单的应用程序,以重现在未调用startForeground()时导致PlayerService崩溃的情况。也许它对您有所帮助。

app/build.gradle

添加一个依赖项,以使用androidx的MediaButtonReceiver

...
implementation "androidx.media:media:1.2.1" 
...

AndroidManifest.xml

...
    <service
        android:name=".PlayerService"
        android:exported="false"
        android:foregroundServiceType="mediaPlayback"
        android:stopWithTask="false">
        <intent-filter>
            <action android:name="android.intent.action.MEDIA_BUTTON" />
        </intent-filter>
    </service>

    <receiver android:name="androidx.media.session.MediaButtonReceiver">
        <intent-filter>
            <action android:name="android.intent.action.MEDIA_BUTTON" />
        </intent-filter>
    </receiver>   
...

MainActivity.java

以下是模拟媒体按钮事件的代码:

...
@Override
protected void onResume() {
    super.onResume();

    Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
    intent.setClass(this, MediaButtonReceiver.class);
    intent.putExtra(Intent.EXTRA_KEY_EVENT, "test");
    sendBroadcast(intent);
}
... 

PlayerService.java

public class PlayerService extends Service {

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        MediaButtonReceiver.handleIntent(null, intent);

        return super.onStartCommand(intent, flags, startId);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

修复

通过在onCreate()中添加startForeground()方法来解决问题。请注意,我准备参数和使用该方法的方式只是草稿。详细信息,请查看官方文档

...
    @Override
    public void onCreate() {
        super.onCreate();

        Notification testNotification = new Notification();
        int testId = 1;
        startForeground(testId, testNotification);
    }
...

-2

对于一些需要访问位置麦克风媒体投影电话相机数据同步连接设备媒体播放的前台服务,您必须在清单文件中指定"foregroundServiceType"并在调用startForeground时为服务设置ServiceInfo。我认为这可以解决您的问题。

编辑

您应该在服务的onStartCommand中像这样启动您的service

if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q){
            startForeground(NOTIFICATION_ID, notification)
        }
        else{
            startForeground(NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK)
        }

你做好了吗?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接