1.启动方式
Service有两种启动方式,分别通过startService方法和bindService方法启动
- startService通过这种方法启动的Service,在启动它的应用退出后,仍然会继续运行,除非服务自身调用stopSelf()或者外部接口调用stopService()方法才能停止服务;当服务停止时,系统会销毁服务
- bindService通过这种方法启动的Service,是与启动他的应用绑定在一起的,即应用退出时,该服务也退出;如果要停止服务,需要调用unBindService()方法> 通过startService启动的服务可以被绑定,即通过bindService()方法与Activity绑定。此时如果需要关闭Service,需要先调用方法unBindService()然后stopService(),否则Service是不会被关闭的
2.生命周期
通过StartService()启动
不论调用几次startService(),Service中onCreate()方法只调用一次,但是每次都会调用onStartCommand()
当调用stopService() / stopSelf()时,如果此时Service未与任何组件绑定,会直接调用onDestroy()方法销毁服务
通过onBindService()绑定
不论调用几次bindService(),Service中onCreate()方法只调用一次,但是每次都会调用onBind()
当调用unBindService()时,系统会回调一个onUnbind()回调方法,然后再销毁服务
先通过onStartService()启动,再通过onBindService()绑定
不论调用几次startService(),Service中onCreate()方法只调用一次,但是每次都会调用onStartCommand()
当终止Service时,需要先unbindService(),再stopService()。如果先调用stopService()将不会停止Service
附加参数
onStartCommand() 提供一个返回值,告诉系统在onStartCommand()方法调用结束后Service被kill时如何重启Service。返回值有如下几种
- START_STICKY 如果Service被kill,那么系统会在随后试图重新启动Service,但是不会继续使用前次传入的Intent对象
- START_NOT_STICKY 如果Service被kill,系统不会试图重新启动Service
- START_REDELIVER_INTENT 类似于START_STICKY,但是会重新传入Intent对象
- START_STICKY_COMPATIBILITY START_STICKY的兼容版本,当START_STICKY不好使时可以试一下这个参数
Foreground Service
使用Foreground Service,使Service在内存回收中获得更高优先级,比后台Service更不容易被系统kill通过在Service的onStartCommand()回调方法中调用startForeground()方法,可以让Service在前台运行通过调用stopForeground()方法,可以让Service停止前台运行,但是Service本身不会被停止
保证service不被杀掉
1.onStartCommand方法,返回START_STICKY
//onStartCommand方法,返回START_STICKY
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
flags = START_STICKY;
return super.onStartCommand(intent, flags, startId);
}
**【结论】 **手动返回START_STICKY,亲测当service因内存不足被kill,当内存又有的时候,service又被重新创建,比较不错,但是不能保证任何情况下都被重建,比如进程被干掉了....
2.提升service优先级
在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = "1000"这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时适用于广播。
<service
android:name="com.dbjtech.acbxt.waiqin.UploadService"
android:enabled="true" >
<intent-filter android:priority="1000" >
<action android:name="com.dbjtech.myservice" />
</intent-filter>
</service>
【结论】目前看来,priority这个属性貌似只适用于broadcast,对于Service来说可能无效
3. Android开发之如何保证Service不被杀掉(broadcast+system/app)
服务不被杀死分3种来讨论
1.系统根据资源分配情况杀死服务
2.用户通过 settings
-> Apps
-> Running
-> Stop
方式杀死服务
3.用户通过 settings
-> Apps
-> Downloaded
-> Force Stop
方式杀死服务
第一种情况:
用户不干预,完全靠系统来控制,办法有很多。比如 onStartCommand() 方法的返回值设为 START_STICKY
,服务就会在资源紧张的时候被杀掉,然后在资源足够的时候再恢复。当然也可设置为前台服务,使其有高的优先级,在资源紧张的时候也不会被杀掉。
第二种情况:
用户干预,主动杀掉运行中的服务。这个过程杀死服务会通过服务的生命周期,也就是会调用 onDestory() 方法,这时候一个方案就是在 onDestory() 中发送广播开启自己。这样杀死服务后会立即启动。如下:
@Override
public void onCreate() { // TODO Auto-generated method stub
super.onCreate();
mBR = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Intent a = new Intent(ServiceA.this, ServiceA.class);
startService(a);
}
};
mIF = new IntentFilter();
mIF.addAction("listener");
registerReceiver(mBR, mIF);
}
@Override
public void onDestroy() {
super.onDestroy();
Intent intent = new Intent();
intent.setAction("listener");
sendBroadcast(intent);
unregisterReceiver(mBR);
}
当然,从理论上来讲这个方案是可行的,实验一下也可以。但有些情况下,发送的广播在消息队列中排的靠后,就有可能服务还没接收到广播就销毁了(这是我对实验结果的猜想,具体执行步骤暂时还不了解)。所以为了能让这个机制完美运行,可以开启两个服务,相互监听,相互启动。服务A监听B的广播来启动B,服务B监听A的广播来启动A。经过实验,这个方案可行,并且用360杀掉后几秒后服务也还是能自启的。到这里再说一句,如果不是某些功能需要的服务,不建议这么做,会降低用户体验。
第三种情况:
强制关闭就没有办法。这个好像是从包的level去关的,并不走完整的生命周期。所以在服务里加代码是无法被调用的。处理这个情况的唯一方法是屏蔽掉 force stop
和 uninstall
按钮,让其不可用。方法自己去找吧。当然有些手机自带的清理功能就是从这个地方清理的,比如华为的清理。所以第三种情况我也没有什么更好的办法了。