android Handler & HandlerThread
16lz
2021-01-26
Android应用中的消息循环由Looper和Handler配合完成,Looper类用于封装消息循环,类中有个MessageQueue消息队列;Handler类封装了消息投递和消息处理等功能。在Looper.java中有一个loop()方法,有个死循环用来处理消息,代码如下:
/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */ public static void loop() { Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } 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(); while (true) { Message msg = queue.next(); // might block // if (msg != null) { if (msg.target == null) { // No target is a magic identifier for the quit message. return; } long wallStart = 0; long threadStart = 0; // 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); wallStart = SystemClock.currentTimeMicro(); threadStart = SystemClock.currentThreadTimeMicro(); } msg.target.dispatchMessage(msg); if (logging != null) { long wallTime = SystemClock.currentTimeMicro() - wallStart; long threadTime = SystemClock.currentThreadTimeMicro() - threadStart; logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); if (logging instanceof Profiler) { ((Profiler) logging).profile(msg, wallStart, wallTime, threadStart, threadTime); } } // 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.recycle(); } } }
通过查看MessageQueue类可以看出,消息队列是以链表形式保存的(在android.os.Message类中有个成员变量为Message next)。在loop()方法的死循环中通过queue.next()读取MessageQueue中的Message,由此也可以看出MessageQueue的next()及enqueueMessage()方法需要同步。 系统默认情况下只有主线程(即UI线程)绑定Looper对象,因此在主线程中可以直接创建Handler的实例(见ActivityThread类),但是在子线程中就不能直接new出Handler的实例了,因为子线程默认并没有Looper对象,此时会抛出RuntimeException异常(在Handler类构造函数中会抛出异常):if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } 如果需要在子线程中使用Handler类,首先需要创建Looper类实例,这时可以通过Looper.prepare()和Looper.loop()函数来实现的。阅读Framework层源码发现,Android为我们提供了一个HandlerThread类,该类继承Thread类,并使用上面两个函数创建Looper对象。源码如下:/** * Handy class for starting a new thread that has a looper. The looper can then be * used to create handler classes. Note that start() must still be called. */public class HandlerThread extends Thread { int mPriority; int mTid = -1; Looper mLooper; public HandlerThread(String name) { super(name); mPriority = Process.THREAD_PRIORITY_DEFAULT; } /** * Constructs a HandlerThread. * @param name * @param priority The priority to run the thread at. The value supplied must be from * {@link android.os.Process} and not from java.lang.Thread. */ public HandlerThread(String name, int priority) { super(name); mPriority = priority; } /** * Call back method that can be explicitly over ridden if needed to execute some * setup before Looper loops. */ protected void onLooperPrepared() { } public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; } /** * This method returns the Looper associated with this thread. If this thread not been started * or for any reason is isAlive() returns false, this method will return null. If this thread * has been started, this method will block until the looper has been initialized. * @return The looper. */ public Looper getLooper() { if (!isAlive()) { return null; } // If the thread has been started, wait until the looper has been created. synchronized (this) { while (isAlive() && mLooper == null) { try { wait();//Looper对象未创建好,等待 } catch (InterruptedException e) { } } } return mLooper; } /** * Ask the currently running looper to quit. If the thread has not * been started or has finished (that is if {@link #getLooper} returns * null), then false is returned. Otherwise the looper is asked to * quit and true is returned. */ public boolean quit() { Looper looper = getLooper(); if (looper != null) { looper.quit(); return true; } return false; } /** * Returns the identifier of this thread. See Process.myTid(). */ public int getThreadId() { return mTid; }}在run()方法中通过Looper.prepare()获取Looper对象,而且通过线程的wait()和notifyAll()解决了getLooper()获取为空的问题。不管是主线程(一般是我们的UI线程)还是子线程,只要有Looper的线程,别的线程就可以向这个线程的消息队列中发送消息和计划任务,然后做相应的处理。
更多相关文章
- Android(安卓)xmpp开发 asmack获取离线在线添加好友消息 及 好友
- android欢迎界面的编程实现[手相评分-软件实例]
- 充电clientandroid电池(五):电池 充电IC(PM2301)驱动分析篇
- Android(安卓)消息处理机制: Handler 中 sendMessage()方法的几
- android 网络连接保活
- Android中的RxJava详解
- android部分介绍
- Android(安卓)Studio使用JDBC连接MySQL出现java.lang.Unsupporte
- Android简易聊天室软件(HTTP实现)