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

时间:2012-03-14 06:15:58

标签: android android-service

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

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

11 个答案:

答案 0 :(得分:42)

您可以使用foregroundstartForeground()中运行该服务。

  

前台服务是一种被认为是某种东西的服务   用户积极地意识到并因此不是系统的候选者   在内存不足时杀人。

但请记住,前台服务必须提供状态栏的通知(read here),并且除非服务被停止或从前台移除,否则无法解除通知。

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

答案 1 :(得分: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
}

“ServiceManager.startService()”的内容是:

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

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

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

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

<receiver android:name=".app.ServiceDestroyReceiver" >
        <intent-filter>
            <action android:name="YouWillNeverKillMe" >
            </action>
        </intent-filter>
    </receiver>

最后,创建一个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();
}

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

答案 2 :(得分:11)

在服务类中覆盖方法onStartCommand(),然后只返回START_STICKY(由“它不为空”)。这就是你所需要的。如果运行服务的进程被杀死(例如,通过低内存条件),Android系统将自动重启(通常有一些延迟,如5秒)。

不要再按照另一个答案的建议使用onStart(),不推荐使用它。

答案 3 :(得分: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;
} 

ref Documentation服务生命周期。

编辑添加的方法。

答案 4 :(得分:5)

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

  1. 使用活动(StartServicesActivity)将服务(FileObserverService)作为Foreground服务启动。
  2. 使用BroadcastReceiver类(在示例CommonReceiver中)在某些特殊情况下重启您的服务,以防它被杀死。
  3. 我在我的应用中使用了此代码&#34;自动发送电子邮件图片&#34; 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应用程序测试了此代码,每次服务被杀死时,它几乎立即重新启动(执行onStartCommand())。每次打开手机和重新启动后,它都会重新启动。 我在我的应用程序中使用此代码,该代码将您使用手机拍摄的每张照片通过电子邮件发送到预先确定的电子邮件列表。发送电子邮件和接收电子邮件列表在另一个活动中设置,并存储在共享首选项中。我在几个小时内拍摄了大约100张照片,所有照片都被正确发送到接收电子邮件中。

答案 5 :(得分:5)

据我所知,只有在明确停止服务时才会调用onDestroy()(强制停止)。但是,如果服务被OS /刷过最近的应用程序列表杀死,则不会调用此方法。在这些情况下,另一个名为onTaskRemoved(Intent)的事件处理程序被调用。这是由于链接here中的Android 4.3-4.4存在缺陷。尝试使用以下代码: -

public void onTaskRemoved(Intent intent){
super.onTaskRemoved(intent);
Intent intent=new Intent(this,this.getClass()); 
startService(intent); 
}

答案 6 :(得分:3)

@Override
public void onDestroy() {

    super.onDestroy();
    startService(new Intent(this, YourService.class));

}

在您的服务中写上面的代码,您的服务永远不会停止,即使用户想要销毁它,或者他们想要杀死它,它永远不会杀死直到你的应用程序没有从你的设备卸载

答案 7 :(得分:2)

您可以尝试重复启动服务,例如每5秒启动一次。 这样,当您的服务运行时,它将每5秒执行onStartCommand()。我测试了这个方案并且它非常可靠,但不幸的是它增加了一些电话开销。 以下是您在活动中启动服务的代码。

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;

}

答案 8 :(得分:0)

首先在另一个进程中创建服务,然后编写以时间间隔递归运行的广播器

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");


    }

};

在主进程中的寄存器广播接收器之后还有在服务到达后第一次广播后启动的定时器递归

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”尚未到达

答案 9 :(得分:-3)

我找到了一个解决方案....迟到的答案,但我想回答......

我们可以在服务的ondestroy中发送广播并创建一个接收广播的接收器并再次启动服务....当它被任何原因销毁时......

答案 10 :(得分:-4)

请尝试以下:

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"/>