转载请注明出处:http://blog.csdn.net/lowprofile_coding/article/details/72580044

介绍

前面的内容对Handler做了介绍,也讲解了如何使用handler,但是我们并不知道他的实现原理。本文从源码的角度来分析如何实现的。

首先我们得知道Handler,Looper,Message Queue三者之间的关系

- Handler封装了消息的发送,也负责接收消。内部会跟Looper关联。

- Looper 消息封装的载,内部包含了MessageQueue,负责从MessageQueue取出消息,然后交给Handler处理

- MessageQueue 就是一个消息队列,负责存储消息,有消息过来就存储起来,Looper会循环的从MessageQueue读取消息。

源码分析

当我们new一个Handler对象的时候,看看他的构造方法里面做了什么.

public Handler(Callback callback, boolean async) {

if (FIND_POTENTIAL_LEAKS) {

final Class extends Handler> klass = getClass();

if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&

(klass.getModifiers() & Modifier.STATIC) == 0) {

Log.w(TAG, "The following Handler class should be static or leaks might occur: " +

klass.getCanonicalName());

}

}

mLooper = Looper.myLooper();

if (mLooper == null) {

throw new RuntimeException(

"Can't create handler inside thread that has not called Looper.prepare()");

}

mQueue = mLooper.mQueue;

mCallback = callback;

mAsynchronous = async;

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

从源码中我们看到他会调用Looper.myLooper方法获取一个Looper对象,然后从Looper对象获取到MessageQueue对象。

Looper myLooper()

跟进去看看Looper.myLooper()方法做了什么。这是一个静态方法,可以类名.方法名直接调用。

public static @Nullable Looper myLooper() {

return sThreadLocal.get();

}

1

2

3

这个方法里面就一行代码,从sThreadLocal中获取一个Looper对象,sThreadLocal是一个ThreadLocal对象,可以在一个线程中存储变量。底层是ThreadLocalMap,既然是Map类型那肯定得先set一个Looper对象,然后我们才能从sThreadLocal对象里面get一个Looper对象。

ActivityThread main()

说到这里得给大家介绍一个新的类ActivityThread,ActivityThread类是Android APP进程的初始类,它的main函数是这个APP进程的入口。我们看看这个main函数干了什么事情。

