說到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); }
如果有讀者知道上述問題的原因,歡迎回帖
參考文章:
