Android消息机制
来源:互联网 发布:java中compare to 编辑:程序博客网 时间:2024/06/16 08:43
好多东西都忘了,看过的源码得记录一下,今天就来分析Andorid消息机制的源码。
Android消息机制主要涉及:
Handler、Looper、MessageQueue、Message、ThreadLocal
它们之间的关系如下所示:
有几个疑问:
1. 在哪发消息? 2. 消息发到哪里去了? 3. 消息最后怎么被处理了? 4. 怎么就把在子线程发的消息变换到了主线程? 5. 上面各个类都是什么作用呢?
Android消息机制在实际开发中的应用
正式开始之前,先看一个Handler在多线程中具体使用的案例:
一个很简单的需求:点击页面上的按钮后更新TextView的内容。public class HandlerActivity extends AppCompatActivity { private UpdateHandler handler; private TextView tv; static class UpdateHandler extends Handler{ private WeakReference<HandlerActivity> mHandlerActivity; public UpdateHandler(HandlerActivity handlerActivity) { this.mHandlerActivity = new WeakReference<HandlerActivity>(handlerActivity); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); HandlerActivity handlerActivity = mHandlerActivity.get(); if (handlerActivity != null){ handlerActivity.tv.setText((String)msg.obj); } } } @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); init(); onLoad(); } private void init() { setContentView(R.layout.activity_handler); tv = (TextView) findViewById(R.id.tv); handler = new UpdateHandler(this); } private void onLoad(){ new Thread(){ @Override public void run() { super.run(); try{ Thread.sleep(4000); }catch (Exception e){ e.printStackTrace(); } Message msg = new Message(); msg.what = 1; msg.obj = "加载完成"; handler.sendMessage(msg); } }.start(); } @Override protected void onDestroy() { super.onDestroy(); handler.removeCallbacksAndMessages(null); }}
在主线程创建一个Handler,然后开启一个工作线程待工作线程休眠4000毫秒后,发出一个Message然后在主线程更新TextView的内容。
消息机制源码分析
结合上面的例子,下面就挨个把这些问题搞明白:
在子线程中发出的消息,通过如下代码:
Message msg = new Message();msg.what = 1; //Message标识msg.obj = "加载完成"; //要传输的信息handler.sendMessage(msg);
追踪sendMessage的源码:
handler.sendMessage(message);
发现经过一串的调用sendMessage->sendMessageDelayed->sendMessageAtTime,最后走到了sendMessageAtTime这个方法中。
public final boolean sendMessage(Message msg){ return sendMessageDelayed(msg, 0); }
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); }
sendMessageAtTime中将Message入队,也就是放入到MessageQueue,MessageQueue是一个由链表实现的消息队列。
发送一个Runnable过程:
public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); }
//该方法把Runnable转换成Message private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }
接下来走到sendMessageDelayed,以Message的方式继续处理
在sendMessageAtTime中调用了enqueueMessage(queue,msg,uptimeMillis)方法,在这个方法中进行了入队操作:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis);}
而真正的入队操作则到了MessageQueue中,代码如下:
boolean enqueueMessage(Message msg, long when) { if (msg.target == null) { throw new IllegalArgumentException("Message must have a target."); } if (msg.isInUse()) { throw new IllegalStateException(msg + " This message is already in use."); } synchronized (this) { if (mQuitting) { IllegalStateException e = new IllegalStateException( msg.target + " sending message to a Handler on a dead thread"); Log.w(TAG, e.getMessage(), e); msg.recycle(); return false; } msg.markInUse(); msg.when = when; Message p = mMessages; boolean needWake; if (p == null || when == 0 || when < p.when) { // New head, wake up the event queue if blocked. msg.next = p; mMessages = msg; needWake = mBlocked; } else { // Inserted within the middle of the queue. Usually we don't have to wake // up the event queue unless there is a barrier at the head of the queue // and the message is the earliest asynchronous message in the queue. needWake = mBlocked && p.target == null && msg.isAsynchronous(); Message prev; for (;;) { prev = p; p = p.next; if (p == null || when < p.when) { break; } if (needWake && p.isAsynchronous()) { needWake = false; } } msg.next = p; // invariant: p == prev.next prev.next = msg; } // We can assume mPtr != 0 because mQuitting is false. if (needWake) { nativeWake(mPtr); } } return true; }
看到prev=p、p = p.next、msg.next=p、prev.next=msg, 这不就是链表吗?所以MessageQueue是以单链表的形式来存储Message
到此为止:
消息已经发出去了,也存到了MessageQueue中等待被处理了,那么问题来了: 1. MessageQueue是被谁处理的? 2. 被怎么处理的?
这个时候Looper就隆重登场了!
在主线程中创建了我们的Handler
handler = new UpdateHandler(this);
追踪源码,此处调用的是Handler默认的构造方法,源码如下:
/** * Default constructor associates this handler with the {@link Looper} for the * current thread. * <p> * If this thread does not have a looper, this handler won't be able to receive messages * so an exception is thrown. */ public Handler() { this(null, false); }
注释告诉我们:
默认的构造方法已经关联了一个当前线程的Looper如果是我们自己启动的线程,不自己准备Looper的话就会抛出异常:Can’t create handler inside thread that has not called Looper.prepare()
接下来调用:
public Handler(Callback callback, boolean async) { 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;}
在主线程启动的时候,已经为我们准备了一个默认的主线程使用的Looper,在ActivityThread中,有如下代码:
public static void main(String[] args) { ...... Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } // End of event ActivityThreadMain. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); Looper.loop(); ......}
其中的两句代码,就可以帮我们揭秘——上面提到的两个问题:
MessageQueue中的消息是被谁处理的?
怎么被处理的?
其中的代码:
Looper.prepareMainLooper();...if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler();}Looper.loop();
这就是为什么,我们在Activity中的OnCreate方法中创建了Handler但是并没有调用Looper.prepre()和Looper.loop()但是没问题的原因,使用的是主线程Looper。
下面看看两个方法,先看看prepareMainLooper:
//为当前线程创建一个Looper,Android环境已经为你准备好了,不需要再调用这个方法。 public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } }
这个方法中调用了prepare(false)方法:
private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } //创建一个Looper,并设置给ThreadLocal sThreadLocal.set(new Looper(quitAllowed)); }
ThreadLocal:现场内部的数据存储类,以线程为单元存储数据,此处在每个现场里都存了Looper。
很好奇new Looper(quitAllowed)这句代码做了什么,点击去看看:
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread();}
一个private方法,我们无法new出一个Looper来,其中包含一个MessageQueue和当前的线程!因为当前线程是主线程,所以MessageQueue,Looper都是在主线程中。
在prepareMainLooper方法的最后,调用了myLooper()方法:
/** * 返回当前线程关联的Looper对象,如果当前线程没有关联Looper对象那么就返回null.*/public static @Nullable Looper myLooper() { return sThreadLocal.get();}
至此,Looper.prepare()方法分析完毕,已经为主线程准备好了Looper。
接下来看,Looper.loop()方法:
/** * 轮询当前线程的消息队列。在轮询完成之后确保调用了quit()方法。 */ public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; ...... //死循环 for (;;) { Message msg = queue.next(); // 可能会阻塞,从MessageQueue中获取下一个消息 if (msg == null) { // No message indicates that the message queue is quitting. return; } ...... try { //msg.target 就是Handler,从MessageQueue中获取到的Message,被分发给了Handler中的dispatchMessage方法 msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } ...... } }
在Looper.loop()方法中,我们找到了答案:
阻塞式的获取消息队列中的Message。然后,调用Handler中的dispatchMessage进行Message的分发。
下面看看dispatchMessage的代码:
/** * 在这儿处理系统Message */ public void dispatchMessage(Message msg) { if (msg.callback != null) { //处理runnable handleCallback(msg); } else { if (mCallback != null) { //new Hanlder(CallBack)处理callBack if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); //处理message } }
接下来子类实现handlerMessage方法来处理消息:
/** * 子类应该实现这个方法,来接收消息 */ public void handleMessage(Message msg) { }
最后消息,在子类的handlerMessage方法中被处理了!
处理Runnable:
private static void handleCallback(Message message) { message.callback.run(); }
Message数据结构:
public class Message{ Handler target; Runnable callback; }
这样Android中的消息机制的源码就分析完毕了,下面来回答刚开始提出的问题!
问题揭秘
1. Message在哪儿发出的
在子线程中发出的消息,通过如下代码:
Message msg = new Message();msg.what = 1;msg.obj = "加载完成";handler.sendMessage(msg);
2. Message发到哪儿去了?
Message发送到了MessageQueue中,一个消息队列中!单链表的形式存储数据
3. Message最后怎么被处理的?
Message被Looper的Loop方法从MessageQueue中借助next()方法取出,分发给Handler中的dispatchMessage方法,进行处理。这是一个典型的生产者、消费者模型!
4. 怎么就把子线程发出的消息变换到了主线程中?
子线程把Message发送到了MessageQueue中,MessageQueue在Looper中初始化,Looper在主线程中,所以MessageQueue也在主线程中,消息就这样被变换到了主线程中。
5. 上面各个类都是什么作用呢?
Handler:发送消息、处理消息
Looper:消息泵,用来从MessageQueue中读取消息
MessageQueue:消息队列,存储Message。内部用链表实现
Message:主线程和子线程之间的通信载体
ThreadLocal: 线程内部的数据存储类,在指定的线程中存储数据,以线程为单元。
Handler在什么线程中创建,Handler就在什么线程,Looper、Message也在该线程工作。UI线程默认有Handler、Looper,并开启了消息循环;在子线程中默认没有Looper,需要创建Looper,并开启消息循环,方式如下:
Looper.prepare(); //创建Looper,Looper以线程为单元hanlder = new Hanlder();Looper.loop(); //开启消息循环
至此,Android消息机制的源码就分析完毕!
- Android消息机制(Handler机制)
- android Handler机制 消息机制
- Android 消息处理机制
- Android消息机制
- android 消息机制
- Android消息机制(一)
- Android消息处理机制
- Android消息处理机制
- Android消息机制(一)
- Android 中的消息机制
- Android 消息通知机制
- Android消息机制学习
- Android消息机制(1)
- Android消息机制
- android消息机制
- Android消息机制
- Android的消息机制
- android消息处理机制
- 栈和队列
- 机器学习算法
- 多态测试
- LeetCode 4. Median of Two Sorted Arrays
- ArrayList使用与遍历
- Android消息机制
- MongoDB常用命令汇总之查看聚集集合基本信息。
- js组件中那些晦涩难懂的写法,理解这个以后看组件会容易很多,包括JQ源码
- 字体以及文本的相关属性
- 【二叉树】树的序列化和反序列化【449. Serialize and Deserialize BST】
- 无聊的游戏
- 有n个人围成一圈,顺序排号,从第一个开始报数(从1到3报数),凡报到3的人退出圈子,问最后最后留下的是原来第几号的那位
- ++ 和 -- 运算符
- Linux Expexct and Python pexepct