「这是我参与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。经过实验,这个方案是可行的。