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); }
如果有读者知道上述问题的原因,欢迎回帖
参考文章: