这篇博客将结合Android7.0源码,解析HandlerThread的使用场景及实现原理。
1.为什么要有handlerThread组件出现?
在Android中我们使用消息机制进行线程间的消息传递,如果是向主线程传递消息,我们构造主线程的handler,并使用他发送消息。使用起来还是很方便的。但是如果是要子线程传递消息,就需要构建子线程的handler. 这样使用起来就比较麻烦了!比如下面这样:
public class Main2Activity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//处理子线程的消息
}
};
Looper.loop();
}
}).start();
}
}
我们得在子线程中构建Looper,并调用Looper的loop方法才能正确的构建出子线程的handler对象。这样用也没什么,但代码看着实在是很不舒服呀。 所以android给我们提供了HandlerThread组件,封装了子线程中构建looper的繁琐操作。
2.HandlerThread的使用场景
在介绍HandlerThread之前,我们先想一个它的使用场景,通过使用场景,结合使用示例。我们才能在分析它的源码的时候有一个好的切入点,而且还可以加深我们对于handlerThread的一些印象; 可以想象一下这样的一个场景,例如我之前研发了一款股票交易软件,因为股票的行情数据都是实时变化的。所以我们软件需要每隔一定时间向服务器请求行情数据。
代码示例如下:
public class MainActivity extends AppCompatActivity {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
TextView updateTimeTv;
Handler mUIHandler=new Handler(){
@Override
public void handleMessage(Message msg) {
//更新ui
updateTimeTv.setText((String)msg.obj);
//1秒后再次请求服务器,并更新数据
timeMessagehandler.sendEmptyMessageAtTime(0,1000);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
updateTimeTv = (TextView)findViewById(R.id.tv);
initThreadHandler();
}
HandlerThread handlerThread;
Handler timeMessagehandler;
private void initThreadHandler() {
//构建HandlerThread
handlerThread=new HandlerThread("updateTimeThread");
//启动handler
handlerThread.start();
//构建子线程的handler对象
timeMessagehandler=new Handler(handlerThread.getLooper()){
@Override
public void handleMessage(Message msg) {
//请求服务端时间
try {
//模拟耗时请求
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//网络请求成功,通过主线程更新ui
Message message=Message.obtain();
message.obj= df.format(new Date());
mUIHandler.sendMessage(message);
System.out.println("handlerTimeMessage"+Thread.currentThread().getName());
}
};
//向子线程发送消息,通知它发送网络请求
timeMessagehandler.sendEmptyMessage(0);
}
}
我们分析一下上面的代码实现,一步一步来解析HandlerThread的使用,略过mUIHandler和view的初始化代码不表。我们可以看到上面的代码先构建了一个HandlerThread对象,然后调用了它的start方法。 这里我们可以提前剧透一下。HandlerThread对象对象其实继承了Thread对象。所以调用它的start方法就会执行它的run方法。 然后我们用handlerThread.getLooper()方法构建一个timeMessagehandler对象。 从上面的代码看timeMessagehandler对象的handleMessage中可以执行耗时操作,也就说明该方法是执行在子线程中的。那handlerThread.getLooper()方法所获取的方法也就肯定是子线程的Looper对象了。 这部分不清楚的可以看我另一篇文章,android消息机制源码分析http://blog.youkuaiyun.com/nightcurtis/article/details/77539971。 所以我们就可以timeMessagehandler对象向子线程发送消息执行耗时任务, 然后通过主线程的mUIHandler对象发消息处理ui的显示。 这些代码就太简单这里就不说了。 结合这段使用代码实例,我们可以知道我们下面这短短的3行代码就能够完成之前构建线程,初始化looper等等操作才能完成的构造子线程handler的这样一个需求。这是怎么做到的呢!
handlerThread=new HandlerThread("updateTimeThread");
//启动handler
handlerThread.start();
//构建子线程的handler对象
timeMessagehandler=new Handler(handlerThread.getLooper());
3.HandlerThread的源码解析
通过HandlerThread的使用场景解析我们知道通过短短3行代码就可以完成之前初始化looper,构建handler对象,并调用loop才能正确创建的子线程handler对象。 这里面的秘密是什么呢? 结合HandlerThread的源码。我们来解析一下:
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
......
}
其实HandlerThread的源码很简单。HandlerThread继承了Thread对象,所以我们构造HandlerThread对象的时候就是构建了一个子线程对象。 调用线程对象的start方法,就会执行HandlerThread的run函数。 我们看到在run方法中有 Looper.prepare(),Looper.loop()两个方法。其实和我们在子线程中构建looper的方法完全相同。 真正值得注意的是,发现在run方法中和looper的getLooper中有一个线程通信的处理。 这个是为什么呢? 想想之前我们是主线程中先构建handlerThread对象,然后调用它的start方法,去初始化looper对象。 然后就调用handlerThread的getLooper()方法去初始化一个子线程的Handler对象。 我们知道 handlerThread的start方法是执行在子线程中的,而handlerThread的getLooper()方法是执行在主线程中的。我们不能确认他们谁先执行,如果是getLooper()方法先执行,而这个时候子线程的looper还没有创建。构建handler就会抛出异常。 所以我们需要确保getLooper()方法在Looper创建成功后执行。所以在这里添加了线程通信的处理。
4.总结
其实分析源码后我们能够发现HandlerThread的源码特别简单,但我们解析它的源码不止是为了分析它的源码。更重要的是要学习它的一下封装的思想。 还有就是了解它的原理后,以后遇到使用了HandlerThread的组件心里上会有征服感。哈哈。 比如了解了HandlerThread的原理后再去看IntentService的原理。 真是不能再简单了。 有么有!!