一.HandlerThread的使用与原理解析
HandlerThread继承于Thread,所以它本质就是个Thread。与普通Thread的差别就在于,它不仅建立了一个线程,并且创立了消息队列,有自己的looper,可以让我们在自己的线程中分发和处理消息,并对外提供自己这个Looper对象的get方法。
HandlerThread自带Looper使他可以通过消息队列,来重复使用当前线程,节省系统资源开销。这是它的优点也是缺点,每一个任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理。
1.HandlerThread使用步骤
第一步:创建HandlerThread实例对象
HandlerThread handlerThread = new HandlerThread("myThread");
第二步:启动HandlerThread线程
handlerThread.start();
第三步:构建循环消息处理机制
private Handler.Callback mSubCallback = new Handler.Callback() {
//该接口的实现就是处理异步耗时任务的,因此该方法执行在子线程中
@Override
public boolean handleMessage(Message msg) {
//doSomething 处理异步耗时任务的
mUIHandler.sendMessage(msg1); //向UI线程发送消息,用于更新UI等操作
}
};
第四步:构建子线程中的Handler:
//由于这里已经获取了workHandle.getLooper(),因此这个Handler是在HandlerThread线程也就是子线程中
childHandler = new Handler(handlerThread.getLooper(), mSubCallback);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//发送异步耗时任务到HandlerThread中,也就是上面的mSubCallback中
childHandler.sendMessage(msg);
}
});
第五步:构建UI线程Handler处理消息(如果需要更新UI的话有这一步)
private Handler mUIHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
//在UI线程中做的事情,比如设置图片什么的
}
};
2.HandlerThread的实现原理
HandlerThread的实现原理比较简单,源码也比较少(只有150行代码),首先它是继承自Thread类的:
public class HandlerThread extends Thread {
因此它完全可以当一个线程来使用,就像上面我们说的:new HandlerTread().start()这样,但是!!!——我们之前在Android中的消息机制——Looper、Handler、MessageQueue与Message这篇文章中说过,在子线程中创建一个Handler,需要手动创建Looper,即先Looper.parpare(),完了再Looper.loop()
这样,我们来看看HandlerThread中的run方法:
@Override
public void run() {
mTid = Process.myTid(); //获得当前线程的id
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
//发出通知,当前线程已经创建mLooper对象成功,这里主要是通知getLooper方法中的wait
notifyAll();
}
//设置当前线程的优先级
Process.setThreadPriority(mPriority);
//该方法实现体是空的,子类可以实现该方法,作用就是在线程循环之前做一些准备工作,当然子类也可以不实现。
onLooperPrepared();
Looper.loop();
mTid = -1;
}
可以看到,这个run方法里边写死了,先Looper.prepare()然后Looper.loop(),也即是说,我们的HandlerThread这个特殊的“线程”是再带Looper的,因此——我们不能再主线程使用它,毕竟主线程是自带MainLooper的,一个线程只能有一个Looper,否则就会抛出异常。
这里我们说一下,为什么要看这个run()方法,之前我们在Android中的线程形态(一)(进程/线程/线程池)中有讲过,Thread工作的时候,不论哪种实现方法,我们都必须重写这个类的run()方法,在其中写我们自己要做的事情。可以看到,HandlerThread类的run()方法已经给我们写死了,这就注定我们只能将它用在子线程中。
我们再来看看HandelerThread类的额另一个重要的方法——getLooper():
//该方法主要作用是获得当前HandlerThread线程中的mLooper对象
public Looper getLooper() {
if (!isAlive()) { //如果线程不是活动的,则直接返回null
return null;
}
// If the thread has been started, wait until the looper has been created.
//如果线程已经启动,但是Looper还未创建的话,就等待,直到Looper创建成功
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
//这里会调用wait方法去等待,当run方法中的notifyAll方法调用之后
//通知当前线程的wait方法等待结束,跳出循环,获得mLooper对象的值。
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
OK,看到这里,结合上面的HandelrThread使用步骤,我们需要总结一下:
- HandelrThread是一个自带Looper的线程,因此只能作为子线程使用
- HandlerThread必须配合Handler使用,HandlerThread线程中做具体事情,必须要在Handler的callback接口中进行,他自己的run方法被写死了。
- 子线程中的Handler与HandlerThread的联系是通过
childHandler = new Handler(handlerThread.getLooper(), mSubCallback);
这句来进行的,也就是你说,childHandler获得HandlerThread线程的Looper,这样,他们两个就在同一阵营了。这也就是在创建Handler作为HandlerThread线程消息执行者,必须在调用start()方法之后的原因——HandlerThread.start()之后,run()方法才能跑起来,Looper才能得以创建,handlerThread.getLooper()
才不会出错。
二.IntentService的使用与实现原理
HandlerThread在Android中的一个具体的应用就是IntentService。IntentService是继承于Service并处理异步请求的一个类。注意这句话——“继承于Service”和“处理异步请求”。“继承于Service”表示他是一个服务,我们知道Service是存在于主线程的,它之中不能存在耗时操作,否则的话回应起ANR,因此便有了IntentService——这个封装了HandlerThread和Handler的特殊Service。
1.IntentService的使用
第一步:创建一个继承IntentService类的子类
首先,通过源码我们知道,IntentService是一个继承自Service类的抽象类,因此我们必须创建一个继承它的子类才能实现相关功能:
public class MyIntentService extends IntentService {
public ServiceUpdate() {
// 注意构造函数参数为空,这个myIntentService字符串就是IntentService中工作线程的名字
super("myIntentService");
}
//打印生命周期
@Override
public void onCreate() {
Log.i("myIntentService", "onCreate");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("myIntentService", "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onStart(Intent intent, int startId) {
Log.i("myIntentService", "onStart");
super.onStart(intent, startId);
}
@Override
public IBinder onBind(Intent intent) {
Log.i("myIntentService", "onBind");
return super.onBind(intent);
}
//重写onHandleIntent方法,在该方法中进行我们的各种事务处理
@Override
protected void onHandleIntent(Intent intent) {
//一般Intent是从Activity发过来的,携带识别参数,根据参数不同执行不同的任务
String taskName = intent.getExtras().getString("taskName");
switch (taskName) {
case "task1":
Log.i("myIntentService", "task1");
break;
case "task2":
Log.i("myIntentService", "task2");
break;
default:
break;
}
}
@Override
public void onDestroy() {
Log.i("myIntentService", "onDestroy");
super.onDestroy();
}
}
第二步:在Activity中开启服务:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
......
//同一服务只会开启一个工作线程,在onHandleIntent函数里依次处理intent请求。
Intent intent1 = new Intent(this,MyIntentService.class);
Bundle bundle = new Bundle();
bundle.putString("taskName", "task1");
intent1.putExtras(bundle);
startService(intent1);
Intent intent2 = new Intent(this,MyIntentService.class);
Bundle bundle2 = new Bundle();
bundle2.putString("taskName", "task2");
intent2.putExtras(bundle2);
startService(intent2);
}
}
第三步:在 Manifest 中注册服务
<service android:name=".service.MyIntentService"/>
上述过程中我们启动了两个IntentService服务,打印出来生命周期为:onCreate -> onStartCommand -> onStart -> onStartCommand -> onStart -> task1 -> task2 -> onDestroy,OnBinder没有执行。
从结果可以看到,onCreate 方法只执行了一次,而 onStartCommand 和 onStart 方法执行了两次,开启了两个 工作线程(Work Thread),这就证实了之前所说的,启动多次,但IntentService 的实例只有一个,这跟传统的Service 是一样的。
2.IntentServic源码分析
IntentService继承Service类之后,整体的源码也就165行,跟HandlerThread差不多,我们先来看看它的实例变量:
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper; //服务所在线程的Looper
private volatile ServiceHandler mServiceHandler; //构建一个服务中的Handler
private String mName; //服务所在线程的名字
private boolean mRedelivery;
1).IntentService的构造方法
上面加了注释的三个变量较为重要,我们待会会一步步分析。接下来我们看看他的构造方法:
public IntentService(String name) {
super();
mName = name;
}
可以看到,上线例子中我们得
public ServiceUpdate() {
super("myIntentService");
}
其中“myIntentService”实际会上传到父类IntentService的构造方法中,也就是IntentService所在线程的线程名字,IntentService构造方法中的super();
又会进一步调用Service类中的构造函数:
public Service() {
super(null);
}
再网上,就到ContextWrapper类里边去了。如果我们看过Activity的源码的话就会知道,Activity也是继承自ContextWrapper类的,而ContextWrapper类继承自Context!也就说,Service和Activity实际上都是一个Context!ContextWrapper有一个比较特殊的地方是,他的实例化的地方是在ActivityThread中由系统完成的,我们无权插手。因此,在StartService或者StartActivity的时候,系统就会自动帮我们实例化这两个组件。这样,Service的构造方法为空也就很好解释了。
2).OnCreat()
看上面的生命周期流程图我们知道,IntentService第一步指定的onCreat方法:
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
首先,super.onCreate();
,这个我们看到Service的onCreat()方法是空的,所以不管,接着看。HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
看到了吧,这里重量级人物——HandlerThread出场了,新建了一个HandlerThread实例,上面我们说过HandlerThread()的构造方法传进去的是HandlerThread所在线程的名字,然后thread.start();
,嗯,非常符合我们上半片文章讲的HandlerThread使用流程。
mServiceLooper = thread.getLooper();
这里通过mServiceLooper获取到HandlerThread线程的Looper。然后mServiceHandler = new ServiceHandler(mServiceLooper);
,我们接着看源码:
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
可以看到,ServiceHandler是IntentService类的一个内部类,并且继承自Handler,重写了handleMessage方法。很显然,这个类是用来处理startService(intent);
传递来的消息的。这个消息处理的过程分为两步,第一调用onHandleIntent((Intent)msg.obj);
方法;第二步stopSelf(msg.arg1);
消息处理完后自动终止服务。所以我们接着而看onHandleIntent((Intent)msg.obj);
:
@WorkerThread
protected abstract void onHandleIntent(Intent intent);
呦呵?这是一个抽象方法,抽象类中的抽象方法意味着我们需要在子类中重写这个方法,也就是说,这个方法才是我们处理消息的地方。可以看到,这个方法上面加了注解,是位于工作线程(子线程)中的。
3).onStartCommand()/onStart()
好了,OnCreat()方法终于执行完了,onStartCommand()方法,它和onStart()方法实际上是连在一起的:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
直接看onStart():
@Override
public void onStart(Intent intent, int startId) {
//Service 启动后直接就向 mServiceHandler 发送消息,则马上就会执行 handleMessage方法
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
这个方法中,mServiceHandler这个Handler的子类,调用了obtainMessage()方法,该方法实际上上到Handler类中调用的是:
public final Message obtainMessage(){
return Message.obtain(this);
}
这个方法中,Message.obtain(this);
这个方法我们复习一下,实际上就是Handler从消息池中取出一个消息,避免Message类重复创建的一个方法。回到IntentSerice的onStart()方法中,Message msg = mServiceHandler.obtainMessage();
,这句就是获取一个Message对象,然后mServiceHandler.sendMessage(msg);
通过Handler发送消息,添加到Looper中的MessageQuenue队列中。
4).onDestroy()
@Override
public void onDestroy() {
mServiceLooper.quit();
}
安全退出Looper()
3.IntentService中的一些坑
1).为什么不建议通过 bindService() 启动 IntentService?
@Override
public IBinder onBind(Intent intent) {
return null;
}
IntentService 源码中的 onBind() 默认返回 null;不适合 bindService() 启动服务,如果你执意要 bindService() 来启动 IntentService,可能因为你想通过 Binder 或 Messenger 使得 IntentService 和 Activity 可以通信,这样那么 onHandleIntent() 不会被回调,相当于在你使用 Service 而不是 IntentService。
2).为什么多次启动 IntentService 会顺序执行事件,停止服务后,后续的事件得不到执行?
IntentService 中使用的 Handler、Looper、MessageQueue 机制把消息发送到线程中去执行的,所以多次启动 IntentService 不会重新创建新的服务和新的线程,只是把消息加入消息队列中等待执行,而如果服务停止,会清除消息队列中的消息,后续的事件得不到执行。
站在巨人的肩膀上摘苹果:
IntentService 示例与详解
Service 和 IntentService 的区别等