博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Handler 原理分析和使用(一)
阅读量:6585 次
发布时间:2019-06-24

本文共 6510 字,大约阅读时间需要 21 分钟。

我为什么写Handler,原因主要还在于它在整个 Android 应用层面非常之关键,他是线程间相互通信的主要手段。最为常用的是其他线程通过Handler向主线程发送消息,更新主线程UI。

下面是一个最简单的例子。

1 import android.os.Handler; 2 import android.os.Looper; 3 import android.os.Message; 4 import android.os.MessageQueue; 5 import android.support.v7.app.AppCompatActivity; 6 import android.os.Bundle; 7 import android.widget.TextView; 8  9 public class MainActivity extends AppCompatActivity {10 11     private TextView myTextView;12     private Handler myHandler = new Handler(){13         @Override14         public void handleMessage(Message msg) {15             //UI线程接收到消息16 17             int arg1 = msg.arg1;18             switch (arg1){19                 case 0:20                     if(msg.arg2 == 0){21                         //更新UI22                         myTextView.setText((String)msg.obj);23                     }24                     break;25                 default:26                     break;27             }28             super.handleMessage(msg);29 30         }31     };32     @Override33     protected void onCreate(Bundle savedInstanceState) {34         super.onCreate(savedInstanceState);35         setContentView(R.layout.activity_main);36         myTextView = (TextView)this.findViewById(R.id.text_view);37         //起独立线程38         new Thread(){39             public void run(){40                 String text = "from handler";41                 Message message = new Message();42                 message.arg1 = 0;43                 message.arg2 = 0;44                 message.obj = text;45                 //通过Handler给UI发消息46 47 48                 myHandler.sendMessage(message);49             }50         }.start();51     }52 }

 

上面的例子看似好简单了。但是支持这样消息从一个线程传到另一个线程,不仅仅需要Handler这样一个类的支持,还需要其他类的支持,分别是 Looper, Message, MessageQueue。

 

消息的流转的架构:

 

  • Handler 负责发送消息和处理消息
  • Message 是消息的实体。
  • MessageQueue 消息队列。
  • Looper 负责消息队列的循环,包括两件事:第一创建和控制 MessageQueue;第二轮询MessageQueue读取Message信息派发给Handler

 

消息的流转的过程:

 

首先,在Android里面每一个线程都有自己的一个Looper。而每个Looper都有一个MessageQueue。

       Looper对象不需要开发人员去初始化,在每个线程里面他是存在的。源码中初始化如下:    

1 private Looper(boolean quitAllowed) {  2         mQueue = new MessageQueue(quitAllowed);  3         mRun = true;  4         mThread = Thread.currentThread();  5 }

       可见消息队列也是在此创建的。但是每个线程需要绑定自己的Looper,调用的方法是Looper.prepare(),源码实现如下

1 public static final void prepare() {  2         //此处说明prepare只能执行一次,再一次会抛异常3         if (sThreadLocal.get() != null) {  4             throw new RuntimeException("Only one Looper may be created per thread");  5         } 6         //绑定Looper7         sThreadLocal.set(new Looper(true));  8 }

 

其次,Handler对象可以跨线程,它在次线程中将Message推入MessageQueue中。

  在Handler初始化时,就已经和自己所在的线程的MessageQueue绑定,源码如下

1 public Handler() {   2         this(null, false);   3 }   4 public Handler(Callback callback, boolean async) {   5         .............. 6         //获取Looper对象 7         mLooper = Looper.myLooper();   8         if (mLooper == null) {   9             throw new RuntimeException(  10                 "Can't create handler inside thread that has not called Looper.prepare()");  11         }  12         //绑定MessageQueue对象13         mQueue = mLooper.mQueue;  14         mCallback = callback;  15         mAsynchronous = async;  16 }

  绑定之后就可以向MessageQueue里面推入Message,源码如下:

1 public final boolean sendMessage(Message msg)  {   2      return sendMessageDelayed(msg, 0);   3  }  4 public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {   5      Message msg = Message.obtain();   6      msg.what = what;   7      return sendMessageDelayed(msg, delayMillis);   8  }   9 public final boolean sendMessageDelayed(Message msg, long delayMillis)  {  10        if (delayMillis < 0) {  11            delayMillis = 0;  12        }  13        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);  14  }15 public boolean sendMessageAtTime(Message msg, long uptimeMillis) {  16        MessageQueue queue = mQueue;  17        if (queue == null) {  18            RuntimeException e = new RuntimeException(  19                    this + " sendMessageAtTime() called with no mQueue");  20            Log.w("Looper", e.getMessage(), e);  21            return false;  22        }  23        return enqueueMessage(queue, msg, uptimeMillis);  24  }

  由上可以看出各种推Message的方法最后都归结到 enqueueMessage(...)方法中,该方法实现源码如下:

1 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {  2        //此处,Handler对象被Message对象标记起来, 3        msg.target = this;  4        if (mAsynchronous) {  5            msg.setAsynchronous(true);  6        }  7        //压入MessageQueue里面。8        return queue.enqueueMessage(msg, uptimeMillis);  9 }

 

再次,Looper发现MessageQueue有Message,于是获取该Message相应的Handler,并将Messager给Handler处理。

  Looper又是如何发现MessageQueue里面的Message,并且分配给指定的Handler?答案是通过Looper.loop()方法,源码如下:

1 public static void loop() {   2         final Looper me = myLooper();   3         if (me == null) {   4             throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");   5         }   6         //获取到Looper对象的MessageQueued对象。   7         final MessageQueue queue = me.mQueue;   8    9         .............10         //开始无限循环11         for (;;) {  12             //从MessageQueue里面读取Message,如果消息暂时不被读取会被阻塞。13             Message msg = queue.next(); 14             if (msg == null) {  15                 // No message indicates that the message queue is quitting.  16                 //消息为空退出。17                 return;  18             }  19   20            ............21             //此处给Message的target(也就是对应的Handler)指派消息。22   23             msg.target.dispatchMessage(msg);  24       25            ............26             //消息被回收27             msg.recycle();  28         }  29 }

 

最后,Handler处理该Messager

  接上面的源码可知,最后Message又被它的发送者Handler进行处理,调用的方法是dispatchMessage(msg),该方法源码实现如下:

1 public void dispatchMessage(Message msg) {   2         if (msg.callback != null) {   3             handleCallback(msg);   4         } else {   5             if (mCallback != null) {   6                 if (mCallback.handleMessage(msg)) {   7                     return;   8                 }   9             }  10             //该方法会被重写,从而实现自定义的UI改动11             handleMessage(msg);  12         }  13  }

  可以看出,最后调用到了handlerMessage(msg)方法,在通常的实践中,这个方法被重写,从而实现自定义的逻辑。

 

以上过程中需要注意。

Message对象本身存在于一个消息池中。如果消息池中有消息,建议不要使用new的方式产生对象应该复用该对象

Message message = myHandler.obtainMessage(); message.arg1 = 0; myHandler.sendMessage(message);

 

今天就到这吧。这只是一部分,明天再说另一部分。同样的作为进程间通信的开源组件EventBus也将被分析。 

转载于:https://www.cnblogs.com/ouyanliu/p/5735032.html

你可能感兴趣的文章
分布式搜索引擎Elasticsearch的查询与过滤
查看>>
SolidEdge 工程图中如何给零件添加纹理或贴图
查看>>
【Java面试题】14 super.getClass()方法调用
查看>>
六种流行的语言---C、C++、python、Java、php、C#比较[转]
查看>>
AP INVOICES IMPORT API(NOT request)
查看>>
怎样面试程序猿
查看>>
Redhat6.5安装DB2 Express-C版本
查看>>
php的http数据传输get/post...
查看>>
【剑指Offer面试题】 九度OJ1368:二叉树中和为某一值的路径
查看>>
checkbox的name与JavaBean的交互时发现的一个现象
查看>>
基于Token的身份验证——JWT(转)
查看>>
Maven(五)之Maven配置阿里云镜像飞快下jar包
查看>>
Mysql加锁过程详解(5)-innodb 多版本并发控制原理详解
查看>>
script 里写 html 模版
查看>>
vue2.0 + vux (三)MySettings 页
查看>>
ASP.NET Core 使用 Alipay.AopSdk.Core 常见问题解答
查看>>
spring @Value 设置默认值
查看>>
带你从零学ReactNative开发跨平台App开发(十一)
查看>>
java 生成zip文件并导出
查看>>
atitit.userService 用户系统设计 v4 q316 .doc
查看>>