Android中的Handler、Looper、Message简要分析
1、Looper
Looper的构造方法:构造方法中创建了一个消息队列
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mRun = true; mThread = Thread.currentThread(); }
Looper主要包含prepare()和loop()两个方法的使用。
Android中主线程创建的时候在ActivityThread.java中的main方法中通过Looper.prepareMainLooper()创建了一个Looper,在最后调用了Looper.loop()开启了一个消息循环。代码如下:
public static void main(String[] args) { Looper.prepareMainLooper();//创建Looper if (sMainThreadHandler == null) { sMainThreadHandler = new Handler(); } ActivityThread thread = new ActivityThread(); thread.attach(false);//应用所有的逻辑都在这个方法中 Looper.loop();//开启一个消息循环,不断的读取MessageQueue中的Message。 }
然而,非主线程是默认没有Looper的,如果需要使用Handler就必须为线程创建Looper,需要我们通过Looper.prepare()手动创建。源码如下:
public static final void prepare() { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(true)); }
其中,sThreadLocal是一个ThreadLocal对象,ThreadLocal并不是线程,它的作用是可以在每个线程中存储数据,ThreadLocal可以在不同的线程之中互不干扰地存储并提供数据,通过ThreadLocal可以轻松获取每个线程的Looper。从源码中可以看到,在调用Looper.prepare()时判断了sThreadLocal是否为null,否则抛出异常。这也就说明了Looper.prepare()方法不能被调用两次,同时也保证了一个线程中只有一个Looper实例。
Looper.loop()源码:
/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the 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); } 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(); } }其中Looper.myLooper()源码如下;该方法直接返回了sThreadLocal存储的Looper实例 public static Looper myLooper() { return sThreadLocal.get(); }
loop()方法中,首先通过Looper.myLooper()获取sThreadLocal中的Looper实例,再通过该实例获取MessageQueue的实例,接着进入无限for循环,不断地查询MessageQueue中是否有新的消息,若有新消息则调用 msg.target.dispatchMessage(msg);把消息交给msg的target的dispatchMessage方法去处理,这里的msg.target就是handler对象。
2、Handler
Handler构造方法:在构造方法中,通过Looper.myLooper()获取当前线程的Looper实例,再通过该实例mLooper.mQueue()获取MessageQueue对象,这样就将Handler、Looper以及MessageQueue关联起来了。
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; }
使用Handler时必须首先创建Handler实例,由于构造方法中会获取当前线程中的Looper实例,所以创建Handler之前必须先创建Looper实例,即Looper.prepare()方法必须在创建Handler之前调用(主线程除外)。
创建完Handler对象之后我们会调用,sendMessage()方法,该方法最终调用了sendMessageAtTime()方法,源码如下:
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); }
在sendMessageAtTime方法中,最后返回enqueueMessage(queue, msg, uptimeMillis);看一下该方法的源码如下:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
在该方法中将this赋值给了msg.target,这与前面Looper.loop()方法中的msg.target就刚好对应上了,即就是在looper()中检测到有message之后,调用了msg.target.dispatchMessage(msg),实际上最终调用了Handler中的dispatchMessage方法,该方法源码如下:
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
可以看到,在该方法的最后调用了handleMessage(msg);这就是我们创建Handler对象之后重写的方法,在该方法中对相应的消息进行处理。
在dispatchMessage方法中还做了如下判断:
if (msg.callback != null) { handleCallback(msg);}
其中的msg.callback是另外一种Handler处理消息的形式。
我们有时候会利用handler.post();方法进行消息处理:
handler.post(new Runnable() { @Override public void run() { } });
然后在run方法中可以写更新UI的代码,实际上这个Runnable并没有创建新的线程,而是发送了一条消息:
public final boolean post(Runnable r){ return sendMessageDelayed(getPostMessage(r), 0);}
再看getPostMessage(r)方法:
private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m;}
在getPostMessage中,得到了一个Message对象,然后将我们创建的Runable对象作为callback属性,赋值给了这个message.
注:产生一个Message对象,可以new,也可以使用Message.obtain()方法;两者都可以,但是更建议使用obtain方法,因为Message内部维护了一个Message池用于Message的复用,避免使用new 重新分配内存。
而sendMessageDelayed方法最后还是调用了sendMessageAtTime这个方法,在sendMessageAtTime方法中判断了callback是否为null,不是null就执行handleCallback(msg);源码如下:
public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); }
更多相关文章
- Android中InstanceState()使用详解
- android.hardware.Camera翻译
- Unity 调用 Android(安卓)Native 方法(一) 获得Android系统音量
- Android(安卓)Activity 切屏处理
- 「抄底 Android(安卓)内存优化 3」 —— JVM 内存管理
- Android(安卓)MTP之服务端UsbService启动
- 从头学Android之多媒体--使用MediaPlayer播放音频
- 浅谈Java中Collections.sort对List排序的两种方法
- Python list sort方法的具体使用