您的位置:首页 > 移动开发 > Android开发

android线程消息传递机制——Looper,Handler,Message

2016-03-22 19:27 495 查看
线程间的通信是需要几个类一起配合使用才行,这几个类分别是:

Looper,Handler,Message。其实还有一个Message Queue(MQ)的,只不过封装在Looper里面了,我们不会直接跟MQ打交道。

Looper——负责循环从MQ中取出Message,然后消息扔给Hanlder的handleMessage方法,。

Handler——负责处理Looper分发过来的Message和发送消息给Looper。在实例化时要重写hanldeMessage方法,处理对应的消息。

Message——一个消息包而已,里面有一个target字段,表明这个Message是发给线程的哪个Handler的。

Message Queue——消息包组成的消息队列。

下面说一下他们是如何配合运作的。当你的A线程需要接受从别的B线程发过来的消息时,就需要在A线程中创建一个Handler,B线程就可以往你创建的Handler发消息。然后A线程就可以收到消息了。但是需要注意的是,在创建Hanlder的时候,需要绑定一个Looper。如果在创建Handler时不指定与其绑定的Looper对象,系统默认会将当前线程的Looper绑定到该Handler上。如果你的当前线程没有创建Looper,系统就会报错。那有同学就说了,我平时在UI线程里用Handler时没有创建Looper也没有报错啊!那是因为系统默认已经帮UI线程创建Looper了。如果你创建的子线程也想拥有一个handler,那也需要帮你的子线程先创建一个Looper才行哦。下面用一段代码看看线程、Looper、handler、Message是怎么个回事吧。

<span style="font-size:18px;">class MyThread extends Thread
{
public Handler mHandler;
public void run()
{
Looper.prepare();
mHandler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
//在这里处理消息
}
}
Looper.loop();
}
} </span>


需要注意的是,一个Thread只能有一个Looper对象。如果你硬是要为一个Thread创建两个Looper,那。。。那。。。那其实你办不到!因为Looper对象定义为ThreadLocal(如果你不理解ThreadLocal,可以上网查)。保证一个Thread最多只能有一个Looper。其实Looper是不能用new去实例化的,因为Looper的构造函数是private的,调用Loop.prepare()就创建Looper了,无论你调用多少次Looper.prepare,都是一个Looper对象,有点像单例模式。而每个Thread可以拥有多个Handler。创建Hanlder时,如果没指定Looper,那么在Handler的构造函数里会关联当前线程的Looper。那他们是怎么关联的?上面代码没有见他们有关联的行为啊。其实玄机就在Handler的构造函数里。

<span style="font-size:18px;">public class handler {

final MessageQueue mQueue;  // 关联的MQ
final Looper mLooper;  // 关联的looper
final Callback mCallback;
// 其他属性

public Handler() {
// 这里有一堆代码直接略过,,,

// 用mLooper获取当前线程的looper
mLooper = Looper.myLooper();
// looper不能为空,如果为空,就是该线程没有Looper,直接报错!即该默认的构造方法只能在looper线程中使用
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
// 重要!!!直接把关联looper的MQ作为自己的MQ,因此它的消息将发送到关联looper的MQ上
mQueue = mLooper.mQueue;
mCallback = null;
}

// 其他方法
}</span>


其实Looper里面的Loop()方法是个死循环,不断的从MQ里取消息,然后分发给对应的handler处理的。

到了这里,大家应该对这个线程的消息传递机制有一定的理解了吧?如果不理解也没关系,进代码零件官方群里讨论吧。

看到这里,感觉线程与Handler已经很完美啦,我要下载一个东西,就先创建一个线程,下载完了就通知UI更新,一个都很美好。其实不然,假如你要下载100张图片,你不可能开100多个线程去下载吧。这样的话系统资源估计撑不住,特别是低端的手机。那怎么办。正确的办法是使用一个线程池,但是自己维护一个线程池十分的麻烦。然后Android早已经帮我们想好这一点了,我们直接使用AsyncTask类即可!其实AsyncTask内部已经维护了一个线程池,有兴趣的同学可以阅读源码。这里就不做更多的讨论了。

最后再来梳理下多线程处理的步骤;

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: