Android 消息传递机制分析
来源:互联网 发布:淘宝橙色cmyk 编辑:程序博客网 时间:2024/06/16 18:16
Android中采用Handle进行消息传递,本文从实例出发分析Handle中一个Message从创建到处理整个流程,以此阐明消息传递机制原理。
一、Handle使用示例
1、在Android studio 创建一个默认项目,在MainActivity中写下如下代码:
public class MainActivity extends AppCompatActivity { private TextView tv; private final static int MSGTYPE =1; //主线程中创建Handle,并重写Handle处理消息的方法handleMessage() //我这里只是简单处理更新一个textview显示 Handler mHandle = new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what){ case MSGTYPE: if(tv !=null){ tv.setText(String.valueOf(msg.obj)); Log.d("Handle",String.valueOf(msg.obj)); } break; } super.handleMessage(msg); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = (TextView) findViewById(R.id.tv); new Thread(){ @Override public void run() { try { for(int i= 0 ; i<10; i++) { Thread.sleep(1000); //建立一个消息实体,并携带数据 Message msg = new Message(); msg.what = MSGTYPE; msg.obj = "Thread" + i; //通过Handle发送消息 mHandle.sendMessage(msg); } } catch (InterruptedException e) { e.printStackTrace(); } } }.start(); }}
子线程通过handle发消息给主线程(UI线程)然后在主线程handle中处理消息,来达到更新UI目的。那么问题来了在这里我们为什么不直接在主线程更新UI或者直接在子线程调用tv.setText()?不在主线程更新是因为主线程不能进行耗时操作,假设一种场景tv控件的数据来源于网络,需要建立一个http获取数据,网络操作是一种极其耗时操作,要等几秒才能更新UI,这对用户体验来说极其不好,而且Android规定UI线程5s没反应,会报ANR错误,所以耗时操作都放子线程。而由于主线程不是线程安全的,Android规定子线程不能更新UI元素。
二、Handle原理分析
在这里我们从上述demo中mHandle.sendMessage(msg)这句代码作为切入口,分析这个msg经过哪些流程被送到mHandle.handleMessage(msg)中进行处理的。
进入Handle.java
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) { //Handle类持有MessageQueue引用 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); }private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { //target类型是Handle,this代表消息最终由哪个handle处理 msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
可以发现,Handle发送的msg被添加进消息队列中,至此我们进入MessageQueue.java
boolean enqueueMessage(Message msg, long when) { .... synchronized (this) { 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 { 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; }
enqueueMessage()这个方法是把消息加入消息队列,中间有一些if-else判断,当队列为空,主线程空闲等待,有消息加入时则唤醒主线程。我们再来看看Looper.java是怎样从队列拿消息分发给handle处理
public Handler(Callback callback, boolean async) { ... //Handle持有所在线程looper对象引用 mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } //Handle持有Looper内部成员MessageQueue的引用 mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; } public static @Nullable Looper myLooper() { //返回当前线程所保存的looper对象,这里用到了ThreadLocal //ThreadLocal是线程内部存储数据类,是线程的一个内部成员, //在这里保存了自己的创建的looper对象 return sThreadLocal.get(); } //prepare用于初始化looper对象private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } //创建looper对象,并保存looper到当前线程ThreadLocal中 sThreadLocal.set(new Looper(quitAllowed)); }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 (;;) { //next()从队列拿消息,当队列为空时则阻塞等待 Message msg = queue.next(); if (msg == null) { // 如果没有消息,表明消息队列正在退出 return; } try { //消息不为空,调用target对象dispatchMessage(), //在发送msg时,msg的target就保存了发送消息的 //handle对象,此时这个msg就送到处理消息的handle中 msg.target.dispatchMessage(msg); } finally { .... } ..... } }public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } //handleMessage(msg)被我们重载实现 handleMessage(msg); } }
通过UML绘制Handle、Message、MessageQueue、Looper之间关系
至此,一个消息完成整个流程。
- Android 消息传递机制分析
- Android 消息传递机制分析
- 源码分析Android消息传递机制
- android 消息传递机制
- Android消息传递机制
- android消息传递机制
- android消息传递机制
- android消息传递机制
- Android消息传递机制
- Android消息传递机制
- 从源码分析Android中Handler的消息传递机制
- Android UI消息传递机制
- Android Handler消息传递机制
- Android Handler消息传递机制
- android Handler 消息传递机制
- Android Handler消息传递机制
- android Handler 消息传递机制
- Android:Handler消息传递机制
- 了解神经网络中的梯度爆炸
- 利用遗传算法优化神经网络:Uber提出深度学习训练新方式
- 为给定任务自动生成神经网络:MIT提出RNN架构生成新方法
- 渡鸦音箱独家测评: 代表百度AI技术尊严的DuerOS, 用户体验真的能过关吗?
- 滚石特写: 沉默7年后, Magic Leap用魔幻现实主义式科技重新定义了自己
- Android 消息传递机制分析
- 从Pix2Code到CycleGAN:2017年深度学习重大研究进展全解读
- 谈谈JavaSE中的一些扩容机制-<StringBuffer,StringBuilder>
- 年薪百万程序员的成功基础
- 为什么程序员要会linux
- 微软正考虑添加 Python 为官方的 Excel 脚本语言!
- 关于程序员的6个问答题
- 要多努力,才能活着离开中兴(上篇 无妄之灾)
- 百度算法更新大全(2013