看到有這樣的代碼塊,好奇這種用法。
Thread lShowToastThread = new Thread() {
@Override
public void run() {
Looper.prepare();
String toast = " program has crashed";
Toast.makeText(WelcomeApplication.this, toast, Toast.LENGTH_LONG).show();
Looper.loop();
}
};
lShowToastThread.start();
如果在Thread里不加Looper,則會(huì)報(bào)錯(cuò):
01-10 19:25:45.091 4769-4811/? E/AndroidRuntime: FATAL EXCEPTION: Thread-213
Process:, PID: 4769
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:200)
at android.os.Handler.<init>(Handler.java:114)
at android.widget.Toast$TN.<init>(Toast.java:345)
at android.widget.Toast.<init>(Toast.java:101)
at android.widget.Toast.makeText(Toast.java:259)
這主要是因?yàn)椋琀andler是Android的東西,必須要有Looper(消息循環(huán)),而Thread僅僅是線程概念,并不要求有消息循環(huán)。所以,在android里使用Thread要小心,不要在調(diào)用鏈過程中,創(chuàng)建Handler!
為了能夠順利執(zhí)行,估計(jì)后面在代碼塊中添加了Looper.prepare和Looper.loop。但這是正確的么?Looper.loop會(huì)導(dǎo)致消息循環(huán),線程無法退出,如果是應(yīng)用期間一直存在沒關(guān)系,那么問題也不算大。如果是可重入的子模塊,則Thread會(huì)不斷創(chuàng)建,造成泄漏。
總結(jié)一下:
Thread里面不能new Handler,因?yàn)槿笔ooper。使用Thread時(shí)避免在調(diào)用鏈中創(chuàng)建Handler(通常是在對象屬性初始化Handler,然后不小心在Thread中new對象)。
在Android里面,Thread不能被多次start,否則會(huì)報(bào)錯(cuò)(不知道java是不是如此)。如果要持有一個(gè)線程多次開啟,使用Thread是無法實(shí)現(xiàn)的,但可以使用HandlerThread代替。
Looper.loop是阻塞的。像上面Thread里面的Looper用法,線程總是一直存在沒能退出。
for (;;) {
Message msg = queue.next(); // might block(可能阻塞)
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
......
}
- Android中盡量避免使用Thread,就是盡力少埋坑。