為什麼在主執行緒的Looper.looper死迴圈不會卡死
阿新 • • 發佈:2019-01-30
public static void main(String[] args) {
.... //建立Looper和MessageQueue物件,用於處理主執行緒的訊息
Looper.prepareMainLooper();
//建立ActivityThread物件
//建立Binder通道 (建立新執行緒)
thread.attach(false); Looper.loop(); //訊息迴圈執行
throw new RuntimeException("Main thread loop unexpectedly exited");
}
我們看looper.loop()的原始碼
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
Looper me = myLooper();//獲取當前looper
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}//如果為空,則拋異常
MessageQueue queue = me.mQueue;//把當前looper的queue賦值給區域性變數queue
// 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();//確保當前執行緒屬於當前程序,並且記錄真實的token。
final long ident = Binder.clearCallingIdentity();
while (true) {
Message msg = queue.next(); // might block有可能會阻塞
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.退出訊息的標示就是target為空
return;
}
long wallStart = 0;
long threadStart = 0;
// This must be in a local variable, in case a UI event sets the logger 一個區域性變數,為ui事件設定log記錄。
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
wallStart = SystemClock.currentTimeMicro();
threadStart = SystemClock.currentThreadTimeMicro();
}
//handler處理訊息
msg.target.dispatchMessage(msg);
if (logging != null) {
long wallTime = SystemClock.currentTimeMicro() - wallStart;
long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
if (logging instanceof Profiler) {
((Profiler) logging).profile(msg, wallStart, wallTime,
threadStart, threadTime);
}
}
// 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);
}
//處理完成後,呼叫Message.recycle()將其放入Message Pool中。
msg.recycle();
}
}
}
那麼知乎上一個大神這麼說 隔開隔開
對於執行緒既然是一段可執行的程式碼,當可執行程式碼執行完成後,執行緒生命週期便該終止了,執行緒退出。而對於主執行緒,我們是絕不希望會被執行一段時間,自己就退出,那麼如何保證能一直存活呢?簡單做法就是可執行程式碼是能一直執行下去的,死迴圈便能保證不會被退出,例如,binder執行緒也是採用死迴圈的方法,通過迴圈方式不同與Binder驅動進行讀寫操作,當然並非簡單地死迴圈,無訊息時會休眠。但這裡可能又引發了另一個問題,既然是死迴圈又如何去處理其他事務呢?通過建立新執行緒的方式。
真正會卡死主執行緒的操作是在回撥方法onCreate/onStart/onResume等操作時間過長,會導致掉幀,甚至發生ANR,looper.loop本身不會導致應用卡死。
隔開隔開
這是一個大神說的 乍看起來好像有點不懂
那麼我來說說我的理解
Looper.loop()中的for迴圈會讓當前執行緒阻塞,不是卡死,這個和作業系統有關。如果你在主執行緒操作,如activity生命週期onCreate、主執行緒的handler,實際上是都是通過handler發訊息的,訊息會在剛才的for迴圈中處理,這個訊息會喚醒執行緒,如果你在onCreate(),onResume()裡面處理耗時操作,那麼下一次的比如使用者的點選事件不能處理了,那就會卡死了