【Android】永不消失的Toast

自己親測兩種解決方法:

1、將Toast換成dialog,呵呵,這個方法比較土鱉,但是很好用。而且不用費力去理原有代碼的流程。

原因:Toast在傳入context的時候,不管你傳的是activity還是application,他都是調用的mContext.getPackageName();這也是爲什麼只有卸載應用才能將Toast消除。但是dialog就不一樣,他是依賴activity本身的,如果activity退出了,activity附屬的dialog也就自然被回收了。補充<span style="font-family: Arial; font-size: 16px; line-height: 24px; background-color: rgb(237, 237, 237);">,當由於</span><span style="font-family: Arial; font-size: 16px; line-height: 24px; background-color: rgb(237, 237, 237);">HandlerThread沒quiet,而activity退出的時候,Toast無法調用相應的hide方法,導致Toast不消失。</span>

public void show() {
        if (mNextView == null) {
            throw new RuntimeException("setView must have been called");
        }

        INotificationManager service = getService();
        String pkg = mContext.getPackageName();
        TN tn = mTN;
        tn.mNextView = mNextView;

        try {
            service.enqueueToast(pkg, tn, mDuration);
        } catch (RemoteException e) {
            // Empty
        }
    }



2、方法二就是常規的處理方式,在onpause方法裏也加個HandlerThread.quiet.

Toast是Android一個比較省心的控件,因爲Toast不提供任何交互界面,看一眼就消失,而且只需要Context就可以創建。

然而無須交互的優勢這也帶來一個問題,如果Toast顯示後無法消失,那麼將真的是無法消失了。除非強制退出應用或者重啓手機。

 

一個簡單的示例程序,就可以創造出一個無法消失的Toast。以下爲Activity代碼:

public class ToastTestActivity extends Activity {
	/** HandlerThread object */
    HandlerThread mThread = null;
    
    /** Handler object */
    ToastHandler mHandler = null;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mThread = new HandlerThread("ToastThread");
        mThread.start();
        mHandler = new ToastHandler(mThread.getLooper());
    }

    /**
     * Called when Button got clicked
     * @param v View that got clicked
     */
    public void myClick(View v) {
        mHandler.sendEmptyMessageDelayed(1, 2000);
    }

    private class ToastHandler extends Handler {
        public ToastHandler(Looper looper) {
            super(looper);
        }

        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Toast toast = Toast.makeText(ToastTestActivity.this, "Dismiss me", Toast.LENGTH_LONG);
            toast.show();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandler.removeMessages(1);
        mThread.getLooper().quit();
        mHandler = null;
        mThread = null;
    }
}
 

該Activity有一個Button, 點擊之後會向HandlerThread發送一個延時消息,Handler處理該消息時會創建並顯示一個Toast,當Toast正在顯示的時候,點Back鍵退出Activity。就會發現正在顯示的Toast不會消失。

 

原因:

罪魁禍首就是HandlerThread在onDestroy方法裏面調用了HandlerThread.getLooper().quit()。因爲Toast在創建的時候,會同時創建一個基於當前線程的Handler對象,雖然NotificationManagerService負責調度Toast,但是真正顯示和隱藏Toast都是向這個Handler發送消息。也就是說Toast做事情也用到了HandlerThread的Looper。所以如果單純在onDestroy方法裏將Looper給quit的話,Toast將無法實現隱藏。

解決方案:

個人感覺讓Toast遠離HandlerThread比較靠譜。可以統一規範代碼,所有顯示Toast的代碼都post到主線程(無論是Activity還是Service)當中,因爲主線程的Looper不會輕易quit,至少不會允許開發者顯示quit。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章