歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Android入門之子線程中Toast

和同學在討論一個小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