我们如何防止服务被操作系统杀死?

Rah*_*hul 45 android android-service

Service在我的应用程序中使用它需要运行,直到我的应用程序被卸载,但问题是它被操作系统杀死.

我们怎样才能防止它被操作系统杀死?或者,如果它被杀死,我们可以通过编程方式再次重启该服务吗?

Dhe*_*.S. 42

您可以使用startForeground()前台运行该服务.

前台服务是一种被认为是用户主动意识到的内容的服务,因此在内存不足时不会被系统杀死.

但请记住,前台服务必须提供状态栏的通知(在此处阅读),并且除非服务被停止或从前台删除,否则无法解除通知.

注意:这仍然不能绝对保证在极低内存条件下服务不会被杀死.它只会减少被杀的可能性.

  • 这就是Android处理低内存情况的方式.如果你真的需要Android不要杀死你的服务,最好的办法就是把它变成一个系统应用程序,或者让你的服务在`onStartCommand()`方法中返回`START_STICKY`.这样,如果您的服务被终止,那么它将排队等待自动重启. (5认同)
  • 感谢您的回复Dheeraj,但我不需要服务通知是否有任何其他方式运行服务而不会被OS杀死..你知道Wake_Lock .. (3认同)
  • 我已经在我的服务中合并了代码,你给了我一个链接startForeground().但有时我的服务也会被os杀死. (2认同)

小智 21

我最近对你的同样问题感到困惑.但现在,我找到了一个很好的解决方案.首先,您应该知道,即使您的服务被操作系统杀死,您的服务的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
}
Run Code Online (Sandbox Code Playgroud)

"ServiceManager.startService()"的内容是:

public static void startService() {
    Log.i(LOGTAG, "ServiceManager.startSerivce()...");
    Intent intent = new Intent(NotificationService.class.getName());
    context.startService(intent);
}
Run Code Online (Sandbox Code Playgroud)

但是,此解决方案仅适用于您的服务被GC杀死的情况.有时我们的服务可能会被程序管理器的用户杀死.在这种情况下,您的好处将被终止,您的服务将永远不会被重新实例化.因此,您的服务无法重新启动.但好消息是,当PM终止你的服务时,它会调用你的onDestroy方法.所以我们可以用这个方法做点什么.

    @Override
public void onDestroy() {
    Intent in = new Intent();
    in.setAction("YouWillNeverKillMe");
    sendBroadcast(in);
    Log.d(LOGTAG, "onDestroy()...");
}
Run Code Online (Sandbox Code Playgroud)

字符串"YouWillNeverKillMe"是一个自定义操作.这个方法最重要的是,在发送广播之前不要添加任何代码.由于系统不会等待onDestroy()的完成,你必须尽快发出广播.然后在manifast.xml中注册一个接收器:

<receiver android:name=".app.ServiceDestroyReceiver" >
        <intent-filter>
            <action android:name="YouWillNeverKillMe" >
            </action>
        </intent-filter>
    </receiver>
Run Code Online (Sandbox Code Playgroud)

最后,创建一个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();
}
Run Code Online (Sandbox Code Playgroud)

希望这对你有所帮助,并原谅我可怜的书面英语.

  • @Alaowan:你已经把重启代码放在不同的地方了.如果服务被GC或者那个PM杀死,那么在任何一种情况下如果调用onDestroy,那么在onDestroy本身调用startService要好得多,如上所述在[at] androidiseverythingforme的答案中? (3认同)
  • 您的代码阻止用户停止服务弊大于利,因为我认为用户应该控制自己的设备; 如果你试图阻止他们手动查杀你的服务,那对他们来说很烦人.我知道可能存在一些适当的情况,但这个问题是关于阻止*OS*杀死服务. (2认同)
  • 我不敢相信这个答案获得了13票. (2认同)
  • 请不要赞成这个答案.这是不正确的. (2认同)

小智 10

覆盖onStartCommand()服务类中的方法并简单地返回START_STICKY(如"它不是空白"所示).这就是你所需要的.如果运行您的服务的进程被杀死(例如,通过低内存条件),Android系统将自动重启(通常有一些延迟,如5秒).

不要onStart()再按照另一个答案中的建议使用它,它已被弃用.


Its*_*ank 9

使用

@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;
} 
Run Code Online (Sandbox Code Playgroud)

ref 文档服务生命周期.

编辑添加的方法.

  • 这似乎误导了我; 我不认为`START_STICKY`会阻止服务被杀.我认为它会导致它重新启动,如果它崩溃或被操作系统杀死. (4认同)
  • 文森特我已经使用了你的方法,但我的服务有时会再次被操作系统杀死......还有其他方法可以做到这一点。 (2认同)

Ale*_*Pap 5

我找到了另一个问题的解决方案,保证你的服务永远存在.在我的情况下,这个方案也重新解决了FileObserver的问题,它在一段时间后停止工作.

  1. 使用活动(StartServicesActivity)将服务(FileObserverService)作为Foreground服务启动.
  2. 使用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));
    }
}
Run Code Online (Sandbox Code Playgroud)

这是它在应用程序结束标记之前的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>
Run Code Online (Sandbox Code Playgroud)

在StartServicesActivity活动中启动服务.

Intent iFileObserver = new Intent(StartServicesActivity.this, FileObserverService.class);
StartServicesActivity.this.startService(iFileObserver);
Run Code Online (Sandbox Code Playgroud)

这是服务的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;
}
Run Code Online (Sandbox Code Playgroud)

我使用Task Killer应用程序测试了此代码,每次服务被杀死时,它几乎立即重新启动(执行onStartCommand()).每次打开手机和重新启动后,它都会重新启动.我在我的应用程序中使用此代码,该代码将您使用手机拍摄的每张照片通过电子邮件发送到预先确定的电子邮件列表.发送电子邮件和接收电子邮件列表在另一个活动中设置,并存储在共享首选项中.我在几个小时内拍摄了大约100张照片,所有照片都被正确发送到接收电子邮件中.


Kar*_*hik 5

据我所知,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); 
}
Run Code Online (Sandbox Code Playgroud)