Android 消息机制
2016-03-29 15:10
573 查看
这篇文章讲的Android SDK版本是API 23。
Android分为UI线程(主线程),和普通的线程(自己写的线程)。做Android的都知道,需要启动线程请求网络或者做
耗时的操作,否则会报ANR异常。另外不能在子线程中去更新UI,不然又会报异常
消息循环。子线程没有消息循环需要自己添加。UI线程默认有消息循环,这是项目启动的时候系统添加进去的,看ActivityThread.java类源码:
例如:
如果不懂ThreadLocal,可以去网上查查。所以说Looper与线程的关联就是通过ThreadLocal来实现的。这样就给线程创建了一个消息循环
而且在创建Looper实例的时候初始化了一个MessageQueue实例,看Looper的构造方法:
总的来说就是,在创建Handler的时候取得了Handler所在线程的Looper实例,和Looper中的MessageQueue实例,这个过程是通过ThreadLocal实现。然后把消息添加到该MessageQueue中,当调用loop方法的时候,取出消息,然后调用消息中Handler的dispatchMessage方法,把消息又交给了Handler的HandleMessage处理。
至此,消息机制讲完了,其中它们的关联实现,ThreadLocal起了很大作用。其实通过Handler更新UI用的比较少了。可以用回调,也可以用Android的AsynTask类。不过AsynTask效率不高,不常用,下一篇讲AsynTask类!!!
Android分为UI线程(主线程),和普通的线程(自己写的线程)。做Android的都知道,需要启动线程请求网络或者做
耗时的操作,否则会报ANR异常。另外不能在子线程中去更新UI,不然又会报异常
Only the original thread that created a view hierarchy can touch its views.所以需要使用
消息循环。子线程没有消息循环需要自己添加。UI线程默认有消息循环,这是项目启动的时候系统添加进去的,看ActivityThread.java类源码:
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); <span style="background-color: rgb(255, 0, 0);">Looper.loop();</span> throw new RuntimeException("Main thread loop unexpectedly exited"); }
这个类是项目启动的时候自己调用的,为我们创建了消息循环红色这行Looper.prepareMainLooper();是Looper里的,后面会讲到。所以在UI线程 中创建Handler的时候不需要创建消息循环。但是在子线程中创建Handler就需要创建消息循环,也就是调用
Looper.prepare();
Looper.loop(); 为子线程创建消息循环。
例如:
class LooperThread extends Thread { public void run() { Looper.prepare(); Log.d("MainActivity", "after prepare"); Handler mHandler=new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); Log.d("MainActivity", msg.what""); } }; mHandler.sendMessage(new Message()); mHandler.sendEmptyMessage(0); Looper.loop(); Log.d("MainActivity", "after loop"); } }
两行关键的代码,Looper.prepare()和Looeper.loop()。看下Looper.prepare();的源代码:
public static void prepare() { prepare(true); } 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)); } /** * Initialize the current thread as a looper, marking it as an * application's main looper. The main looper for your application * is created by the Android environment, so you should never need * to call this function yourself. See also: {@link #prepare()} */ public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } }
上面代码其实就是把一个Looper实例添加到了当前线程的本地变量里,也就是调用了红色的这么一句代码:
sThreadLocal.set(new Looper(quitAllowed)); 想必大家看到了prepareMainLooper(),这里面也是调用了prepare方法,这个方法是有ActivityThread自己调用的,所以UI线程默认会有消息循环!!!每一个线程只有一个Looper,否则会抛出throw new RuntimeException("Only one Looper may be created per thread");
如果不懂ThreadLocal,可以去网上查查。所以说Looper与线程的关联就是通过ThreadLocal来实现的。这样就给线程创建了一个消息循环
而且在创建Looper实例的时候初始化了一个MessageQueue实例,看Looper的构造方法:
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }当调用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."); } final MessageQueue queue = me.mQueue; // 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 (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } // This must be in a local variable, in case a UI event sets the logger Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } <span style="color:#FF0000;">msg.target.dispatchMessage(msg);</span> 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(); } }
那么到底是怎么分发出去的呢?又分发到哪里去了呢?重点看这一行代码: msg.target.dispatchMessage(msg); Message的target是Handler类型,Handler把消息添加到消息队列的时候把自己赋值给了Message的target,看下面的代码:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }Looper.loop()是通过循环不断的把消息队列中的消息分发给当前的Handler,所以Handler既是消息的发送者,又是消息的处理者。它是怎么做的呢?看Handler的创建过程:
public Handler() { this(null, false); } 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; } public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
创建Handler的时候调用: mLooper=Looper.myLooper(); 也就是Looper里的方法从当前Handler所在的线程中取出了属于当前线程的Looper,并且mQueue = mLooper.mQueue;取出了消息队列mQueue。 所以Handler发送消息就是把消息添加到了MessageQueue中,看Handler发送消息的一步步调用:
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); } private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this;//这里刚才已经说过,Handler把自己赋值给了Message的target if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
这里是通过层层调用的,不过没关系,只是一些方法的封装。最后一个方法最后一行: queue.enqueueMessage(msg, uptimeMillis); 就是调用消息队列的方法把消息添加进入了,自己可以去看看。在添加消息的过程中有这么一句msg.target = this;这里就是给target赋值。 this当然是指的Handler,所以在loop方法中才可以调用Handler的dispatchMessage(Message msg)方法。 看下dispatchMessage(Message msg)源码:
/** * Handle system messages here. */ public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg);</span> } }
在这个方法里我们看到了熟悉的方法: handleMessage(msg); 这就是在重写Handler的时候自己实现的方法,这是个空的没有实现的方法,需要我们自己实现,这里仅仅是回调。到此Handler就完成了发送消息到 接收处理消息的过程。
总的来说就是,在创建Handler的时候取得了Handler所在线程的Looper实例,和Looper中的MessageQueue实例,这个过程是通过ThreadLocal实现。然后把消息添加到该MessageQueue中,当调用loop方法的时候,取出消息,然后调用消息中Handler的dispatchMessage方法,把消息又交给了Handler的HandleMessage处理。
Handler还有post方法,handler.post(Runnable r),它的参数是一个线程实例,内部也是创建了一个消息,看源码:
public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); } private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }
在getPostMessage中获取了一个消息: Message.obtain();这也是官方推荐的获取消息的方法,效率高。并把post的线程实例赋值给了消息的callBack变量:Runnable callback;当然, 在后面的消息分发时候做了判断,再次看Handler的dispatchMessage方法:
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
这里是做了判断的,当msg.callback不为空,也就是post的时候回调用:
handleCallback(msg);这里面调用了Runnable的run方法,也就是我们自己写的:
private static void handleCallback(Message message) { message.callback.run(); }
至此,消息机制讲完了,其中它们的关联实现,ThreadLocal起了很大作用。其实通过Handler更新UI用的比较少了。可以用回调,也可以用Android的AsynTask类。不过AsynTask效率不高,不常用,下一篇讲AsynTask类!!!
相关文章推荐
- Android内存泄漏分析及调试
- Android分区
- 从案例学RxAndroid开发
- Retrofit2.0 的使用
- Android各个Support Library介绍
- android studio创建aidl文件
- Android中View(视图)绘制不同状态背景图片原理深入分析以及StateListDrawable使用详解
- Android Activity生命周期与启动模式
- CheckBox 自定义
- android学习之wifi - wifi连接woosim打印机
- Android 代码混淆
- asorm1.0beta android Sqlite3 ORM 框架说明文档20160329
- Android 反编译 原来这么简单—绝对详解(有图有真相)
- 【Android】自定义View
- android 绘图
- Android DrawerLayout子组件属性设定问题
- Android简单的图片浏览器开发遇到的各种坑
- Android--锁定横屏、竖屏、去标题全屏
- Android组件之BroadcastReceiver
- android shape的使用