文章大纲
- 引言
- 一、Service的生命周期
- 二、Service的声明
- 三、Service的启动
- 四、如何保证Service不被杀死 ?
- 1、onStartCommand方式中,返回START_STICKY或则START_REDELIVER_INTENT
- 2、提高Service的优先级 在AndroidManifest.xml文件中对于intent-filter可以配置android:priority
- 3、在onDestroy方法里重启Service
- 4、提升Service进程的优先级
- 5、将APK安装到/system/app,变身为系统级应用
- 五、Service的类别
- 六、IntentService
- 七、Service 和IntentService
引言
Service(服务)是一种可以在后台执行长时间运行操作而没有用户界面的组件,如非特意指定,属于App进程的一部分代码,默认在主线程中创建并运行于主线程,由AMS去通知App去调用Service的生命周期函数。
一、Service的生命周期
方法 | 说明 |
---|---|
onCreate() | 首次创建服务时,系统将调用此方法。若服务已在运行,则不会调用此方法(只处触发一次) |
onStartCommand() | 当另一个组件通过调用startService() 请求启动服务时,系统将调用此方法。 |
onDestroy() | 当服务不再使用且将被销毁时,系统将调用此方法。 |
onBind() | 当另一个组件通过调用bindService() 与服务绑定时,系统将调用此方法。 |
onUnbind() | 当另一个组件通过调用unbindService() 与服务解绑时,系统将调用此方法。 |
onRebind() | 当旧的组件与服务解绑后,另一个新的组件与服务绑定,onUnbind() 返回true时,系统将调用此方法。 |
- onCreate()——如果service没被创建过,调用startService()后会执行onCreate()回调;如果service已处于运行中,调用startService()不会执行onCreate()方法。即onCreate()只会在第一次创建service时候调用,多次执行startService()不会重复调用onCreate(),此方法适合完成一些初始化工作。
- onStartComand()——服务启动时调用,此方法适合完成一些数据加载工作,比如会在此处创建一个线程用于下载数据或播放音乐。
- onBind()——服务被绑定时调用。
- onUnBind()——服务被解绑时调用。
- onDestroy()——服务停止时调用。
二、Service的声明
和其他四大组件一样,必须在清单文件中声明,原因是PMS需要从清单文件中解析出Service 并为其定义对应的数据结构。
三、Service的启动
Service 可通过两种方式启动:startService和bindService。
1、startService启动
通过 startService()
启动 Service 会执行 onCreate()
——>onStartCommand()
——>onDestroy()
方法。但在 startService(Intent intent) 后,之后只执行一次 onCreate()
方法,反复多次调用 startService 后,Service 只会重复执行 onStartCommand
——> onStart(已经过时)
方法,Service 停止后只执行一次 onDestroy
方法。通过这种方式启动 Service ,这个时候的 Service 几乎和 Activity 不能交互(不考虑全局变量的方式),在 Service 里面也没有 getIntent()
方法,完全与其他四大组件隔离且会一直运行下去,直到stopSelf()
或者stopService
被调用。
1.1、启动Service服务
-
单次——
startService() —> onCreate() —> onStartCommand()
-
多次——
startService() —> onCreate() —> onStartCommand() —> onStartCommand()
1.2、停止Service服务
stopService() —> onDestroy()
startService()通过这种方式调用startService,onCreate()只会被调用一次,多次调用startSercie会多次执行onStartCommand()和onStart()方法,如果外部没有调用stopService()或stopSelf()方法,service会一直运行。而bindService()方式启动,若该服务之前还没创建,系统回调顺序为onCreate()→onBind(),如果调用bindService()方法前服务已经被绑定,多次调用bindService()方法不会多次创建服务及绑定。如果调用者希望与正在绑定的服务解除绑定,可以调用unbindService()方法,回调顺序为onUnbind()→onDestroy()。
2、bindService 启动服务(Binder机制实现)
bindService(Intent intent ,ServiceConnection connetion,int flag)来启动 Service,相当于 Service和Context 绑定到一起, Service 启动的生命周期是:onCreate——>onBind(iBnder 会作为参数传递到 connect 中的 onServiceConnected 方法中),绑定后再次执行 bindService Service 什么都不执行。如果 Context 销毁了,则Service将会被销毁,执行 onUnbind -> onDestroy。
2.1、绑定Service服务
bindService() —> onCreate() —> onBind()
2.2、解绑Service服务
unbindService() —> onUnbind() —> onDestroy()
2.3、启动绑定Service服务
startService() —> onCreate() —> onStartCommand() —> bindService() —> onBind()
2.4、解绑停止Service服务
unbindService() —> onUnbind() —> stopService() —> onDestroy()
2.5、解绑绑定Service服务
unbindService() —> onUnbind(ture) —> bindService() —> onRebind()
四、如何保证Service不被杀死 ?
1、onStartCommand方式中,返回START_STICKY或则START_REDELIVER_INTENT
-
START_STICKY——如果返回START_STICKY,表示Service运行的进程被Android系统强制杀掉之后,Android系统会将该Service依然设置为started状态(即运行状态),但是不再保存onStartCommand方法传入的intent对象
-
START_NOT_STICKY——如果返回START_NOT_STICKY,表示当Service运行的进程被Android系统强制杀掉之后,不会重新创建该Service
-
START_REDELIVER_INTENT——如果返回START_REDELIVER_INTENT,其返回情况与START_STICKY类似,但不同的是系统会保留最后一次传入onStartCommand方法中的Intent再次保留
下来并再次传入到重新创建后的Service的onStartCommand方法中
2、提高Service的优先级 在AndroidManifest.xml文件中对于intent-filter可以配置android:priority
这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时适用于广播。
3、在onDestroy方法里重启Service
当service走到onDestroy()时,发送一个自定义广播,当收到广播时,重新启动service;
4、提升Service进程的优先级
进程优先级由高到低:前台进程 一 可视进程 一 服务进程 一 后台进程 一 空进程 ,可以使用startForeground将service放到前台状态,这样低内存时,被杀死的概率会低一些。
5、将APK安装到/system/app,变身为系统级应用
五、Service的类别
-
前台服务 foreground service ——通过startForegroundService 方法启动,提供一些可感知的操作,优先级比普通服务高些,耗时超过ActivityService#SERVICE_TIMEOUT(即20s)则ANR。
-
后台服务 background service——通过startService 启动,执行的操作对用户而言是不可感知的,耗时超过ActivityService#SERVICE_BACKGROUND_TIMEOUT(即200s)则ANR。
-
绑定服务 bound service——通过bindService启动,主要是提供c/s接口,允许组件与service进行通信或者是跨进程的通信。
前后台服务本质上执行的方法是一致的,区别在于传入的一个标记值,requireForeground,即一个boolean形的标志位决定是bg还是fg service。
六、IntentService
IntentService继承于Service, 它的实现相当于在Service的基础上增加了一个HandlerThread, 以及自定义的Handler, IntentService将所有的耗时操作放到HandlerThread线程中去处理, 当onHandleIntent处理完后,就会调用stopSelf来停止到这个Service,所以每次启动一个IntentService, 都是经过这样的生命周期 onCreate -> onStartCommand -> onStart -> onHandleIntent -> onDestroy
,其中onStart/onStartCommand
都将Intent route到了onHandleIntent中去处理。
public class MyIntentService extends IntentService {
public static UpdateUI updateUI;
public static void setUpdateUI(UpdateUI updateUIInterface){
updateUI=updateUIInterface;
}
@Override
protected void onHandleIntent(Intent intent) {
//在子线程中进行网络请求
Bitmap bitmap=downloadUrlBitmap(intent.getStringExtra(DOWNLOAD_URL));
Message msg1 = new Message();
msg1.what = intent.getIntExtra(INDEX_FLAG,0);
msg1.obj =bitmap;
//通知主线程去更新UI
if(updateUI!=null){
updateUI.updateUI(msg1);//通过Handler将msg1发送到主线程更新UI
}
}
@Override
public IBinder onBind(Intent intent) {
return super.onBind(intent);
}
public interface UpdateUI{
void updateUI(Message message);
}
private Bitmap downloadUrlBitmap(String urlString) {
....
return bitmap;
}
}
应用
public class IntentServiceActivity extends Activity implements MyIntentService.UpdateUI{
private String url[] = {..};
private static final Handler mUIHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
imageView.setImageBitmap((Bitmap) msg.obj);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_intent_service);
imageView = findViewById(R.id.image);
Intent intent = new Intent(this,MyIntentService.class);
for (int i=0;i<url.length;i++) {
intent.putExtra(MyIntentService.DOWNLOAD_URL,url[i]);
intent.putExtra(MyIntentService.INDEX_FLAG,i);
startService(intent);
}
MyIntentService.setUpdateUI(this);
}
@Override
public void updateUI(Message message) {
mUIHandler.sendMessageDelayed(message,message.what * 1000);
}
七、Service 和IntentService
Service是用于后台服务的,当应用程序被挂到后台的时候,为了保证应用某些组件仍然可以工作而引入了Service这个概念。Service既不是独立的进程,也不是独立的线程,它是依赖于应用程序的主线程的,因此不宜在Service中编写耗时的逻辑和操作,否则可能导致会引起ANR。为了解决这样的问题,引入了IntentService,IntentService是继承Service的,那么它包含了Service的全部特性,当然也包含service的生命周期。那么与service不同的是,IntentService在执行onCreate操作的时候,内部开了一个线程,去执行耗时操作IntentService,异步处理服务,新开一个线程,handlerThread在线程中发消息,然后接受处理完成后,会清理线程,并且关掉服务,再通过Handler 与主线程通信
未完待续…