您的位置:首页 > 运维架构

安卓异步线程消息机制学习——Handler+Thread+Looper

2015-10-22 15:26 155 查看
前言:在安卓应用开发中面临着一个问题,如果应用在主线程(即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线程体。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: