前言:在安卓应用开发中面临着一个问题,如果应用在主线程(即UI线程)中进行网络通信的时候很有可能会造成主线程长时间阻塞,而阻塞超过5秒钟程序就会崩溃!自然可以考虑新建一个工作线程(Thread)来完成网络通信,那么问题又来了,譬如在完成了网络通信后往往需要更新UI,我们的网络通信是在子线程中完成的,而安卓的UI交互是在主线程中实现的!显然,我们无法在网络通信的子线程中更新UI。如果说子线程可以在自己完成任务后发一个相应的消息给主线程,那么主线程就可以根据消息的内容去完成UI更新,那么Handler对象就扮演着在子线程和主线程之间发送、传递、处理消息的角色。聪明的你一定意识到了,如果主线程收到的消息比较多,它一定忙不过来,那么主线程肯定要有一个消息队列,Looper对象就是负责管理这个消息队列。(说明一点,本文并不会过多涉及代码的实现)
android异步线程消息机制示意图
一、Thread
实现一个子线程,主要两种方式:1、继承Thread对象,重写run()方法;2、实现Runnable接口的run()方法生成线程体,用这个线程体实例化一个Thread对象。
注:需要注意的是Thread类实际上也是实现了Runnable接口,如果直接调用run()方法,代码实际上还是在主线程中跑。必须调用Thread对象的start()方法才会创建一个新线程,我的理解是实例化一个Thread对象只是分配给这个独立线程需要的资源,调用start()方法使得这个线程处于就绪状态!
一、Message、MessageQuenen和Looper
1、Message对象,主要使用到Message.what和Message.obj两个属性,前者是消息的唯一标识,后者是传递的消息内容。(提一下,线程之间消息的传递可以通过Handler对象实现,进程之间消息的传递是Messger对象实现,这个后面再继续学习一下)。
2、MessageQuenen、Looper、Thread的联系
如图所示,一个线程只有一个Looper对象管理着一个消息队列,需要注意的是只有和Looper对象绑定的线程才有消息队列,我们把这样的线程称作Looper线程。主线程自然是Looper线程,但是我们实现的子线程并不是!当然通过代码可以实现子线程和Looper对象的绑定,并为它分配一个消息队列,了解一下Looper的源码实现能更好的帮助我们理解MessageQuenen、Looper、Thread之间对应的关系。
我们就不过多去纠结代码细节问题了,重点在于调用Looper对象的prePare()方法后Looper对象会创建一个消息队列并且和当前的线程绑定。同时Looper对象的loop方法负责不断的从消息队列中取消息,交给Handler对象处理。
注:在主线程中,Looper的实现对我们来说是‘透明’的!不用去考虑代码实现Looper、消息队列、线程之间的关联,只要在主线程中实例化Handler对象,重写handleMessage()方法处理消息,子线程里面引用主线程实例化的Handler对象发送消息。
一、消息机制的实现
1、子线程向主线程发送消息
主线程接受并处理消息,自然是在主线程实例化Handler对象,这样主线程的Looper对象才能从主线程的消息队列中提取消息给Handler对象处理,而子线程中引用主线程实例化的Handler对象发送消息。
参考代码:
主线程中(实例化Handler对象):
class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
//根据msg.waht识别不同消息,处理msg.obj数据
}
}
子线程中(线程体中引用Handler对象发送消息):
public void run() {
try {
// 执行相应业务,例如网络通信
...........
// 任务完成后创建通知UI线程的消息
Message msg = handler.obtainMessage();
msg.waht=XXX;
msg.obg=XXX;
// 发送消息
handler.sendMessage(msg);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
2、主线程向子线程发送消息
主线程向子线程发送消息的实现逻辑和上述是类似的(反一下而已),不同的地方在于:主线程默认就是Looper线程,不需要再去代码实现线程、Looper、消息队列的关联!而子线程则必须要有这一步
代码参考:
子线程:
public class LooperThread extends Thread {
@Override
public void run() {
// 将当前线程初始化为Looper线程
Looper.prepare();
//子线程需要处理的任务
// 实例化handler
// 开始循环处理消息队列
Looper.loop();
}
}
注:Handler对象除了可以发送Message对象到消息队列外,也可以通过post()方法和postDelay()方法发送Runnable线程体对象到消息队列中。通过源码的解读可以发现其实质还是发送了一个Message对象,该Message对象具有callback属性,其callback属性值即是发送的Runnable线程体。
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。