在ActivityThread.java里有一个main()函数,它是Android每一个应用最早执行的函数。
public static void main(String[] args) {
.....
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"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
它先prepare的,看这个prepare干了些什么事情?
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
prepare是初始化,初始化了一个Looper。
然后又接着调用的Looper.loop()函数,这个loop()函数其实就是执行了那个for循环,它不断的调用next()函数,通过调用next()函数去轮询我们的MessageQueue。
如果不调用prepare(),Looper没有被初始化;如果不调用loop(),Looper的机制滚动不起来。所以,所有的执行必须先prepare(),然后再loop()。
回到问题,为什么主线程不需要做这些操作呢?
因为主线程一启动的时候,在main()函数中,由系统已经帮我们完成了,我们主线程中的所有代码,全都运行在这两个函数(prepare() 和 loop())之间。
在上一题 为什么主线程可以new Handler?中其实已经解答,所有的线程都必须要prepare()和loop(),如果子线程中想要进行Handler操作,就必须在子线程中执行prepare() 和 loop()。
我们先来创建一个子线程,然后子线程中创建了一个Looper,并且发送了一个消息,消息处理完了,看一下会发生什么样的事情。
Handler threadHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new Runnable() {
@Override
public void run() {
if (threadHandler == null){
Looper.prepare();
threadHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.e("seas","handle Message");
}
};
Log.e("seas","Looper loop() UP");
Looper.loop();
Log.e("seas","Looper loop() DOWN");
}
}
}).start();
}
public void click(View view){
Log.e("seas","click");
threadHandler.sendMessage(threadHandler.obtainMessage());
}
我运行之后,再点击执行click方法,就出现了如下的log。
如果这个子线程结束,那么他应该是有调用到 Log.e("seas","Looper loop() DOWN"); 这个语句才对,但是它并没有,这就意味着这个Looper一直处于一个阻塞状态。
也就是说它一直卡在了这个地方:
for (;;) {
Message msg = queue.next(); // might block
.....
}
所以它就一直在等待,这个子线程也已经干不了其他的事情了,其实也被卡死了。
子线程中维护的Looper,消息队列无消息的时候的处理方案是什么?有什么用?
在Handler机制里面有一个Looper,在Looper机制里面有一个函数,叫做quitSafely()和quit()函数,这两个函数是调用的MessageQueue的quit()。
/**
* Quits the looper.
*
* Causes the {@link #loop} method to terminate without processing any
* more messages in the message queue.
*
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
*
* Using this method may be unsafe because some messages may not be delivered
* before the looper terminates. Consider using {@link #quitSafely} instead to ensure
* that all pending work is completed in an orderly manner.
*
*
* @see #quitSafely
*/
public void quit() {
mQueue.quit(false);
}
/**
* Quits the looper safely.
*
* Causes the {@link #loop} method to terminate as soon as all remaining messages
* in the message queue that are already due to be delivered have been handled.
* However pending delayed messages with due times in the future will not be
* delivered before the loop terminates.
*
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
*
*/
public void quitSafely() {
mQueue.quit(true);
}
再进入到MessageQueue的quit()函数。
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
它会remove消息,把消息队列中的全部消息给干掉。
把消息全部干掉,也就释放了内存。
private void removeAllFutureMessagesLocked() {
final long now = SystemClock.uptimeMillis();
Message p = mMessages;
if (p != null) {
if (p.when > now) {
removeAllMessagesLocked();
} else {
Message n;
for (;;) {
n = p.next;
if (n == null) {
return;
}
if (n.when > now) {
break;
}
p = n;
}
p.next = null;
do {
p = n;
n = p.next;
p.recycleUnchecked();
} while (n != null);
}
}
}
而在quit()函数的最后一行,有一个nativeWake()函数。
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
这个函数的调用,就会叫醒等待的地方,醒来之后,就接着往下执行。
//native的方法,在没有消息的时候回阻塞管道读取端,只有nativePollOnce返回之后才能往下执行
//阻塞操作,等待nextPollTimeoutMillis时长
nativePollOnce(ptr, nextPollTimeoutMillis);
往下执行后,发现 Message msg = mMessages; 是空的,然后就执行了这个,就接着往下走。
if (msg != null) {
......
} else {
// No more messages.
//没有消息,nextPollTimeoutMillis复位
nextPollTimeoutMillis = -1;
}
然后又调用了这个方法,并且return了null。
// Process the quit message now that all pending messages have been handled.
//如果消息队列正在处于退出状态返回null,调用dispose();释放该消息队列
if (mQuitting) {
dispose();
return null;
}
所以说,这个时候Looper就结束了(跳出了死循环),则达成了第二个作用:释放线程。
如果我在刚才的例子上加入退出操作。
public void stopclick(View view){
Log.e("seas","click");
threadHandler.getLooper().quit();
}
打印如下:
这个线程就真正的执行了,否则这个线程就一直在等待。
如果在子线程中创建了一个Handler,那么就必须做三个操作:
1. prepare();
2. loop();
3. quit();
是不能的。它会抛出一个异常,让程序挂掉。
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
......
}