我的用户报告了数百次崩溃,但仍然无法找到解决方法。这些崩溃来自Android 8(三星,华为,谷歌)。
我遇到了这两起崩溃事件:
Fatal Exception: android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1881)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6938)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
和另一个:
Fatal Exception: android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2104)
at android.os.Handler.dispatchMessage(Handler.java:108)
at android.os.Looper.loop(Looper.java:166)
at android.app.ActivityThread.main(ActivityThread.java:7428)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921)
我认为这些崩溃是相同的,但正如您所见,堆栈跟踪显示不同的代码行。
问题是我无法重现它,我的设备和模拟器上的一切正常。但是,我(不知何故)通过创建服务而不调用startForeground()
类中的Service
来复制。
我无法“捕获”异常,因为它在创建服务5秒后立即来自系统级别。
我做了什么,我创建了一个创建粘性通知并调用startForeground
方法(我的服务类)的方法:
private void startWithNotification() {
Resources res = getResources();
String title = res.getString(R.string.application_name);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createChannels();
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, ANDROID_CHANNEL_ID)
.setContentTitle(title)
.setChannelId(ANDROID_CHANNEL_ID)
.setCategory(NotificationCompat.CATEGORY_SERVICE)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setOngoing(true)
.setAutoCancel(false)
.setSmallIcon(R.drawable.ic_siluette)
.setColor(ContextCompat.getColor(this, R.color.colorPrimary))
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.application_icon));
startForeground(NOTIFICATION_APP, builder.build());
}
private void createChannels() {
// create android channel
NotificationChannel androidChannel = new NotificationChannel(ANDROID_CHANNEL_ID, ANDROID_CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
// Sets whether notifications posted to this channel should display notification lights
androidChannel.enableLights(true);
// Sets whether notification posted to this channel should vibrate.
androidChannel.enableVibration(true);
// Sets the notification light color for notifications posted to this channel
androidChannel.setLightColor(Color.GREEN);
// Sets whether notifications posted to this channel appear on the lockscreen or not
androidChannel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.createNotificationChannel(androidChannel);
}
从不同的服务生命周期事件中调用此方法:
onCreate()
onStartCommand()
stopService()
onDestroy()
我在这些事件中调用方法,因为人们说可能没有创建服务并且它会自动销毁。
当通过BroadcastReceiver
进行来电或拨出电话时,服务即开始:
public class IncomingOutgoingCallReceiver extends BroadcastReceiver {
private void callAppService(Context context, int callType) {
Intent intent = new Intent(context, MyService.class);
Bundle bundle = new Bundle();
bundle.putInt(CALL_TYPE, callType);
intent.putExtras(bundle);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent);
}
else {
context.startService(intent);
}
}
private void onCallEnd(Context context) {
context.stopService(new Intent(context, MyService.class));
}
}
服务类:
public class MyService extends Service {
private void handleIntent(Intent intent) {
// Use intent data and do work
if (canStartService(intent)) {
return;
}
}
private boolean canStartService(Intent intent) {
// multiple checks
// if (intent bundle contains ... ) return false;
// if (phone number contains .... ) return false;
return true;
}
@Override
public void onCreate() {
super.onCreate();
startWithNotification();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
handleIntent(intent);
startWithNotification();
return START_NOT_STICKY;
}
private void startWithNotification() {
// Contains the code from above (didn't put here because of space)
}
@Override
public boolean stopService(Intent name) {
startWithNotification();
return super.stopService(name);
}
// Can be called from different Views which are attached to the WindowManager (user interacting with the UI)
public void stopService() {
startWithNotification();
stopForeground(true);
stopSelf();
}
@Override
public void onDestroy() {
startWithNotification();
super.onDestroy();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}