Context.startForegroundService() 仅在 Android 11 Samsung 设备上没有调用 Service.startForeground()
Posted
技术标签:
【中文标题】Context.startForegroundService() 仅在 Android 11 Samsung 设备上没有调用 Service.startForeground()【英文标题】:Context.startForegroundService() did not then call Service.startForeground() only on Android 11 Samsung devices 【发布时间】:2021-05-31 18:47:00 【问题描述】:我只在运行 android 11 的三星设备上遇到此崩溃。显然该应用程序正在调用 startForegroundService(intent)
并要求我发布通知让用户知道我正在运行前台服务,但此调用是对 @987654322 @从未在应用程序源代码中制作,三星是否有可能制作了android 11的自定义实现并在我调用startService(intent)
时自动调用startForegroundService(intent)
?
堆栈跟踪
Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord4ab4323 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)
我使用context.startService(intent)
启动服务,服务在应用的OnResume中启动,上下文就是应用上下文。
这也是服务在清单中的声明方式
<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>
这是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 平台的崩溃,同一崩溃的其他实例发生的频率较低,因此它们在崩溃列表中的排名靠后在火力基地上。
【问题讨论】:
嘿,我也面临同样的问题。你有解决办法吗? @vishusrivastava 您正在构建媒体播放器应用程序吗? 是的,应用中有播客功能。 您只需要确保您的应用程序在前台服务启动时发布通知。就像大多数答案所说的那样。 我的情况有点不同,因为我没有在应用程序中启动前台服务,但是当单击耳机的播放按钮并且我的应用程序是 androidx.media.session.MediaButtonReceiver 调用前台时最后一个播放音频的应用。 【参考方案1】:更新
可能的原因
在您提供更多代码后,您是否在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;
修复
通过将startForeground()
添加到onCreate()
,问题得到解决。请注意,我准备参数和使用方法的方式只是草稿。详细信息请查看官方文档here。
...
@Override
public void onCreate()
super.onCreate();
Notification testNotification = new Notification();
int testId = 1;
startForeground(testId, testNotification);
...
【讨论】:
【参考方案2】:对于一些需要做工作的前台服务需要访问location
、microphone
、mediaProjection
、phoneCall
、camera
、dataSync
、connectedDevice
和mediaPlayback
,必须在清单中指定"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)
你做到了吗?
【讨论】:
以上是关于Context.startForegroundService() 仅在 Android 11 Samsung 设备上没有调用 Service.startForeground()的主要内容,如果未能解决你的问题,请参考以下文章