这个话题相信大家都不陌生,本人权当是一次比较系统的梳理。
Handler的几种消息发送方式
在Android中最常用的消息通信机制,即子线程和UI线程之间的通信,我们一般是基于Handler机制实现的,那么下面来看一看Handler的几种发送消息的方式。
1.sendMessage(Message message)
最常用的一种方式,下面我们一层层走下去。最后走到了sendMessageAtTime这个方法。我们见到了MessageQueue,相信大家也都知道,这就是传说中的那个消息队列,那么这个队列到底在哪初始化的呢?
假如我们使用的是new Handler()这个构造函数, 那么最终是调用Handler(Callback callback, boolean async)这个构造函数,可以看到这么行代码 mQueue = mLooper.mQueue,瞬间明朗,原来是Looper中的。(可参见Looper)
2.post(Runnable)
当我们在子线程中执行完之后,然后只想在执行一段代码块,二不需进行一些判断等操作时,我们可以使用该方法。sendMessageDelayed(getPostMessage(r), 0); 按照我们传统的理解,Handler发送消息,Looper取消息,那么现在这里居然没有消息,很奇怪哈。

private static Message getPostMessage(Runnable r, Object token) {        Message m = Message.obtain();        m.obj = token;        m.callback = r;        return m;    }

你自己虽然没有取消息,但是系统已经帮你做了,并且还将你的Runnable放到了消息中
后面的流程就和普通的发送消息类似了,走到了enqueueMessage这步。
他有一行重要的代码msg.target = this;
3.在Handler的构造方法中自带CallBack

public Handler(Looper looper, Callback callback) {        this(looper, callback, false);    }

最后是这样的,mCallback = callback;

再看Looper
让我们一起来细细的研究一下Looper类中的几个方法。
大家都知道UI线程和我们自己线程的区别,这对待Looper上也是有差别的呢。prepareMainLooper方法说的很清楚了,在UI线程启动的时候,系统会主动为你准备好一个MainLooper,这也是我们为什么只需在子线程中将消息发送就可以了,而无需操心主线程中的Looper,但是,如果是我们往子线程中发送消息呢?那么我们就必须调用prepare方法了,他会执行这么一句代码sThreadLocal.set(new Looper(quitAllowed));(可参见ThreadLocal)

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

MessageQueue有了。
下面再看看Looper的loop()方法,当我们在子线程中调用完prepare()后,便调用该方法,相当于开启轮询器,重要的方法在这里 msg.target.dispatchMessage(msg);
那么这里msg.target就是刚才发送消息的Handler啊,是时候看看dispatchMessage了

public void dispatchMessage(Message msg) {        if (msg.callback != null) {            handleCallback(msg);        } else {            if (mCallback != null) {                if (mCallback.handleMessage(msg)) {                    return;                }            }            handleMessage(msg);        }    }

我们会先检查callback这个变量,如果我们是用过post方法处理的,那么就是有这个callback的,其实就是你放进去的Runnable,最后会走到这一步message.callback.run();
然后会检查有没有CallBack,通过方法3处理消息就会有这个CallBack,如果没有,才走handleMessage方法。
ThreadLocal是个什么玩意儿呢
上面的方法源码如下:

 public void set(T value) {        Thread currentThread = Thread.currentThread();        Values values = values(currentThread);        if (values == null) {            values = initializeValues(currentThread);        }        values.put(this, value);    }

1.拿到当前线程
2.拿到当前线程中的ThreadLocal.Values对象
3.将value放进去,键值即为当前的ThreadLocal
那么,我们可以这样理解,在每一个线程中都维护了一个ThreadLocal.Values对象,他相当于一个
集合,用于保存一些引用,那么当我们调用Looper.prepare()时,实际上是new出了一个Looper,然后保存到了ThreadLocal中的Values中。

更多相关文章

  1. [置顶] Android点击Button实现功能的几种方法
  2. Android架构实例分析之注册hello HAL的JNI方法表
  3. 经典Android试题及答案
  4. android 程序中运行main方法
  5. [Android] 单独编译生成boot.img时mkbootfs: No such file or di
  6. Android提供的系统服务之--WindowManager(窗口管理服务)
  7. ContentProvider详解
  8. Android(安卓)button 性能探讨
  9. 安卓(Android)实现选择时间功能

随机推荐

  1. 数据库查询构造器
  2. TF卡里面的文件名目录名或卷标语法不正确
  3. mysql数据库ddl与dml语言实操
  4. 名词解释:外贸推广人员口中的谷歌SEO是什
  5. Java 给 Word 添加数字签名
  6. 变换Mac上的墙纸的4种方法
  7. LDAP/SASL/GSSAPI/Kerberos编程API(5)--k
  8. 项目启动大会,数据治理项目不容忽视的关键
  9. 智慧气象与数字化转型相关思考
  10. BlueStore checksum机制