Android消息机制简述(Java层)
16lz
2021-01-26
1、简述
- android中的消息驱动机制,主要是用于线程之间的数据交互;
- 消息机制涉及对象:
Handler : 消息处理者,负责消息的create、post、dispatch、remove等操作;
Message :消息,表示一个具体的任务
MessageQueue:消息队列,保存各种消息
Looper :负责消息循环
- LooperThread : 任何一个普通的线程通过简单的操作可以变成一个Looper线程,Looper线程和普通线程之间最大的区别在于,普通线程在任务结束后就退出了,但是Looper线程不会退出,它会进入一个循环等待下一个任务的到来。LooperThread的好处是避免的Thread的多次创建,从而减少资源消耗。
class LooperThread extends Thread{ @Override public void run() { // 为该线程创建Looper对象 Looper.prepare(); // 消息处理者 Handler mHandler = new Handler(){ public void handlerMessage(){ // 对消息进行处理 } }; // 循环 Looper.loop(); } }
- HandlerThread :这个类基本就是一个LooperThread,可以直接使用它的Looper来构造出一个Handler。
HandlerThread mHandlerThread = new HandlerThread();// 启动Looper线程mHandlerThread.start();// 利用HandlerThread构建一个Handler,这样操作之后,后续的任务都执行在了HandlerThread里面Handler mHandler = new Handler(mHandlerThread.getLooper());
2、Looper
2.1 为每个线程创建唯一的Looper对象:Looper.prepare()
// sThreadLocal和sMainLooper都是static,也就是说是和对象无关的// 使用了ThreadLocal来保证一个线程只会存在一个Looper static final ThreadLocal sThreadLocal = new ThreadLocal(); // sMainLooper在ActivityThread.main()中进行初始化,ActivityThread表示一个应用进程的主线程 private static Looper sMainLooper; // guarded by Looper.class public static void prepare() { prepare(true); } // 创建一个Looper并保存在ThreadLocal中,一个线程只能拥有唯一的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)); } // 这个是每个应用进程对应的主线程拥有的Looper对象,其初始化在ActivityThread.main()中 // 这也就是为什么我们可以在UI线程中直接new Handler()的原因 public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } } private Looper(boolean quitAllowed) { // 创建一个消息队列 mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
2.2 消息循环: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); } // 将Message交给Handler来进行处理 msg.target.dispatchMessage(msg); 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(); } }
3、Handler
3.1 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(); // 一定要先有Looper才行 // 所以在子线程当中要创建Handler对象时必须先要创建Looper对象 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; }
3.2 Message的创建 从消息池中取一个,详细略过
3.3 Message发送过程
Message发送的方式在Handler中有两种方式,一种是通过post一个Runnable,另外一种是通过sendMessage方式,其实这两种本质上都是一样的:
///////////////////////// post(Runnable) public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); } private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r;// Runnable作为Message的CallBack return m; } ///////////////////////// sendMessage(Message) public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); } //////////////////////// 最终调用的都是sendMessageAtTime() 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) { // Looper中的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为当前对象,也就是Handler msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
MessageQueue.enqueueMessage():将消息加入到队列的合适位置
boolean enqueueMessage(Message msg, long when) { // 每个Message必须指定一个Handler 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; } // 标记当前Message正在被使用 msg.markInUse(); msg.when = when; // mMessages用来记录队列中的头部消息 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; }
Message加入到MessageQueue后,通过调用nativeWake()转到Native层,Native层最终转到Looper.loop(),然后调用Message的target也就是Handler来对其进行分发处理。
Message的分发:Handler.dispatchMessage()
public void dispatchMessage(Message msg) { if (msg.callback != null) {// post方式 handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } private static void handleCallback(Message message) { // 从这里看到,post方式传入的runnable只不过是一个回掉 // 这个回掉和Handler运行在同一个线程(LooperThread)//这里也就解释了为什么想将子线程切换到UI线程的时候只要调用//handler.post(runnable)就可以,前提是这个handler是UI所在的handler。 message.callback.run(); }
4 问题
对于Handler的使用,如果某个任务处理的时间特别的长,就要采取措施来避免因为Handler长时间没有得到释放而引起的内存泄漏问题:Handler被Message持有不能及时释放,因为java中内部对象默认会持有外部对象的一个引用,因而会导致诸如Activity或是Fragment不能够得到及时的释放;解决方法是要么定义Handler为static,然后持有Activity的一个弱引用,要么及时的调用Handler的removeMessage()来移除不需要的任务。
更多相关文章
- SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
- ThreadPoolExecutor 快速实际应用
- Android(安卓)5种倒计时的实现
- Android_UI主线程与子线程
- AIDL 消息通信
- Service通过Broadcast更新UI
- Android(安卓)ApiDemos示例解析(45):App->Text-To-Speech
- android 如何中断一个子线程
- 查看ANR日志