Android下Handler分析
介绍
Handler是Android应用内通讯组件,可实现线程间的通讯如子线程获取网络数据须在主线程更新UI使用,Handler通讯由
现在虽然不流行这样的方式但是我们还是需要了解其内部的原理
组件介绍
- Handler(消息发送接收)
- Message(消息体)
- MessageQueue(消息队列)
- Looper(轮询器)
Handler
private Handler handler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(@NonNull Message msg) { switch (msg.what) { //what可以理解为消息类型 case 1: Object obj = msg.obj; Log.e("MainActivity", "handleMessage: " + obj); break; default: Log.e("MainActivity", "handleMessage: default message"); break; } } };
这里声明了一个持有主线程Looper的Handler对象我们可以在handlerMessage函数中对接收到消息进行相应的处理
Message message = handler.obtainMessage(); message.what = 1; message.obj = "this is Handler Message body"; handler.sendMessage(message);
这里我们发送了一条消息,将会被handlerMessage中接收并且处理,值得注意的是获得Message对象我们应该使用obtainMessage()函数获取这样可以节省内存,为什么可以节省内存了我们继续往下看
我们来看一下obtainMessage的源码就知道啦
@NonNull public final Message obtainMessage() { return Message.obtain(this); } public static Message obtain(Handler h) { Message m = obtain(); m.target = h; return m; } public static Message obtain() { synchronized (sPoolSync) { //sPool 不等于null的话就会复用sPool if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; m.flags = 0; // clear in-use flag sPoolSize--; return m; } } //直接新建了一个Message对象 return new Message(); }
在上述代码片段中我们可以看到obtainMessage最终执行了obtain函数,如果sPool不等于null的情况下就会复用sPool这个Message对象,所以这就是为什么推荐使用obtainMessage获取Message对象的原因了
Message
Message就是消息内容啦,可以理解为生活中你在某宝买了东西卖家给你寄过来的包裹
MessageQueue
MessageQueue就是消息池啦,我们调用sendMessage(),sendEmptyMessageDelayed(),sendEmptyMessageAtTime()这些函数其实就是把Message对象存放到Handler对应的MessageQueue中
public boolean sendMessageAtTime(@NonNull 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); }
这里其实就是把消息放进了消息池,那么就有小伙伴在线这个MessageQueue是哪来的呢?
那我们看下Looper这个东东就知道啦
Looper
Looper是个什么东东呢? 首先我们看下官方的解释
Class used to run a message loop for a thread. Threads by default do
not have a message loop associated with them; to create one, call
{@link #prepare} in the thread that is to run the loop, and then
{@link #loop} to have it process messages until the loop is stopped.
大概的意思是这是一个运行线程消息循环的类,默认和创建这个线程进行关联
final MessageQueue mQueue;
看下源码发现mQueue是它的一个成员变量并且用final修饰了,那么我们直接去构造函数找mQueue的初始化了
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
这里可以看到是直接new了一个MessageQueue对象仔细一看构造居然是private修饰的那这个对象是在哪里创建的呢
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)); }
这里就是创建Looper对象的地方啦,那为什么我们之前使用handler发送消息的时候没有调用prepare()函数也没报异常呢,这是因为我们刚才创建的Handler使用的是MainThread的Looper所以我们不需要自己调用一遍prepare()了.
哈哈哈,讲了半天没讲到重点消息发送我知道到MessageQueue那消息是怎么让handlerMessage()处理的呢?
public static void loop() { ... 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 final Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } // Make sure the observer won't change while processing a transaction. final Observer observer = sObserver; final long traceTag = me.mTraceTag; long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs; long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs; if (thresholdOverride > 0) { slowDispatchThresholdMs = thresholdOverride; slowDeliveryThresholdMs = thresholdOverride; } final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0); final boolean logSlowDispatch = (slowDispatchThresholdMs > 0); final boolean needStartTime = logSlowDelivery || logSlowDispatch; final boolean needEndTime = logSlowDispatch; if (traceTag != 0 && Trace.isTagEnabled(traceTag)) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0; final long dispatchEnd; Object token = null; if (observer != null) { token = observer.messageDispatchStarting(); } long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid); try { msg.target.dispatchMessage(msg); if (observer != null) { observer.messageDispatched(token, msg); } dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0; } catch (Exception exception) { if (observer != null) { observer.dispatchingThrewException(token, msg, exception); } throw exception; } finally { ThreadLocalWorkSource.restore(origWorkSource); if (traceTag != 0) { Trace.traceEnd(traceTag); } } if (logSlowDelivery) { if (slowDeliveryDetected) { if ((dispatchStart - msg.when) <= 10) { Slog.w(TAG, "Drained"); slowDeliveryDetected = false; } } else { if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery", msg)) { // Once we write a slow delivery log, suppress until the queue drains. slowDeliveryDetected = true; } } } if (logSlowDispatch) { showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", 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(); } }
这里有个for死循环一直从消息池中取消息
Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; }
在往下看我们有这么一行代码msg.target.dispatchMessage(msg)
其实这个target就是发送消息的handler,所以我们再看下handler的dispatchMessage()函数拿到这个msg都干了些啥
public void dispatchMessage(@NonNull Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
这里最终就把消息调到了handleMessage()就是我们处理消息这里
我们上面说到MainThread不需要我们去调用Looper.loop()来启动这个轮询,但是子线程中的Handler我们就需要调用下面两个函数来使这个Handler正常运作起来
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对象,需要注意的是这个函数只能调用一遍否则将会抛出异常 “Only one Looper may be created per thread”
接下来就是调用Looper.loop()了,至此子线程中的Handler也能正常使用了.
更多相关文章
- Binder 学习笔记
- setVolumeControlStream(int streamType)
- Android的MediaPlayer架构介绍 补充
- Android中bindService()启动Service的过程分析
- 一只不务正业的程序猿玩出个Processing交互库
- LogUtils:一个强大的Android日志管理器,支持对象、List、Map、数组
- Android进程-zygote进程
- AsyncTask的坑,Handler,Looper与MessageQueue
- 最详细的Android(安卓)Bitmap回收机制(从2.3到7.0,8.0)