public static final void main(String[] args) {

------

Looper.prepareMainLooper();

if (sMainThreadHandler == null) {

sMainThreadHandler = new Handler();

}

ActivityThread thread = new ActivityThread();

thread.attach(false);

if (false) {

Looper.myLooper().setMessageLogging(new

LogPrinter(Log.DEBUG, "ActivityThread"));

}

Looper.loop();

-----

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

在第二行代码调用Looper.prepareMainLooper()方法,第13行调用了Looper.loop()方法。

Looper prepareMainLooper()

继续跟进Looper.prepareMainLooper()方法,在这个方法中第一行代码调用了内部的prepare方法。prepareMainLooper有点像单例模式中的getInstance方法,只不过getInstance会当时返回一个对象,而prepareMainLooper会新建一个Looper对象,存储在sThreadLocal中。

public static void prepareMainLooper() {

prepare(false);

synchronized (Looper.class) {

if (sMainLooper != null) {

throw new IllegalStateException("The main Looper has already been prepared.");

}

sMainLooper = myLooper();

}

}

1

2

3

4

5

6

7

8

9

Looper prepare()

继续跟进prepare方法,看第5行代码,新建了一个Looper对象,调用sThreadLocal.set方法把Looper对象保存起来。看到这里我想聪明的你们肯定明白了为什么new Handler对象的时候调用Looper.myLooper()方法能从sThreadLocal对象中取到Looper对象。

private static void prepare(boolean quitAllowed) {

if (sThreadLocal.get() != null) {

throw new RuntimeException("Only one Looper may be created per thread");

}

sThreadLocal.set(new Looper(quitAllowed));

}

1

2

3

4

5

6

Looper 构造方法

文章开头我们就讲到Looper内部包含了MessageQueue,其实就是在new Looper对象的时候就new了一个MessageQueue对象。

private Looper(boolean quitAllowed) {

mQueue = new MessageQueue(quitAllowed);

mThread = Thread.currentThread();

}

1

2

3

4

Looper loop()

ActivityThread类main方法中调用了Looper的两个方法,前面我们解释了prepareMainLooper(),现在来看第二个方法loop()。

public static void loop() {

final Looper me = myLooper();//获取Looper对象

if (me == null) {

throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");

}

final MessageQueue queue = me.mQueue;//从Looper对象获取MessageQueue对象

// Make sure the identity of this thread is that of the local process,

// and keep track of what that identity token actually is.

Binder.clearCallingIdentity();

final long ident = Binder.clearCallingIdentity();

for (;;) {//死循环  一直从MessageQueue中遍历消息

Message msg = queue.next(); // might block

if (msg == null) {

return;

}

// This must be in a local variable, in case a UI event sets the logger

final Printer logging = me.mLogging;

if (logging != null) {

logging.println(">>>>> Dispatching to " + msg.target + " " +

msg.callback + ": " + msg.what);

}

final long traceTag = me.mTraceTag;

if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {

Trace.traceBegin(traceTag, msg.target.getTraceName(msg));

}

try {

//调用handler的dispatchMessage方法,把消息交给handler处理

msg.target.dispatchMessage(msg);

} finally {

if (traceTag != 0) {

Trace.traceEnd(traceTag);

}

}

if (logging != null) {

logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);

}

// Make sure that during the course of dispatching the

// identity of the thread wasn't corrupted.

final long newIdent = Binder.clearCallingIdentity();

if (ident != newIdent) {

Log.wtf(TAG, "Thread identity changed from 0x"

+ Long.toHexString(ident) + " to 0x"

+ Long.toHexString(newIdent) + " while dispatching to "

+ msg.target.getClass().getName() + " "

+ msg.callback + " what=" + msg.what);

}

msg.recycleUnchecked();

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

这个方法的代码呢比较多。我都给代码加上了注释。其实就是一个死循环,一直会从MessageQueue中取消息,如果取到了消息呢,会执行msg.target.dispatchMessage(msg)这行代码,msg.target就是handler,其实就是调用handler的dispatchMessage方法,然后把从MessageQueue中取到的message传入进去。

Handler dispatchMessage()

public void dispatchMessage(Message msg) {

//如果callback不为空,说明发送消息的时候是post一个Runnable对象

if (msg.callback != null) {

handleCallback(msg);

} else {

if (mCallback != null) {//这个是用来拦截消息的

if (mCallback.handleMessage(msg)) {

return;

}

}

handleMessage(msg);//最终调用我们重写的handleMessage方法

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

这个方法对消息做最后处理,如果是post类型调用handleCallback方法处理,如果是sendMessage发送的消息。看我们有没有拦截消息,如果没有最终调用handleMessage方法处理。

Handler handleCallback()

看到这里我们知道为什么post一个Runnable对象,run方法执行的代码在主线程了吧,因为底层根本就没有开启线程,就只是调用了run方法而已。

private static void handleCallback(Message message) {

message.callback.run();

}

1

2

3

前面我们从创建handler对象开始,以及创建Looper,创建MessageQueue的整个流程,现在来分析下,当我们调用post以及sendMessage方法时,怎么把Message添加到MessageQueue。

Handler post()

调用了getPostMessage方法,把Runnable传递进去。

public final boolean post(Runnable r)

{

return  sendMessageDelayed(getPostMessage(r), 0);

}

1

2

3

4

Handler getPostMessage()

首先调用Message.obtain()方法,取出一个Message对象,这个方法之前有讲过,然后把Runnable对象赋值了Message对象的callback属性。看到这里我们也明白了dispatchMessage方法为什么要先判断callback是否为空了吧。

private static Message getPostMessage(Runnable r) {

Message m = Message.obtain();

m.callback = r;

return m;

}

1

2

3

4

5

Handler enqueueMessage()

在post方法里面调用了sendMessageDelayed方法,其实最终调用的是enqueueMessage方法,所以我这里就直接看enqueueMessage方法源码。第一行代码就把handler自己赋值给messgae对象的target属性。然后调用MessageQueue的enqueueMessage方法把当前的Messgae添加进去。

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {

msg.target = this;

if (mAsynchronous) {

msg.setAsynchronous(true);

}

return queue.enqueueMessage(msg, uptimeMillis);

}

1

2

3

4

5

6

7

总结

总结:handler负责发送消息,Looper负责接收Handler发送的消息,并直接把消息回传给Handler自己。MessageQueue就是一个存储消息的容器。

---------------------

作者:安辉就是我

来源:CSDN

原文:https://blog.csdn.net/lowprofile_coding/article/details/72580044

版权声明:本文为博主原创文章,转载请附上博文链接!

C语言handler类作用,Handle的原理(Looper、Handler、Message三者关系)相关推荐

  1. Handle的原理(Looper、Handler、Message三者关系)

    转载请注明出处:http://blog.csdn.net/lowprofile_coding/article/details/72580044 介绍 前面的内容对Handler做了介绍,也讲解了如何使 ...

  2. Android异步消息处理机制 深入理解Looper、Handler、Message三者关系

    转载子:http://blog.csdn.net/lmj623565791/article/details/38377229 ,本文出自[张鸿洋的博客] 很多人面试肯定都被问到过,请问Android中 ...

  3. Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系

    很多人面试肯定都被问到过,请问Android中的Looper , Handler , Message有什么关系?本篇博客目的首先为大家从源码角度介绍3者关系,然后给出一个容易记忆的结论. 1. 概述 ...

  4. Handle的原理分析

    介绍 Handle的原理(Looper.Handler.Message三者关系 前面的内容对Handler做了介绍,也讲解了如何使用handler,但是我们并不知道他的实现原理.本文从源码的角度来分析 ...

  5. Android 系统(59)---Android开发:Handler异步通信机制全面解析(包含Looper、Message Queue)

    Android开发:Handler异步通信机制全面解析(包含Looper.Message Queue) 前言 最近刚好在做关于异步通信的需求,那么,今天我们来讲解下Android开发中的Handler ...

  6. android 消息循环机制--looper handler

    Looper类说明   Looper 类用来为一个线程跑一个消息循环. 线程在默认情况下是没有消息循环与之关联的,Thread类在run()方法中的内容执行完之后就退出了,即线程做完自己的工作之后就结 ...

  7. Android Handler消息队列的实现原理

    我们在写Android程序的时候,有经常用到Handler来与子线程通信,亦或者是用其来管理程序运行的状态时序.Handler其是由Android提供的一套完善的操作消息队列的API.它既可以运行在主 ...

  8. java 泛化_Java语言class类用法及泛化(详解)

    这篇文章主要介绍了Java语言class类用法及泛化(详解),大家都知道Java程序在运行过程中,对所有的对象进行类型标识,也就是RTTI.这项信息记录了每个对象所属的类.虚拟机通常使用运行时类型信息 ...

  9. 用一句话概括Handler,并简述其原理

    目录 Q1:用一句话概括Handler,并简述其原理? (1)Handler是什么? (2)Handler的原理是什么? (3)Handler有什么作用? (4)为什么使用handler,Messag ...

最新文章

  1. 调制优缺点_复合铝基润滑脂和普通润滑脂的区别,复合铝基脂有什么优缺点
  2. oracle和dba,oracle db、dba和rdba
  3. 什么叫做“假学习”?什么叫做“真学习”?
  4. Qt C++属性类型提供给 QML调用(三)
  5. 【计算机视觉】究竟谁能解决可解释性 AI?
  6. 通过简单的 ResourceManager 管理 XNA 中的资源,WPXNA(二)
  7. B - Friends
  8. ajax:html5上传文件,上传之前可以实现本地预览
  9. python装饰器详解-python装饰器使用实例详解
  10. Cloudflare配置网站免费CDN加速使用教程
  11. 命令查看windows2008是否激活
  12. R语言实战笔记后续修改
  13. 八皇后问题(回溯问题)
  14. 多个路由器设置静态路由 不同网段可以互相访问
  15. 邮件发送html, 分别用p,code,xmp三个标签嵌入代码段后的样式比较
  16. 计算机电脑网络电缆,笔记本电脑的网络电缆在哪里
  17. macbookair苹果MAC笔记电脑本更换电池教程
  18. 《Modulated Fusion using Transformer for Linguistic-Acoustic EmotionRecognition》论文翻译
  19. 多种经典色差计算公式——matlab代码
  20. Maya快捷键学习游戏的方法有很多,但是自学和老师带是不一样

热门文章

  1. 小米max刷原生android,小米max标准版 魔趣OS 安卓10 MagiskV21版 完美ROOT 纯净完美 原生极简 纯净推荐...
  2. 解决selenium模拟浏览器爬取(淘宝、微博等需要登陆验证的网站)多次登陆问题
  3. 鬼笔环肽蛋白研究——罗丹明标记鬼笔环肽
  4. MATLAB中果蝇味道浓度判定函数,果蝇优化算法MATLAB实现
  5. Detail-revealing Deep Video Super-resolution 中文翻译
  6. 计算机操作教学计划,计算机操作基础教学计划.doc
  7. 腾讯阿里原来是这样设计api的
  8. 深度学习之---起源
  9. 我们如何成为ebay卖家?ebay入驻条件
  10. 程序员35岁被裁只能开滴滴、送外卖?这条晋升道路你一定别错过