Android Toast cancel和show 不踩中不會知道的坑


說到Android Toast,幾乎都很熟悉吧,下面講講怎么實現下面幾種場景:

1、連續點擊一個按鈕,每次都產生一個新的Toast並且調用show方法

  問題:觸發了toast以后,toast內容會一直排着隊的顯示出來,不能很快的消失

2、連續點擊一個按鈕,緩存一個Toast,每次都調用show方法

  推薦:這種方式體驗感覺最好,Toast消失的計時會從最后一次show之后才開始計算,還可以通過setText設置不同的內容

3、連續點擊一個按鈕,緩存一個Toast,每次先調用cancel再調用show方法 

  問題:這里有坑,可能cancel之后就show不出來了

4、別人封裝的一個列子,介紹了Toast其他的一些問題


 

下面看下上面1-3種方式的代碼寫法:

1、連續點擊一個按鈕,每次都產生一個新的Toast並且調用show方法,這個沒什么好說的,都會寫

Toast.makeText(context, "要顯示的提示", Toast.LENGTH_LONG).show();

2、連續點擊一個按鈕,緩存一個Toast,每次都調用show方法(推薦寫法,體驗比較好)

 private Toast mShowingToast;
 private void showTestToast() {
     // mActivity是一個Activity對象,彈Toast一般用Activity類型的Context
     if (mShowingToast == null) {
         mShowingToast = Toast.makeText(mActivity, "要顯示的提示", Toast.LENGTH_LONG);
     }
     mShowingToast.show();
 }

3、連續點擊一個按鈕,緩存一個Toast,每次先調用cancel再調用show方法 (容易踩坑的地方

private Toast mShowingToast;
private void showTestToast() {
    // mActivity是一個Activity對象,彈Toast一般用Activity類型的Context
    if (mShowingToast == null) {
        mShowingToast = Toast.makeText(mActivity, "要顯示的提示", Toast.LENGTH_LONG);
    }
    mShowingToast.cancel(); mShowingToast.show(); // 會發現cancel之后調用show是show不出來的
}    

上面這種方式會發現Toast顯示不出來,改下寫法也許讀者能猜到為什么

private Toast mShowingToast;
// 主線程的Handler對象
private Handler mHandler = new Handler(Looper.getMainLooper());
private void showTestToast() {
    // mActivity是一個Activity對象,彈Toast一般用Activity類型的Context
    if (mShowingToast == null) {
        mShowingToast = Toast.makeText(mActivity, "要顯示的提示", Toast.LENGTH_LONG);
    }
    mShowingToast.cancel(); mHandler.postDelayed(new Runnable() { @Override public void run() { mShowingToast.show(); // 會發現延遲之后就顯示出來了 } }, 200); // 這個時間是自己拍腦袋寫的,不影響體驗就好,試過使用post也不行
}

 

為什么呢?可能是同步異步的問題,有可能show操作被后續執行的cancel給覆蓋了,所以不生效,看了下源碼也沒具體看出來

/**
* 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
    }
}

/**
 * Close the view if it's showing, or don't show it if it isn't showing yet.
 * You do not normally have to call this.  Normally view will disappear on its own
 * after the appropriate duration.
 */
public void cancel() {
    mTN.hide();

    try {
        getService().cancelToast(mContext.getPackageName(), mTN);
    } catch (RemoteException e) {
        // Empty
    }
}

這是Toast內部內TN的一個方法

/**
 * schedule handleHide into the right thread
 */
@Override
public void hide() {
    if (localLOGV) Log.v(TAG, "HIDE: " + this);
    mHandler.post(mHide);
}

如果有讀者知道上述問題的原因,歡迎回帖

 

參考文章:

http://blog.csdn.net/goodding/article/details/8792628

http://blog.csdn.net/arui319/article/details/7022392


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM