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是怎么个回事吧。
需要注意的是,一个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的构造函数里。
其实Looper里面的Loop()方法是个死循环,不断的从MQ里取消息,然后分发给对应的handler处理的。
到了这里,大家应该对这个线程的消息传递机制有一定的理解了吧?如果不理解也没关系,进代码零件官方群里讨论吧。
看到这里,感觉线程与Handler已经很完美啦,我要下载一个东西,就先创建一个线程,下载完了就通知UI更新,一个都很美好。其实不然,假如你要下载100张图片,你不可能开100多个线程去下载吧。这样的话系统资源估计撑不住,特别是低端的手机。那怎么办。正确的办法是使用一个线程池,但是自己维护一个线程池十分的麻烦。然后Android早已经帮我们想好这一点了,我们直接使用AsyncTask类即可!其实AsyncTask内部已经维护了一个线程池,有兴趣的同学可以阅读源码。这里就不做更多的讨论了。
最后再来梳理下多线程处理的步骤;
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内部已经维护了一个线程池,有兴趣的同学可以阅读源码。这里就不做更多的讨论了。
最后再来梳理下多线程处理的步骤;
![](http://lesscode.cn/static/attach/20160311/56e233b717ba3.png)
相关文章推荐
- Android中进程(Process)和线程(Thread)
- Android Studio 遇到 “method ID not in [0, 0xffff]: 65536” error
- java环境的搭建及Android SDK环境搭建的路径
- android实现从一个activity跳转到另一个activity中
- Android studio怎样隐藏标题栏
- Android studio 开发快捷键使用(新手)
- Android新手入门2016(12)--基于Layout文件的AlertDialog
- Android官方开发文档Training系列课程中文版:添加ActionBar之添加Action按钮
- android开发--ListView&Adapter
- android view setTag()和findViewWithTag()
- Android自定义view-弹出式dialog
- android Bitmap(将视图转为bitmap对象)
- linearlayout问题
- android 快速入门
- Android代码混淆之混淆规则
- android 开发工具
- 郭霖深入了解View系列 共4篇
- RN组件之ToolbarAndroid
- Android Studio的一些基本设置
- Android RSA 公钥加密、解密