歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Android入門之子線程中Toast

Android入門之子線程中Toast

日期:2017/3/1 11:08:14   编辑:Linux編程
和同學在討論一個小Demo,無意間,在子線程中Toast了一把,竟然報錯了

因為Toast在service和activity中都可以執行。所以開始就認為和ui線程沒有有太大的關系,而現在子線程Toast竟然報錯!無奈之下,花了半天的時間看了一下Handler,Looper,Toast的源碼,終於搞定了。(這個效率..本人愚鈍啊)----->的確和UI線程沒有關系

記錄下來,希望對遇上同樣問題的同學有所幫助。下面正題

1、錯誤的關鍵位置在於Toast初始化的時候,這句

public class Toast {final Handler mHandler = new Handler();….}

2、其實在別的地方也看到過,普通線程不能直接new一個Handler

原因:

public Handler(){

…..

mLooper = Looper.myLooper();

if (mLooper == null) {

throw new RuntimeException(

"Can't create handler inside thread that has not called Looper.prepare()");

}

…..

}

3、而Looper中

public static final Looper myLooper() {

//這個方法是從當前線程的ThreadLocal中拿出設置的looper

return (Looper)sThreadLocal.get();

}

而事實上子線程只是一個普通的線程,其ThreadLoacl中沒有設置過Looper,所以會拋出異常

4、解決方法

public void onClick(View v) {

new Thread(){

public void run() {

Log.i("log", "run");

Looper.prepare();

Toast.makeText(ActivityTestActivity.this, "toast", 1).show();

Looper.loop();// 進入loop中的循環,查看消息隊列

};

}.start();

}

Looper.prepare()方法參考

//Looper

public static final void prepare() {

if (sThreadLocal.get() != null) {

throw new RuntimeException("Only one Looper may be created per thread");

}

sThreadLocal.set(new Looper());

}

下邊的可以忽略了

5、至於內部的通訊機制就不知道了

只知道show()方法裡邊調用了InotificationManager. enqueueToast(pkgName, tn, mDuration)

其中tn是繼承了ItransientNotification.Stub的遠程通信接口,而handler也是在這個TN類中調用!猜想內部機制也是NotificationService的進程間通信機制!

下邊代碼,算是管中窺豹吧

-----源碼不是這個樣子的,被我概括

ItransientNotification中有個show方法

public void show() {

if (localLOGV) Log.v(TAG, "SHOW: " +this);

Handler.post(mShow);

}

其中mshow是

final Runnable mShow = new Runnable() {

public void run() {

…..

WindowManagerImpl mWM = WindowManagerImpl.getDefault();

mWM.addView(mView, mParams);

…..

}

};

Copyright © Linux教程網 All Rights Reserved