Android Service(三) 保证Service不被后台销毁

·  阅读 2061

「这是我参与11月更文挑战的第2天,活动详情查看:2021最后一次更文挑战

保证Service不被后台销毁

Service:服务是android系统中非常重要的组件。Service可以脱离应用程序运行。也就是说,应用程序只起到一个启动Service的作用。一旦Service被启动,就算应用程序关闭,Service仍然会在后台运行。android系统中的Service主要有两个作用:后台运行和跨进程通讯。后台运行就不用说了,当Service启动后,就可以在Service对象中 运行相应的业务代码,而这一切用户并不会察觉。如果想让应用程序可以跨进程通讯,就要使用AIDL服务,AIDL的全称是Android Interface Definition Language,也就是说,AIDL实际上是一种Android接口定义语言。通过这种语言定义接口后,Android Studio编译后会自动生成相应的Java代码接口代码。

保证Service不被后台销毁的方式

一、在onStartCommand方法中,返回START_STICKY

在StartCommand()几个常量:

START_STICKY 系统重新创建服务并且调用onStartCommand()方法,但并不会传递最后一次传递的intent,只是传递一个空的intent。除非存在将要传递来的intent,那么就会传递这些intent。这个适合播放器一类的服务,不需要执行命令,只需要独自运行,等待任务。

START_NOT_STICKY 系统不重新创建服务,除非有将要传递来的intent。这是最安全的选项,可以避免在不必要的时候运行服务。

START_REDELIVER_INTENT 系统重新创建服务并且调用onStartCommand()方法,传递最后一次传递的intent。其余存在的需要传递的intent会按顺序传递进来。这适合像下载一样的服务,立即恢复,积极执行。

@Override  
public int onStartCommand(Intent intent, int flags, int startId) {  
    flags = START_STICKY;  
    return super.onStartCommand(intent, flags, startId);  
}
复制代码

手动返回START_STICKY,亲测当service因内存不足被kill,当内存又有的时候,service又被重新创建,比较不错,但是不能保证任何情况下都被重建,比如进程被干掉了….

二、通过前台服务来提升Service的优先级

前台服务是被认为用于已知的正在运行的服务,当系统需要释放内存时不会优先杀掉该进程。前台进程必须发一个notification在状态栏中显示,知道进程被杀死。因为前台服务一直消耗一部分资源,但不像一般服务那样会在需要的时候被杀掉,所以为了节约资源,保护电池寿命,一定要在建前台服务的时候发送notification,提示用户。当然系统提供的方法就必须有notification参数的,所以不要想着怎么把notification隐藏掉。

@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
@Override
public void onCreate() {
    super.onCreate();
    Log.d(TAG, "onCreate: 已执行");
    Intent intent = new Intent(this, MainActivity.class);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
    Notification notification = new Notification.Builder(this)
            .setContentTitle("这是内容标题")
            .setContentText("这是内容正文")
            .setWhen(System.currentTimeMillis())
            .setSmallIcon(R.mipmap.ic_launcher)
            .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
            .setContentIntent(pendingIntent)
            .build();
    startForeground(1, notification);   //前台服务
}
复制代码

三、在onDestroy中发送广播,让广播来开启自己

服务+广播方式,就是当service调用到onDestroy的时候,发送一个自定义的广播,当收到广播的时候,重新启动service;

    <receiver
        android:name=".MyReceiver"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="com.peterli.localservicetest.destroy"/>
        </intent-filter>
    </receiver>
复制代码

在service中onDestroy的时候:

@Override
public void onDestroy() {
    Log.d(TAG, "onDestroy: ");
    stopForeground(true);  //有前台服务的时候把这句话加上
    Intent intent = new Intent("com.peterli.localservicetest.destroy");
    sendBroadcast(intent);
    super.onDestroy();
}
复制代码

在MyReceiver中:

public class MyReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
    assert intent.getAction() != null;
    if (intent.getAction().equals("com.peterli.localservicetest.destroy")) {
        Intent serviceIntent = new Intent(context, MyService.class);
        context.startService(serviceIntent);
    }
}
}
复制代码

当然,从理论上来讲这个方案是可行的,实验一下结果也是可行的。但是有些情况下,发送的广播在消息队列中排的靠后,就有可能服务还没有接收到广播就销毁了(只是猜想)。所以为了能让这个机制完美运行,可以开启两个服务,相互监听,相互启动。服务A监听B的广播来启动B,服务B监听A的广播来启动A。经过实验,这个方案是可行的。

分类:
Android
标签:
收藏成功!
已添加到「」, 点击更改