Android异步处理三:Handler+Looper+MessageQueue深入详解

33862人阅读 评论(29) 收藏 举报 android null thread layout ui string

本博文地址:http://blog.csdn.net/mylzc/article/details/6771331转载请注明出处

Android异步处理系列文章索引

Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面

Android异步处理二:使用AsyncTask异步更新UI界面

Android异步处理三:Handler+Looper+MessageQueue深入详解

Android异步处理四:AsyncTask的实现原理


在《Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面》中,我们讲到使用Thread+Handler的方式来实现界面的更新,其实是在非UI线程发送消息到UI线程,通知UI线程进行界面更新,这一篇我们将深入学习Android线程间通讯的实现原理。

概述:Android使用消息机制实现线程间的通信,线程通过Looper建立自己的消息循环,MessageQueue是FIFO的消息队列,Looper负责从MessageQueue中取出消息,并且分发到消息指定目标Handler对象。Handler对象绑定到线程的局部变量Looper,封装了发送消息和处理消息的接口。

例子:在介绍原理之前,我们先介绍Android线程通讯的一个例子,这个例子实现点击按钮之后从主线程发送消息"hello"到另外一个名为” CustomThread”的线程。

代码下载

LooperThreadActivity.java

[java] view plain copy
  1. packagecom.zhuozhuo;
  2. importandroid.app.Activity;
  3. importandroid.os.Bundle;
  4. importandroid.os.Handler;
  5. importandroid.os.Looper;
  6. importandroid.os.Message;
  7. importandroid.util.Log;
  8. importandroid.view.View;
  9. importandroid.view.View.OnClickListener;
  10. publicclassLooperThreadActivityextendsActivity{
  11. /**Calledwhentheactivityisfirstcreated.*/
  12. privatefinalintMSG_HELLO=0;
  13. privateHandlermHandler;
  14. @Override
  15. publicvoidonCreate(BundlesavedInstanceState){
  16. super.onCreate(savedInstanceState);
  17. setContentView(R.layout.main);
  18. newCustomThread().start();//新建并启动CustomThread实例
  19. findViewById(R.id.send_btn).setOnClickListener(newOnClickListener(){
  20. @Override
  21. publicvoidonClick(Viewv){//点击界面时发送消息
  22. Stringstr="hello";
  23. Log.d("Test","MainThreadisreadytosendmsg:"+str);
  24. mHandler.obtainMessage(MSG_HELLO,str).sendToTarget();//发送消息到CustomThread实例
  25. }
  26. });
  27. }
  28. classCustomThreadextendsThread{
  29. @Override
  30. publicvoidrun(){
  31. //建立消息循环的步骤
  32. Looper.prepare();//1、初始化Looper
  33. mHandler=newHandler(){//2、绑定handler到CustomThread实例的Looper对象
  34. publicvoidhandleMessage(Messagemsg){//3、定义处理消息的方法
  35. switch(msg.what){
  36. caseMSG_HELLO:
  37. Log.d("Test","CustomThreadreceivemsg:"+(String)msg.obj);
  38. }
  39. }
  40. };
  41. Looper.loop();//4、启动消息循环
  42. }
  43. }
  44. }
main.xml

[html] view plain copy
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="vertical"
  4. android:layout_width="fill_parent"
  5. android:layout_height="fill_parent"
  6. >
  7. <TextView
  8. android:layout_width="fill_parent"
  9. android:layout_height="wrap_content"
  10. android:text="@string/hello"
  11. />
  12. <Buttonandroid:text="发送消息"android:id="@+id/send_btn"android:layout_width="wrap_content"android:layout_height="wrap_content"></Button>
  13. </LinearLayout>

Log打印结果:

原理:

我们看到,为一个线程建立消息循环有四个步骤:

1、 初始化Looper

2、 绑定handler到CustomThread实例的Looper对象

3、 定义处理消息的方法

4、 启动消息循环

下面我们以这个例子为线索,深入Android源代码,说明Android Framework是如何建立消息循环,并对消息进行分发的。

1、 初始化Looper : Looper.prepare()

Looper.java

[java] view plain copy
  1. privatestaticfinalThreadLocalsThreadLocal=newThreadLocal();
  2. publicstaticfinalvoidprepare(){
  3. if(sThreadLocal.get()!=null){
  4. thrownewRuntimeException("OnlyoneLoopermaybecreatedperthread");
  5. }
  6. sThreadLocal.set(newLooper());
  7. }

一个线程在调用Looper的静态方法prepare()时,这个线程会新建一个Looper对象,并放入到线程的局部变量中,而这个变量是不和其他线程共享的(关于ThreadLocal的介绍)。下面我们看看Looper()这个构造函数:

Looper.java

[java] view plain copy
  1. finalMessageQueuemQueue;
  2. privateLooper(){
  3. mQueue=newMessageQueue();
  4. mRun=true;
  5. mThread=Thread.currentThread();
  6. }

可以看到在Looper的构造函数中,创建了一个消息队列对象mQueue,此时,调用Looper. prepare()的线程就建立起一个消息循环的对象(此时还没开始进行消息循环)。

2、 绑定handler到CustomThread实例的Looper对象 : mHandler= new Handler()

Handler.java

