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

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

 import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.MessageQueue;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView; public class MainActivity extends AppCompatActivity { private TextView myTextView;
private Handler myHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
//UI线程接收到消息 int arg1 = msg.arg1;
switch (arg1){
case 0:
if(msg.arg2 == 0){
//更新UI
myTextView.setText((String)msg.obj);
}
break;
default:
break;
}
super.handleMessage(msg); }
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myTextView = (TextView)this.findViewById(R.id.text_view);
//起独立线程
new Thread(){
public void run(){
String text = "from handler";
Message message = new Message();
message.arg1 = 0;
message.arg2 = 0;
message.obj = text;
//通过Handler给UI发消息 myHandler.sendMessage(message);
}
}.start();
}
}

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

消息的流转的架构:

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

消息的流转的过程:

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

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

 private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mRun = true;
mThread = Thread.currentThread();
}

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

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

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

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

 public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
..............
//获取Looper对象
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
//绑定MessageQueue对象
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}

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

 public final boolean sendMessage(Message msg)  {
return sendMessageDelayed(msg, 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}

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

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

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

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

 public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//获取到Looper对象的MessageQueued对象。
final MessageQueue queue = me.mQueue; .............
//开始无限循环
for (;;) {
//从MessageQueue里面读取Message,如果消息暂时不被读取会被阻塞。
Message msg = queue.next();
if (msg == null) {
// No message indicates that the message queue is quitting.
//消息为空退出。
return;
} ............
//此处给Message的target(也就是对应的Handler)指派消息。 msg.target.dispatchMessage(msg); ............
//消息被回收
msg.recycle();
}
}

最后,Handler处理该Messager

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

 public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//该方法会被重写,从而实现自定义的UI改动
handleMessage(msg);
}
}

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

以上过程中需要注意。

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

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

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

Handler 原理分析和使用(二)

最新文章

  1. Hibernate一对多关联
  2. js获取浏览器前缀
  3. 6.Counting Point Mutations
  4. JQuery Easy Ui DataGrid
  5. C#的变迁史 - C# 4.0 之多线程篇
  6. hdoj 2046 骨牌铺方格
  7. UVALive-4287 Proving Equivalences 有向图的强连通分量+缩点
  8. Date对象
  9. LeetCode-Divdend two Integers
  10. cpanel导入大数据库(mysql)的方法
  11. Linux redhat ICE环境安装
  12. Linux 终端 Bash 常用快捷键介绍及经验
  13. 调试 lvgl 的一个例子
  14. MT【213】二次曲线系方程
  15. 【Latex】常用工具包
  16. 通过数组和枚举简化GPIO操作编码(转)
  17. selenium webdriver 实现Canvas画布自动化测试
  18. C语言--成绩汇总(5班)
  19. golang的Flag和Pflag
  20. 微信小程序 - 分包加载(预下载)

热门文章

  1. C#常见算法题目(面试准备)
  2. (转载)struct 与typdef struct的区别
  3. javascript在alert()出现中文乱码
  4. ARM学习笔记9——ARM汇编汇编语言中的伪指令
  5. Bzoj 1984: 月下“毛景树” 树链剖分
  6. 稀疏矩阵coo_matrix的乘法
  7. usaco 购买饲料 &amp;&amp; 修剪草坪
  8. mv、umask、chattr、lsattr命令
  9. [学习笔记]设计模式之Abstract Factory
  10. ubuntu 安装软件(apt源)