我们如何防止服务被操作系统杀死?
我在我的应用程序中使用Service
,它需要运行,直到我的应用程序卸载,但问题是它被操作系统杀死。
我们如何防止它被操作系统杀死? 或者,如果它被杀害,我们可以通过编程重新启动该服务吗?
你可以使用startForeground()在前台运行服务。
前台服务是被认为是用户主动注意到的服务,因此当内存不足时,系统不会杀死它。
但请记住,前台服务必须提供状态栏的通知(请阅读此处 ),并且除非服务被停止或从前台移除,否则通知不能被解除。
注意:这仍然不能保证服务在极低的内存条件下不会被终止。 它只是使它不太可能被杀死。
最近我对你的问题感到困惑,但现在我find了一个好的解决scheme。 首先,你应该知道,即使你的服务被OS所杀,你的服务的onCreate方法将在短时间内被OS调用。所以你可以使用onCreate方法做这样的事情:
@Override public void onCreate() { Log.d(LOGTAG, "NotificationService.onCreate()..."); //start this service from another class ServiceManager.startService(); } @Override public void onStart(Intent intent, int startId) { Log.d(LOGTAG, "onStart()..."); //some code of your service starting,such as establish a connection,create a TimerTask or something else }
“ServiceManager.startService()”的内容是:
public static void startService() { Log.i(LOGTAG, "ServiceManager.startSerivce()..."); Intent intent = new Intent(NotificationService.class.getName()); context.startService(intent); }
但是,这个解决scheme只适用于你的服务被GC杀死的情况,有时我们的服务可能会被程序pipe理员用户杀死。在这种情况下,你的程序员将被杀死,你的服务将永远不会被重新实例化。所以你的服务无法重新启动。 但好消息是,当PM终止你的服务时,它会调用你的onDestroy方法。所以我们可以用这个方法做一些事情。
@Override public void onDestroy() { Intent in = new Intent(); in.setAction("YouWillNeverKillMe"); sendBroadcast(in); Log.d(LOGTAG, "onDestroy()..."); }
“YouWillNeverKillMe”string是一个自定义操作。 这种方法最重要的是,在发送广播之前不要添加任何代码。由于系统不会等待onDestroy()完成,所以你必须尽快发送广播。 然后在manifast.xml中注册一个接收者:
<receiver android:name=".app.ServiceDestroyReceiver" > <intent-filter> <action android:name="YouWillNeverKillMe" > </action> </intent-filter> </receiver>
最后,创build一个BroadcastReceiver,并在onReceive方法中启动你的服务:
@Override public void onReceive(Context context, Intent intent) { Log.d(LOGTAG, "ServeiceDestroy onReceive..."); Log.d(LOGTAG, "action:" + intent.getAction()); Log.d(LOGTAG, "ServeiceDestroy auto start service..."); ServiceManager.startService(); }
希望这对你有所帮助,请原谅我可怜的英文。
在您的服务类中覆盖方法onStartCommand()
,并简单地返回START_STICKY
(如“其非空白”所示)。 这就是你所需要的。 如果运行你的服务的进程被杀死(例如内存不足),Android系统将自动重启(通常有一些延迟,比如5秒)。
不要再使用onStart()
,如另一个答案中的build议,它已被弃用。
使用
@Override public int onStartCommand(Intent intent, int flags, int startId) { //**Your code ** // We want this service to continue running until it is explicitly // stopped, so return sticky. return START_STICKY; }
ref服务的文档生命周期。
编辑添加的方法。
我发现问题的另一个解决scheme,保证你的服务将永远活着。 在我的情况下,这个scheme还使用FileObserver的问题,在一段时间后停止工作。
- 使用活动(StartServicesActivity)作为Foreground服务启动服务(FileObserverService)。
- 使用BroadcastReceiver类(例如CommonReceiver)在某些特殊情况下重新启动服务,以防止它被终止。
我在我的应用程序“自动电子邮件图片”中使用此代码https://play.google.com/store/apps/details?id=com.alexpap.EmailPicturesFree
这是CommonReceiver类。
public class CommonReceiver extends BroadcastReceiver { public void onReceive(Context paramContext, Intent paramIntent) { paramContext.startService(new Intent(paramContext, FileObserverService.class)); } }
这是AndroidManifest.xml中的应用程序结束标记之前的定义。
<receiver android:name="com.alexpap.services.CommonReceiver"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED"/> </intent-filter> <intent-filter> <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/> </intent-filter> <intent-filter> <action android:name="android.intent.action.USER_PRESENT"/> </intent-filter> </receiver>
在StartServicesActivity活动中启动服务。
Intent iFileObserver = new Intent(StartServicesActivity.this, FileObserverService.class); StartServicesActivity.this.startService(iFileObserver);
这是服务的onStartCommand()方法。
public int onStartCommand(Intent intent, int flags, int startId) { int res = super.onStartCommand(intent, flags, startId); /*** Put your code here ***/ startServiceForeground(intent, flags, startId); return Service.START_STICKY; } public int startServiceForeground(Intent intent, int flags, int startId) { Intent notificationIntent = new Intent(this, StartServicesActivity.class); notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); Notification notification = new NotificationCompat.Builder(this) .setContentTitle("File Observer Service") .setContentIntent(pendingIntent) .setOngoing(true) .build(); startForeground(300, notification); return START_STICKY; }
我使用Task Killer应用程序testing了这个代码,每次服务被杀死后,它几乎立即重新启动(执行onStartCommand())。 每次打开电话和重新启动后,都会重新启动。 我在我的应用程序中使用此代码,通过电子邮件将您用手机拍摄的每张照片发送给预定义的电子邮件列表。 发送电子邮件和接收电子邮件列表被设置在另一个活动中,并存储在共享首选项中。 我在几个小时内拍了大约100张照片,所有这些照片都被正确地发送到接收邮件。
@Override public void onDestroy() { super.onDestroy(); startService(new Intent(this, YourService.class)); }
在你的服务中写上面的代码,你的服务将永远不会停止,即使用户想要销毁它,或者他们想杀了它,它永远不会杀死,直到你的应用程序不会从你的设备卸载
您可以尝试重复启动您的服务,例如每5秒。 这样,当你的服务运行时,它会每5秒执行一次onStartCommand()。 我testing了这个scheme,这是非常可靠的,但不幸的是,它略微增加了手机的开销。 以下是您在开始服务的活动中的代码。
Intent iFileObserver = new Intent(StartServicesActivity.this, FileObserverService.class); PendingIntent pendingIntentFileObserver = PendingIntent.getService(StartServicesActivity.this, 0, iFileObserver, 0); AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE); Date now = new Date(); //start every 5 seconds alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, now.getTime(), 5*1000, pendingIntentFileObserver);
这里是onStartCommand()的服务。
//class variable public static boolean isStarted = false; public int onStartCommand(Intent intent, int flags, int startId) { int res = super.onStartCommand(intent, flags, startId); //check if your service is already started if (isStarted){ //yes - do nothing return Service.START_STICKY; } else { //no isStarted = true; } /**** the rest of your code ***/ return Service.START_STICKY; }
据我所知,只有在明确停止服务(强制停止)时,才会调用onDestroy()
)。 但是,如果服务被操作系统杀死/刷新最近的应用程序列表,这个方法将不会被调用。 在这些情况下,另一个名为onTaskRemoved(Intent)
事件处理程序被调用。 这是由于Android 4.3-4.4在这里的链接的缺陷。 尝试使用下面的代码: –
public void onTaskRemoved(Intent intent){ super.onTaskRemoved(intent); Intent intent=new Intent(this,this.getClass()); startService(intent); }
首先在另一个进程中创build服务,然后写一个以时间间隔recursion运行的广播器
protected CountDownTimer rebootService = new CountDownTimer(9000, 9000) { @Override public void onTick(long millisUntilFinished) { } @Override public void onFinish() { sendBroadcast(reboot); this.start(); Log.d(TAG, "rebootService sending PREVENT AUTOREBOT broadcast"); } };
在主服务器注册广播接收机之后,首先从服务广播到服务器之后启动定时器recursion
protected static class ServiceAutoRebooter extends BroadcastReceiver { private static ServiceAutoRebooter instance = null; private RebootTimer rebootTimer = null; private static ServiceAutoRebooter getInstance() { if (instance == null) { instance = new ServiceAutoRebooter(); } return instance; } public class RebootTimer extends CountDownTimer { private Context _context; private Intent _service; public RebootTimer(long millisInFuture, long countDownInterval) { super(millisInFuture, countDownInterval); } @Override public void onTick(long millisUntilFinished) { } @Override public void onFinish() { _context.startService(_service); this.cancel(); Log.d(TAG, "Service AutoRebooted"); } } @Override public void onReceive(Context context, Intent intent) { if (rebootTimer == null) { Log.d(TAG, "rebootTimer == null"); rebootTimer = new RebootTimer(10000, 10000); rebootTimer._context = context; Intent service = new Intent(context, SomeService.class); rebootTimer._service = service; rebootTimer.start(); } else { rebootTimer.cancel(); rebootTimer.start(); Log.d(TAG, "rebootTimer is restarted"); } } }
如果RebootTimer(主进程)的时间到期,服务将自动重启,这意味着从服务广播的“PREVENT AUTOREBOT”还没有到达
我find了一个解决scheme….迟到的答案,但我想回答…
我们可以在服务的ondestroy发送一个广播,并创build一个接收器,接收广播,并再次启动服务….当它被任何原因破坏…
请尝试以下内容:
final Messenger mMessenger = new Messenger(new IncomingHandler()); class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { default: super.handleMessage(msg); } } } @Override public void onCreate() { super.onCreate(); makeServiceForeground(); } @Override public IBinder onBind(Intent arg0) { return mMessenger.getBinder(); } private void makeServiceForeground() { IActivityManager am = ActivityManagerNative.getDefault(); try { am.setProcessForeground(onBind(null), android.os.Process.myPid(), true); } catch (RemoteException e) { Log.e("", "cant set to foreground" + e.toString()); } }
还需要在manifest.xml中添加
<uses-permission android:name="android.permission.SET_PROCESS_LIMIT"/>