本文主要是介绍Handler浅析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
前言
Android中多线程经常会涉及到传递消息的问题,尤其是更新UI,众所周知,子线程是无法更新UI,这时候就要借助Handler的消息传递机制。
一、构成
- Message: 消息,Handler处理的对象
- Looper:每个线程都有自己的looper,他负责将消息分发给对应的Handler
- MessageQueue: 初始化Looper对象的时候,会生成MessageQueue,它管理着Message
- Handler: 发送和处理消息
二、实例
我们先来看一个实例:
public class MainActivity extends AppCompatActivity {MyThread mThread;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mThread = new MyThread();mThread.start();mThread.mHandler.sendEmptyMessage(0x01);}class MyThread extends Thread {public Handler mHandler;@Overridepublic void run() {//初始化Looper,并生成MessageQueueLooper.prepare();mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {//处理发送过来的消息}};//不断的循环获取消息,并分发消息,没有消息时推出循环Looper.loop();}}
}
三、源码分析
1.Looper
1.1 Loop.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));}//这个是ActivityThread类中使用的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 static void prepare(boolean quitAllowed),sThreadLocal是ThreadLocal类型,它有set和get方法
ThreadLocal:线程本地存储空间,不同线程之间,不能互相访问
ThreadLocal.set(T value):
将数据存储到ThreadLocal
public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value);}
ThreadLocal.get():
从ThreadLocal中得到数据
public T get() {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {ThreadLocalMap.Entry e = map.getEntry(this);if (e != null)return (T)e.value;}return setInitialValue();}
1.2 Looper构造函数
private Looper(boolean quitAllowed) {mQueue = new MessageQueue(quitAllowed);mThread = Thread.currentThread();}
从代码可以看出,MessageQueue是在Looper生成的
1.3 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//如果没有消息,就会退出// No message indicates that the message queue is quitting.return;}// This must be in a local variable, in case a UI event sets the loggerfinal Printer logging = me.mLogging;if (logging != null) {logging.println(">>>>> Dispatching to " + msg.target + " " +msg.callback + ": " + msg.what);}final long traceTag = me.mTraceTag;if (traceTag != 0) {Trace.traceBegin(traceTag, msg.target.getTraceName(msg));}try {//分发消息msg.target.dispatchMessage(msg);} finally {if (traceTag != 0) {Trace.traceEnd(traceTag);}}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();}}
1.4 dispatchMessage
上面Looper.loop()中有一行这样的代码:
msg.target.dispatchMessage(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);}}
从这方法可以很清楚的看到,调用顺序:
- 当msg的回调方法部位null,则回调msg.callback.run();
- 当Handler的mCallback成员变量不为null时,则回调方法mCallback.handleMessage(msg);
- 调用Handler的回调方法handleMessage(),该方法默认为空,Handler子类需要覆写该方法。
一般情况下我们用的是第三种方法,也就是Handler.handleMessage()
2.消息
发送消息有很多方法,我例举两个:post和sendEmptyMessage,不过他们最终调用的是MessageQueue.enqueueMessage()。
post:
public final boolean post(Runnable r){return sendMessageDelayed(getPostMessage(r), 0);}
sendEmptyMessage:
public final boolean sendEmptyMessage(int what){return sendEmptyMessageDelayed(what, 0);}
enqueueMessage:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {msg.target = this;if (mAsynchronous) {msg.setAsynchronous(true);}return queue.enqueueMessage(msg, uptimeMillis);}
post方法里面有有一个Runnable,但是这并不是新开了一个线程,而是把消息加Handler所在线程的消息队列里
3.Handler
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());}}//必须先执行Looper.prepare(),不然mLooper会等于nullmLooper = 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;}
Looper为当前线程的Looper
有参:
public Handler(Looper looper, Callback callback, boolean async) {mLooper = looper;mQueue = looper.mQueue;mCallback = callback;mAsynchronous = async;}
可以指定Looper
4. MessageQueue
4.1 enqueueMessage
添加一条消息到消息队列,源码省略
4.2 removeMessages
移除制定条件的消息,源码省略
5. 消息池
类似于线程池,当消息池不为空时,直接从消息池中获取Message对象,而不是直接创建Message,提高效率。
消息池有两个重要的方法,分别为:obtain()和recycle()
5.1 obtain()
public static Message obtain() {synchronized (sPoolSync) {if (sPool != null) {Message m = sPool;sPool = m.next;m.next = null;m.flags = 0; // clear in-use flagsPoolSize--;return m;}}return new Message();}
当sPool不为空,直接从头部获取一个消息,如果sPool为空,则重新创建一个消息
5.2 recycle()
public void recycle() {if (isInUse()) {if (gCheckRecycle) {throw new IllegalStateException("This message cannot be recycled because it "+ "is still in use.");}return;}recycleUnchecked();}//将不再使用的消息加入消息池void recycleUnchecked() {// Mark the message as in use while it remains in the recycled object pool.// Clear out all other details.flags = FLAG_IN_USE;what = 0;arg1 = 0;arg2 = 0;obj = null;replyTo = null;sendingUid = -1;when = 0;target = null;callback = null;data = null;synchronized (sPoolSync) {if (sPoolSize < MAX_POOL_SIZE) {next = sPool;sPool = this;sPoolSize++;}}}
这篇关于Handler浅析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!