[英]Android Background Service causes a lot of crashes
我有一個即時服務,可引起大量事故(每天約10.000次)的后台服務。
我所做的事情:使用onStartCommant
啟動服務並返回START_STICKY
。
onDestroy()
和onTaskRemoved()
調用廣播,重新啟動服務,以便它會更新,並且大多數情況下都有效。
現在,我認識到android設備管理器會建議將其設置為待機狀態,因為崩潰太多(在后台用戶不會注意到它)。
這是我的服務:
public static boolean isMyServiceRunning(Class<?> serviceClass, Context c) {
ActivityManager manager = (ActivityManager) c.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
public static MassageDataSource getMassageDataSource() {
return massageDataSource;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
if (context == null) {
context = this;
}
SQLiteDatabase.loadLibs(context);
if (massageDataSource == null) {
massageDataSource = new MassageDataSource(context);
massageDataSource.open();
}
startTimer();
return START_STICKY;
//return START_REDELIVER_INTENT;
}
@Override
public void onDestroy() {
super.onDestroy();
Intent broadcastIntent = new Intent(context, RestartService.class);
sendBroadcast(broadcastIntent);
}
@Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Intent broadcastIntent = new Intent(context, RestartService.class);
sendBroadcast(broadcastIntent);
}
public void startTimer() {
//set a new Timer
timer = new Timer();
//initialize the TimerTask's job
initializeTimerTask();
//schedule the timer, to wake up every 1 second
timer.schedule(timerTask, 1000, 1000); //
}
/**
* it sets the timer to print the counter every x seconds
*/
public void initializeTimerTask() {
timerTask = new TimerTask() {
public void run() {
Log.i("in timer", "in timer ++++ " + (counter++));
}
};
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
這是我的廣播:
@Override
public void onReceive(Context context, Intent intent) {
Log.i(RestartService.class.getSimpleName(), "Service Stopped!");
if (!BackgroundService.isMyServiceRunning(BackgroundService.class, context)) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent service = new Intent(context, BackgroundService.class);
PendingIntent pendingIntent;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
pendingIntent = PendingIntent.getForegroundService(context, BackgroundService.SERVICE_ID, service, PendingIntent.FLAG_CANCEL_CURRENT);
} else {
pendingIntent = PendingIntent.getService(context, BackgroundService.SERVICE_ID, service, PendingIntent.FLAG_CANCEL_CURRENT);
}
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), intervall, pendingIntent);
Log.i(RestartService.class.getSimpleName(), "Service restarted.");
} else {
Log.i(RestartService.class.getSimpleName(), "Service is already running");
}
}
該服務運行8秒鍾,然后通過廣播正常運行而停止並重新啟動。 但是每次銷毀它都會崩潰,並在logcat上產生以下輸出:
Thread[3,tid=17948,WaitingInMainSignalCatcherLoop,Thread*=0x75b3a16400,peer=0x13b80020,"Signal Catcher"]: reacting to signal 3
Wrote stack traces to '[tombstoned]'
D/ConnectivityManager_URSP: Ursp sIsUrsp=false, sIsCheckUrsp=false, uid=10291
D/Proxy: urspP is null: 10291
I/LoadedApk: No resource references to update in package com.test.module1
I/LoadedApk: No resource references to update in package com.test.module2
D/SensorManager: registerListener :: 10, TMD4906 lux Sensor, 66667, 0,
I/RestartService: Service Stopped!
I/RestartService: Service restarted.
我讀到是START_STICKY
引起的,所以我嘗試了其他命令,但只有使用START_STICKY
我的服務才不會消失。
同樣由於某些原因,服務無法在啟動時啟動。
如果您返回START_REDELIVER_INTENT , START_STICKY和相關標志,則Android框架將使服務保持活動狀態(或為您重新創建)。
doc中對START_REDELIVER_INTENT的描述:
從
onStartCommand(Intent, int, int)
返回的常量:如果此服務的進程在啟動時被殺死(從onStartCommand(Intent, int, int))
返回之后onStartCommand(Intent, int, int))
,則它將安排重新啟動,並計划最后一次交付的Intent通過onStartCommand(Intent, int, int)
重新傳遞給它。 在服務調用stopSelf(int)
並將其提供給onStartCommand(Intent, int, int)
的開始ID之前,將一直計划該Intent進行重新交付 。
因此,我建議使用Android的框架行為來實現,方法是通過返回START_REDELIVER_INTENT使服務由於某種原因被殺死后再次運行,而不調用Service.stopSelf()
或Context.stopService()
。
但是,如果您需要使用廣播機制來執行此操作,則可以只返回START_NOT_STICKY以防止系統為您執行此操作。 並且系統不會重新創建服務,這將導致多次調用onStartCommand()
並導致崩潰。
有關onStartCommand()
更多詳細信息,請參考文檔 。
更新:
如上所述,我現在要返回START_NOT_STICKY。 但這無法解決問題。 所以我決定將startInForeground用於api> = 26(Android Oreo)。 現在,該服務永遠存在,並且沒有問題。
我唯一不喜歡的當然是始終有一個通知。 我想要像Whatsapp使用的后台服務。 他們的后台服務一直在運行,如果它被銷毀或出現其他情況,會出現一條通知“您可能有新消息”,然后該服務又恢復了生命,通知也消失了。
所以我現在做的是:
-廣播還是一樣
-后台服務:
@Override
public void onCreate() {
super.onCreate();
Log.i("BackgroundService", "onCreate was called");
SQLiteDatabase.loadLibs(this);
messageDataSource = new MessageDataSource(this);
messageDataSource.open();
startForegroundService();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
Log.i("BackgroundService", "onStartCommand was called");
context = this;
return START_NOT_STICKY;
}
public void startForegroundService() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ChannelID = createNotificationChannel("app_service_1", "Benachrichtigungen", NotificationManager.IMPORTANCE_NONE);
} else {
ChannelID = "app_service_1";
}
startForeground(101, buildForegroundNotification("Sie könnten neue Nachrichten haben")); //should use resource string
}
@Override
public void onDestroy() {
super.onDestroy();
Intent broadcastIntent = new Intent(context, RestartService.class);
sendBroadcast(broadcastIntent);
}
@Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Intent broadcastIntent = new Intent(context, RestartService.class);
sendBroadcast(broadcastIntent);
}
private Notification buildForegroundNotification(String message) {
NotificationCompat.Builder b = new NotificationCompat.Builder(this, ChannelID);
b.setOngoing(true)
.setContentTitle("MyApp")
.setContentText(message)
.setSmallIcon(com.app.R.drawable.schloss_deutsch4);//dauerhafte Benachrichtigung in der Leiste
//.setSmallIcon(1); //aufgrund eines Fehlers läuft der Dienst dauerhaft aber ohne Benachrichtigung
return (b.build());
}
@RequiresApi(Build.VERSION_CODES.O)
private String createNotificationChannel(String channelId, String channelName, int importance) {
android.app.NotificationChannel chan = new NotificationChannel(channelId,
channelName, importance);
chan.setLightColor(Color.BLUE);
chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
NotificationManager service = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
service.createNotificationChannel(chan);
return channelId;
}
所以我嘗試在onDestroy()和onTaskRemoved()中使用startForegroundService(),並刪除了startBroadcast(),也嘗試將其與startBroadcast()一起使用,並在onCreate()或onStartCommand()中使用stopForeground(true)停止通知。
想法是:如果服務因為在后台運行而沒有通知而被破壞,我將淡入通知,如果服務再次穩定,則將再次刪除該通知。
有沒有可能實現這一目標?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.