我们都知道Android消息机制是可以用来执行异步任务,而上一篇 Android HandlerThread最直白的解析 中,我们又聊过了HandlerThread,那么现在我们就来聊聊Android多线程中另一种常见的用法 IntentService,其内部线程的切换实质就是用 HandlerThread 来实现的。
首先用一段很直白的话来简单总结下什么是 IntentService及它的作用与使用场景:
- IntentService是一个继承了Service的抽象类,有较高的优先级;
- 开发者使用它能很方便的在后台执行耗时的异步任务,并且当任务完成后会自动停止;
- 使用IntentService执行的异步任务是按顺序执行的,其本身并不支持并发需求。
按照惯例,我们来看看官网对IntentService的介绍:
IntentService is a base class for
Service
s that handle asynchronous requests (expressed asIntent
s) on demand. Clients send requests throughContext.startService(Intent)
calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.All requests are handled on a single worker thread -- they may take as long as necessary (and will not block the application's main loop), but only one request will be processed at a time.
IntentService是一个服务的基类,根据Intent的需求来处理异步请求。客户端通过调用 Context.startService(Intent) 发送请求。该服务使用一个工作线程来处理每个 Intent ,并且当它完成工作时会自动停止。所有请求都是在一个工作线程上处理的,它们也许会需要很长时间(不会阻塞应用程序的主线程),但是一次只能处理一个请求。
首先来看看IntentService的常规使用:
新建一个IntentService的子类
public class IntentServiceTest extends IntentService {
//在构造函数中传入线程名字
public IntentServiceTest() {
this("defaultIntentService");
}
@Override
public void onCreate() {
Log.e("sheep","onCreate");
super.onCreate();
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
Log.e("sheep","onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
/**
* 重写onHandleIntent方法
* 这个方法运行在子线程
* 根据不同的intent 执行耗时任务
*
* @param intent
*/
@Override
protected void onHandleIntent(@Nullable Intent intent) {
int flag = intent.getIntExtra("flag", 0);
switch (flag) {
case 0:
//执行传入intent flag为0时的操作
Log.e("sheep", "flag=" + flag);
break;
case 1:
//执行传入intent flag为1时的操作
Log.e("sheep", "flag=" + flag);
break;
//...
default:
break;
}
}
@Override
public void onDestroy() {
Log.e("sheep","onDestory");
super.onDestroy();
}
}
在Activity中开启Service服务
private void init() {
Intent intent=new Intent(this,IntentServiceTest.class);
intent.putExtra("flag",0);
startService(intent);
intent.putExtra("flag",1);
startService(intent);
intent.putExtra("flag",0);
startService(intent);
btn0.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(IntentServiceActivityTest.this,IntentServiceTest.class);
intent.putExtra("flag",0);
startService(intent);
}
});
}
我们在执行了init() 方法后,又点击了一次btn0,运行结果如下
可以看到根据不同的Intent,我们在onHandleIntent() 方法中分别执行了相应操作,同时当任务执行完成后,IntentService就自尽了,所以走到了onDestory() ,再点击一次btn0时,就会重新走oncreate()。是不是觉得特别简单,其实IntentService的使用就分为三步:
-
创建一个
IntentService
的子类,传入线程的名称,同时重写onHandleIntent() 方法,根据传入不同的Intent ,执行相应的异步操作; -
在Manifest.xml中注册此service;
-
在
Activity
中开启此Service
服务。
现在我们来看一看IntentService的源码,探求一下其中原理,其实也挺简单的:
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
//定义IntentService内部的Handler
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
//调用此方法处理异步任务
onHandleIntent((Intent)msg.obj);
//完成任务后自尽
//这里重点解释下,stopSelf()此方法接收的id即是启动服务时,ActivityManager分配的
//id,当结束服务时会比对该id是否和最新启动该服务的id一致,只有当比对一致时才会结束掉
//自己,所以说只有当最后一次startService(intent)启动的服务中onHandleIntent()方
//法执行完毕时才会自尽。
stopSelf(msg.arg1);
}
}
//子类重写构造函数需要传入一个字符串作为工作线程名称
public IntentService(String name) {
super();
mName = name;
}
//如果传入true,则onStartCommand()方法将返回 Service.START_REDELIVER_INTENT,这样当
//服务被kill时,系统会自动重启该服务,并将Intent的值传入。(如果有多个 Intent,只会使用最后
//的一个);如果传入false,则onStartCommand()方法将返回 Service.START_NOT_STICKY,“非粘
//性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启
//该服务。
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public void onCreate() {
super.onCreate();
//服务创建时,会启动一个HandlerThread
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
//创建一个Handler,只有handlerThread中的Looper,则轮循在子线程中
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
//将 intent 和 startId 赋值在消息中,通过handler来发送
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
/**
* You should not override this method for your IntentService. Instead,
* override {@link #onHandleIntent}, which the system calls when the IntentService
* receives a start request.
* @see android.app.Service#onStartCommand
*/
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
//销毁时退出Looper的轮循
mServiceLooper.quit();
}
/**
* Unless you provide binding for your service, you don't need to implement this
* method, because the default implementation returns null.
* @see android.app.Service#onBind
*/
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
}
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}
具体分析在代码中都已经注释了,仔细看看挺简单的,其实IntentService的本质也就是 HandlerThread + Handler:
- 通过HandlerThread 单独开启1个工作线程;
- 使用HandlerThread的Looper创建了一个Handler,此Handler便可以执行异步任务;
- 在onStartCommand() 方法中将 intent 和 startId 赋值在消息中,通过Handler来发送,依次插入到工作队列中逐个发送给onHandleIntent() ;
- 在onHandleIntent() 中依次处理不同Intent 所对应的任务。
至此,IntentService 的使用和源码我们就都分析完了,有一点需要注意的是 onHandleIntent() 中任务的执行是和启动服务的顺序一致的。
再次使用文章开头的总结:IntentService是有着较高优先级的Service,能顺序执行异步任务,同时当完成任务时会自尽。