1. 程式人生 > >Toast彈不出來之謎

Toast彈不出來之謎

前言

今天早上測試應用的時候,忽然發現Toast彈不出來了,我用的華為測試機,以為是通知許可權被關了,後來發現是開著的,這就納了悶了,這個Toast工具類用了好長時間了,後來發現這Toast原來還能這樣...

正文

以前工具類是這個樣子的(華為的通知許可權放在了其他的地方)

final public class ToastUtil {
    private static Toast toast;//單例的toast

    /**
     * 顯示Toast
     */
    public static void showToast(int text) {
        showToast(App.getInstance().getResources().getString(text));
    }

    public static void showToast(String text) {
        if (toast == null)
            toast = Toast.makeText(App.getInstance(), text, Toast.LENGTH_SHORT);
        toast.setText(text);
        toast.show();
    }
}

平時用的都是好好的,為什麼不能用了呢?

然後我通過debug發現所有路徑都走了,說明是呼叫成功了,後來想起來,是不是子執行緒的問題,列印了一下執行緒資訊:

Thread.currentThread().getName();

發現果然第一次呼叫沒有跑在主執行緒中,這就尷尬了,在子執行緒中建立,並show()竟然沒有報錯,而且子執行緒建立的在主執行緒呼叫show()也沒有報錯,只是不顯示

到show()的原始碼中發現,被try了..

    /**
     * Show the view for the specified duration.
     */
    public void show() {
        if (mNextView == null) {
            throw new RuntimeException("setView must have been called");
        }

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

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

修改方法

在建立和show的時候可以判斷是否是主執行緒,如果不是就放到主執行緒中就ok了

修改後的程式碼,嗯,這樣就可以了(雖然有強迫症看到這程式碼很不爽,但是首先得能用)

final public class ToastUtil {
    private static Toast toast;//單例的toast

    /**
     * 顯示Toast
     */
    public static void showToast(int text) {
        showToast(App.getInstance().getResources().getString(text));
    }

    public static void showToast(final String text) {
        if (toast == null) {
                AppManager.getAppManager().currentActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        toast = Toast.makeText(App.getInstance(), text, Toast.LENGTH_SHORT);
                        toast.show();
                    }
                });
        } else {
            //如果show()是在子執行緒觸發的,則在主執行緒來顯示
            if ("main".equals(Thread.currentThread().getName())) {
                toast.setText(text);//將文字設定給toast
                toast.show();
            } else {
                AppManager.getAppManager().currentActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        toast.setText(text);//將文字設定給toast
                        toast.show();
                    }
                });
            }
        }
    }
}

end