public class MainActivity extends ActionBarActivity {
private int mCount = 0;
private Handler mHandlerThr = null;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d(null, “>>>>>>>>>>>>>UI# mHandler–handleMessage–msg.what=”+msg.what);
//接收发送到UI线程的消息,然后向线程中的Handler发送msg 1。
mHandlerThr.sendEmptyMessage(1);
mCount++;
if (mCount >= 3) {
//由于mHandlerThr是在Child Thread创建,Looper手动死循环阻塞,所以需要quit。
mHandlerThr.getLooper().quit();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
}
@Override
protected void onStop() {
super.onStop();
//删除所有call与msg
mHandler.removeCallbacksAndMessages(null);
}
private void initData() {
Log.d(null, “>>>>>>>>>>>>>UI# begin start thread!!!”);
new Thread() {
@Override
public void run() {
super.run();
Looper.prepare();
mHandlerThr = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d(null, “>>>>>>>>>>>>>Child# mHandlerThr–handleMessage–msg.what=” + msg.what);
//接收发送到子线程的消息,然后向UI线程中的Handler发送msg 0。
mHandler.sendEmptyMessage(0);
}
};
Log.d(null, “>>>>>>>>>>>>>Child# begin start send msg!!!”);
//Activity中启动Thread,在Thread结束前发送msg 0到UI Thread。
mHandler.sendEmptyMessage(0);
Looper.loop(); //不能在这个后面添加代码,程序是无法运行到这行之后的。
}
}.start();
}
}
运行结果展示如下:
UI# begin start thread!!!
Child# begin start send msg!!!
UI# mHandler–handleMessage–msg.what=0
Child# mHandlerThr–handleMessage–msg.what=1
UI# mHandler–handleMessage–msg.what=0
Child# mHandlerThr–handleMessage–msg.what=1
UI# mHandler–handleMessage–msg.what=0
怎么样,这和你平时用的Handler一样吧,对于Handler异步处理的简单基础示例先说到这,接下来依据上面示例的写法分析原因与源代码原理。
3 分析Android 5.1.1(API 22)异步消息机制源码
3-1 看看Handler的实例化过程源码
3-1-1 Handler实例化源码
从哪着手分析呢?当然是实例化构造函数呀,所以我们先从Handler的默认构造函数开始分析,如下:
/**
-
Default constructor associates this handler with the {@link Looper} for the
-
current thread.
-
If this thread does not have a looper, this handler won’t be able to receive messages
-
so an exception is thrown.
*/
public Handler() {
this(null, false);
}
通过注释也能看到,默认构造函数没有参数,而且调运了带有两个参数的其他构造函数,第一个参数传递为null,第二个传递为false。
这个构造函数得到的Handler默认属于当前线程,而且如果当前线程如果没有Looper则通过这个默认构造实例化Handler时会抛出异常,至于是啥异常还有为啥咱们继续往下分析,this(null, false)的实现如下:
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;
}
可以看到,在第11行调用了mLooper = Looper.myLooper();
语句,然后获取了一个Looper对象mLooper ,如果mLooper实例为空,则会抛出一个运行时异常(Can’t create handler inside thread that has not called Looper.prepare()!)。
3-1-2 Looper实例化源码
好奇的你指定在想什么时候mLooper 对象才可能为空呢?很简单,跳进去看下吧,Looper类的静态方法myLooper如下:
/**
-
Return the Looper object associated with the current thread. Returns
-
null if the calling thread is not associated with a Looper.
*/
public static Looper myLooper() {
return sThreadLocal.get();
}
咦?这里好简单。单单就是从sThreadLocal对象中get了一个Looper对象返回。跟踪了一下sThreadLocal对象,发现他定义在Looper中,是一个static final类型的ThreadLocal<Looper>
对象(在Java中,一般情况下,通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的,各个线程中访问的是不同的对象。)。所以可以看出,如果sThreadLocal中有Looper存在就返回Looper,没有Looper存在自然就返回null了。
这时候你一定有疑惑,既然这里是通过sThreadLocal的get获得Looper,那指定有地方对sThreadLocal进行set操作吧?是的,我们在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的static方法prepare没有?这段代码首先判断sThreadLocal中是否已经存在Looper了,如果还没有则创建一个新的Looper设置进去。
那就看下Looper的实例化,如下:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
可以看见Looper构造函数无非就是创建了一个MessageQueue(它是一个消息队列,用于将所有收到的消息以队列的形式进行排列,并提供入队和出队的方法。)和货到当前Thread实例引用而已。通过这里可以发现,一个Looper只能对应了一个MessageQueue。
你可能会说上面的例子在子线程中明明先调运的是Looper.prepare();方法,这里怎么有参数了?那就继续看吧,如下:
public static void prepare() {
prepare(true);
}
可以看见,prepare()仅仅是对prepare(boolean quitAllowed) 的封装而已,默认传入了true,也就是将MessageQueue对象中的quitAllowed标记标记为true而已,至于MessageQueue后面会分析。
稀奇古怪的事情来了!如果你足够留意上面的例子,你会发现我们在UI Thread中创建Handler时没有调用Looper.prepare();,而在initData方法中创建的Child Thread中首先就调运了Looper.prepare();。你指定很奇怪吧?UI Thread为啥不需要呢?上面源码分析明明需要先保证mLooper对象不为null呀?
这是由于在UI线程(Activity等)启动的时候系统已经帮我们自动调用了Looper.prepare()方法。
那么在哪启动的呢?这个涉及Android系统架构问题比较多,后面文章会分析Activity的启动流程。这里你只要知道,以前一直都说Activity的人口是onCreate方法,其实android上一个应用的入口应该是ActivityThread类的main方法就行了。
所以为了解开UI Thread为何不需要创建Looper对象的原因,我们看下ActivityThread的main方法,如下:
public static void main(String[] args) {
SamplingProfilerIntegration.start();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
Security.addProvider(new AndroidKeyStoreProvider());
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, “ActivityThread”));
}
Looper.loop();
throw new RuntimeException(“Main thread loop unexpectedly exited”);
}
看见22行没?没说错吧?Looper.prepareMainLooper();
,我们跳到Looper看下prepareMainLooper方法,如下:
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException(“The main Looper has already been prepared.”);
}
sMainLooper = myLooper();
}
}
可以看到,UI线程中会始终存在一个Looper对象(sMainLooper 保存在Looper类中,UI线程通过getMainLooper方法获取UI线程的Looper对象),从而不需要再手动去调用Looper.prepare()方法了。如下Looper类提供的get方法:
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
看见没有,到这里整个Handler实例化与为何子线程在实例化Handler之前需要先调运Looper.prepare();语句的原理分析完毕。
3-1-3 Handler与Looper实例化总结
到此先初步总结下上面关于Handler实例化的一些关键信息,具体如下:
-
在主线程中可以直接创建Handler对象,而在子线程中需要先调用Looper.prepare()才能创建Handler对象,否则运行抛出”Can’t create handler inside thread that has not called Looper.prepare()”异常信息。
-
每个线程中最多只能有一个Looper对象,否则抛出异常。
-
可以通过Looper.myLooper()获取当前线程的Looper实例,通过Looper.getMainLooper()获取主(UI)线程的Looper实例。
-
一个Looper只能对应了一个MessageQueue。
-
一个线程中只有一个Looper实例,一个MessageQueue实例,可以有多个Handler实例。
Handler对象也创建好了,接下来就该用了吧,所以下面咱们从Handler的收发消息角度来分析分析源码。
3-2 继续看看Handler消息收发机制源码
3-2-1 通过Handler发消息到消息队列
还记得上面的例子吗?我们在Child Thread的最后通过主线程的Handler对象调运sendEmptyMessage方法发送出去了一条消息。
当然,其实Handler类提供了许发送消息的方法,我们这个例子只是用了最简单的发送一个empty消息而已,有时候我们会先定义一个Message,然后通过Handler提供的其他方法进行发送。通过分析Handler源码发现Handler中提供的很多个发送消息方法中除了sendMessageAtFrontOfQueue()方法之外,其它的发送消息方法最终都调用了sendMessageAtTime()方法。所以,咱们先来看下这个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);
}
再看下Handler中和其他发送方法不同的sendMessageAtFrontOfQueue方法,如下:
public final boolean sendMessageAtFrontOfQueue(Message msg) {
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, 0);
}
对比上面两个方法可以发现,表面上说Handler的sendMessageAtFrontOfQueue方法和其他发送方法不同,其实实质是相同的,仅仅是sendMessageAtFrontOfQueue方法是sendMessageAtTime方法的一个特例而已(sendMessageAtTime最后一个参数传递0就变为了sendMessageAtFrontOfQueue方法)。所以咱们现在继续分析sendMessageAtTime方法,如下分析:
sendMessageAtTime(Message msg, long uptimeMillis)方法有两个参数;msg是我们发送的Message对象,uptimeMillis表示发送消息的时间,uptimeMillis的值等于从系统开机到当前时间的毫秒数再加上延迟时间。
在该方法的第二行可以看到queue = mQueue,而mQueue是在Handler实例化时构造函数中实例化的。在Handler的构造函数中可以看见mQueue = mLooper.mQueue;,而Looper的mQueue对象上面分析过了,是在Looper的构造函数中创建的一个MessageQueue。
接着第9行可以看到,上面说的两个参数和刚刚得到的queue对象都传递到了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);
}
这个方法首先将我们要发送的消息Message的target属性设置为当前Handler对象(进行关联);接着将msg与uptimeMillis这两个参数都传递到MessageQueue(消息队列)的enqueueMessage()方法中,所以接下来我们就继续分析MessageQueue类的enqueueMessage方法,如下:
boolean enqueueMessage(Message msg, long when) {
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(“MessageQueue”, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
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;
}
通过这个方法名可以看出来通过Handler发送消息实质就是把消息Message添加到MessageQueue消息队列中的过程而已。
通过上面遍历等next操作可以看出来,MessageQueue消息队列对于消息排队是通过类似c语言的链表来存储这些有序的消息的。其中的mMessages对象表示当前待处理的消息;然后18到49行可以看出,消息插入队列的实质就是将所有的消息按时间(uptimeMillis参数,上面有介绍)进行排序。所以还记得上面sendMessageAtFrontOfQueue方法吗?它的实质就是把消息添加到MessageQueue消息队列的头部(uptimeMillis为0,上面有分析)。
到此Handler的发送消息及发送的消息如何存入到MessageQueue消息队列的逻辑分析完成。
那么问题来了!既然消息都存入到了MessageQueue消息队列,当然要取出来消息吧,不然存半天有啥意义呢?我们知道MessageQueue的对象在Looper构造函数中实例化的;一个Looper对应一个MessageQueue,所以说Handler发送消息是通过Handler构造函数里拿到的Looper对象的成员MessageQueue的enqueueMessage方法将消息插入队列,也就是说出队列一定也与Handler和Looper和MessageQueue有关系。
还记不记得上面实例部分中Child Thread最后调运的Looper.loop();方法呢?这个方法其实就是取出MessageQueue消息队列里的消息方法。具体在下面分析。
3-2-2 通过Handler接收发送的消息
先来看下上面例子中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();
}
}
可以看到,第6行首先得到了当前线程的Looper对象me,接着第10行通过当前Looper对象得到与Looper对象一一对应的MessageQueue消息队列(也就类似上面发送消息部分,Handler通过myLoop方法得到Looper对象,然后获取Looper的MessageQueue消息队列对象)。17行进入一个死循环,18行不断地调用MessageQueue的next()方法,进入MessageQueue这个类查看next方法,如下:
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;😉 {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (false) Log.v(“MessageQueue”, "Returning message: " + msg);
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
最后
赠送大家一套完整的Android学习资料吧。
以前一直是自己在网上东平西凑的找,找到的东西也是零零散散,很多时候都是看着看着就没了,时间浪费了,问题却还没得到解决,很让人抓狂。
后面我就自己整理了一套资料,还别说,真香!
资料有条理,有系统,还很全面,我不方便直接放出来,大家可以先看看有没有用得到的地方吧。
附上白嫖地址:《Android架构视频+BATJ面试专题PDF+学习笔记》
= true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
最后
赠送大家一套完整的Android学习资料吧。
以前一直是自己在网上东平西凑的找,找到的东西也是零零散散,很多时候都是看着看着就没了,时间浪费了,问题却还没得到解决,很让人抓狂。
后面我就自己整理了一套资料,还别说,真香!
资料有条理,有系统,还很全面,我不方便直接放出来,大家可以先看看有没有用得到的地方吧。
附上白嫖地址:《Android架构视频+BATJ面试专题PDF+学习笔记》
[外链图片转存中…(img-qeYZerWE-1645099552628)]
[外链图片转存中…(img-TeI9nCco-1645099552629)]
[外链图片转存中…(img-pfcneLxo-1645099552630)]
[外链图片转存中…(img-fjT99uWR-1645099552630)]
[外链图片转存中…(img-d5vBY2GS-1645099552631)]