[java] view plain copy
  1. finalMessageQueuemQueue;
  2. finalLoopermLooper;
  3. publicHandler(){
  4. if(FIND_POTENTIAL_LEAKS){
  5. finalClass<?extendsHandler>klass=getClass();
  6. if((klass.isAnonymousClass()||klass.isMemberClass()||klass.isLocalClass())&&
  7. (klass.getModifiers()&Modifier.STATIC)==0){
  8. Log.w(TAG,"ThefollowingHandlerclassshouldbestaticorleaksmightoccur:"+
  9. klass.getCanonicalName());
  10. }
  11. }
  12. mLooper=Looper.myLooper();
  13. if(mLooper==null){
  14. thrownewRuntimeException(
  15. "Can'tcreatehandlerinsidethreadthathasnotcalledLooper.prepare()");
  16. }
  17. mQueue=mLooper.mQueue;
  18. mCallback=null;
  19. }

Handler通过mLooper = Looper.myLooper();绑定到线程的局部变量Looper上去,同时Handler通过mQueue =mLooper.mQueue;获得线程的消息队列。此时,Handler就绑定到创建此Handler对象的线程的消息队列上了。

3、定义处理消息的方法:Override public void handleMessage (Message msg){}

子类需要覆盖这个方法,实现接受到消息后的处理方法。

4、启动消息循环 : Looper.loop()

所有准备工作都准备好了,是时候启动消息循环了!Looper的静态方法loop()实现了消息循环。

Looper.java

[java] view plain copy
  1. publicstaticfinalvoidloop(){
  2. Looperme=myLooper();
  3. MessageQueuequeue=me.mQueue;
  4. //Makesuretheidentityofthisthreadisthatofthelocalprocess,
  5. //andkeeptrackofwhatthatidentitytokenactuallyis.
  6. Binder.clearCallingIdentity();
  7. finallongident=Binder.clearCallingIdentity();
  8. while(true){
  9. Messagemsg=queue.next();//mightblock
  10. //if(!me.mRun){
  11. //break;
  12. //}
  13. if(msg!=null){
  14. if(msg.target==null){
  15. //Notargetisamagicidentifierforthequitmessage.
  16. return;
  17. }
  18. if(me.mLogging!=null)me.mLogging.println(
  19. ">>>>>Dispatchingto"+msg.target+""
  20. +msg.callback+":"+msg.what
  21. );
  22. msg.target.dispatchMessage(msg);
  23. if(me.mLogging!=null)me.mLogging.println(
  24. "<<<<<Finishedto"+msg.target+""
  25. +msg.callback);
  26. //Makesurethatduringthecourseofdispatchingthe
  27. //identityofthethreadwasn'tcorrupted.
  28. finallongnewIdent=Binder.clearCallingIdentity();
  29. if(ident!=newIdent){
  30. Log.wtf("Looper","Threadidentitychangedfrom0x"
  31. +Long.toHexString(ident)+"to0x"
  32. +Long.toHexString(newIdent)+"whiledispatchingto"
  33. +msg.target.getClass().getName()+""
  34. +msg.callback+"what="+msg.what);
  35. }
  36. msg.recycle();
  37. }
  38. }
  39. }

while(true)体现了消息循环中的“循环“,Looper会在循环体中调用queue.next()获取消息队列中需要处理的下一条消息。当msg != null且msg.target != null时,调用msg.target.dispatchMessage(msg);分发消息,当分发完成后,调用msg.recycle();回收消息。

msg.target是一个handler对象,表示需要处理这个消息的handler对象。Handler的void dispatchMessage(Message msg)方法如下:

Handler.java

[java] view plain copy
  1. publicvoiddispatchMessage(Messagemsg){
  2. if(msg.callback!=null){
  3. handleCallback(msg);
  4. }else{
  5. if(mCallback!=null){
  6. if(mCallback.handleMessage(msg)){
  7. return;
  8. }
  9. }
  10. handleMessage(msg);
  11. }
  12. }

可见,当msg.callback== null 并且mCallback == null时,这个例子是由handleMessage(msg);处理消息,上面我们说到子类覆盖这个方法可以实现消息的具体处理过程。


总结:从上面的分析过程可知,消息循环的核心是Looper,Looper持有消息队列MessageQueue对象,一个线程可以把Looper设为该线程的局部变量,这就相当于这个线程建立了一个对应的消息队列。Handler的作用就是封装发送消息和处理消息的过程,让其他线程只需要操作Handler就可以发消息给创建Handler的线程。由此可以知道,在上一篇《Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面》中,UI线程在创建的时候就建立了消息循环(在ActivityThread的public static final void main(String[] args)方法中实现),因此我们可以在其他线程给UI线程的handler发送消息,达到更新UI的目的。

本博文地址:http://blog.csdn.net/mylzc/article/details/6771331转载请注明出处


笔记:

1,Looper会创建消息队列,并在while中不停得读取下一个消息

2,处理消息会调用handler的handleMessage()函数

3,消息队列是在底层处理的,在4.x版本中是以管道的方式实现的,以epoll的方法监听事件;


更多相关文章

  1. Android(安卓)学习笔记--android――Activity学习
  2. android之实现各个组件点击事件处理
  3. android技术开发例子,解析以及源码集锦
  4. Android之gif动画实现
  5. Android(安卓)源码编译make的错误处理
  6. 横竖屏切换时不销毁当前activity 和 锁定屏幕
  7. android技术开发例子,解析以及源码集锦
  8. Android使用XPush配置极光推送
  9. Android之Handler用法总结

随机推荐

  1. android ListView 多次调用 getView方法
  2. Could not find com.android.tools.build
  3. android studio mark
  4. Android(安卓)工程混淆后无法找到自定义
  5. Android(安卓)文件管理器 Android文件管
  6. Android(安卓)Timer 更好方法
  7. Android(安卓)listView
  8. android模拟器上网
  9. Android(安卓)下压缩图片—微弱失真
  10. CreateProcess error = 2,系统找不到指定