AndroidToastcancel问题、源码分析和解决方案

本文中部分内容摘自API 部分代码来自android.widget.Toast类源代码

解决方案中 ToastUtil代码 由http://www.linuxidc.com/Linux/2012-01/51925.htm 修改而来(基本没做什么修改 删除了一个方法 添加了一个方法)

Toast介绍:

Atoastisaviewcontainingaquicklittlemessagefortheuser.Thetoastclasshelpsyoucreateandshowthose.

Whentheviewisshowntotheuser,appearsasafloatingviewovertheapplication.Itwillneverreceivefocus.Theuserwillprobablybeinthemiddleoftypingsomethingelse.Theideaistobeasunobtrusiveaspossible,whilestillshowingtheusertheinformationyouwantthemtosee.Twoexamplesarethevolumecontrol,andthebriefmessagesayingthatyoursettingshavebeensaved.

TheeasiestwaytousethisclassistocalloneofthestaticmethodsthatconstructseverythingyouneedandreturnsanewToastobject.

问题:

问题主要出现在通过按钮或事件触发Toast时,若多次点击按钮(或某事件多次触发),会触发一系列Toast,它们会依次缓慢出现在屏幕上,无法消除,令用户看起来很难受。

当然Toast类中存在消除Toast的方法

publicvoidcancel()

Since:APILevel1

Closetheviewifit'sshowing,ordon'tshowitifitisn'tshowingyet.Youdonotnormallyhavetocallthis.Normallyviewwilldisappearonitsownaftertheappropriateduration.

但是事实证明,API中对cancel类的说明完全是胡扯。

比如我在程序中存放一个ArrayList<Toast>对象用来存放所有的Toast对象,按照API的说法,即使我按了无数次的按钮触发了无数次Toast,但是只要遍历ArrayList将全部Toastcancel掉不就一切都清净了?

遗憾的事,即使遍历ArrayList对每一个Toast对象指向cancel方法,只有当前正在显示的Toast会被cancel掉,队列中的Toast的依然会依次展现。

查看下Toast类的源代码:

首先找到cancel方法及相关调用链:

publicvoidcancel(){

mTN.hide();

//TODOthisstillneedstocanceltheinflightnotificationifany

}

/**

*schedulehandleHideintotherightthread

*/

publicvoidhide(){

if(localLOGV)Log.v(TAG,"HIDE:"+this);

mHandler.post(mHide);

}

finalRunnablemHide=newRunnable(){

publicvoidrun(){

handleHide();

}

};

publicvoidhandleHide(){

if(localLOGV)Log.v(TAG,"HANDLEHIDE:"+this+"mView="+mView);

if(mView!=null){

//note:checkingparent()justtomakesuretheviewhas

//beenadded...ihaveseencaseswherewegetherewhen

//theviewisn'tyetadded,solet'strynottocrash.

if(mView.getParent()!=null){

if(localLOGV)Log.v(

TAG,"REMOVE!"+mView+"in"+this);

mWM.removeView(mView);

}

mView=null;

}

}

看到了么,源代码中显示,执行cancel方法只会把正在显示的Toast移除,还未被显示的Toast,根本就通不过上面的if条件判断。

API中所说的Closetheviewifit'sshowing,ordon'tshowitifitisn'tshowingyet.

只有前半段是对的,后半段纯属胡扯。

解决方案:

由于Toast中控制显示隐藏的部分privateclassTNextendsITransientNotification.Stub是个私有内部类,所以继承Toast修改代码是不成了,也听说有高手用反射动态修改这部分的,不知解决情况究竟如何。

这里这个解决办法很简单,既然加入Toast队列的Toast我无法控制,我自己在外部实现一个Toast队列,自己控制它就是了。

简单的实现:全局只有1Toast对象由此类中的静态方法控制显示。

每次显示时,cancel掉原来的Toast对象。即,Toast队列中,只有01Toast。每次触发Toast动作,都会立即清除上一个Toast.

packageXXXXXXXXXXXXXXXXXXXXXX;

importandroid.content.Context;

importandroid.os.Handler;

importandroid.os.Looper;

importandroid.widget.Toast;

publicclassToastUtil{

privatestaticHandlerhandler=newHandler(Looper.getMainLooper());

privatestaticToasttoast=null;

privatestaticObjectsynObj=newObject();

publicstaticvoidshowMessage(finalContextact,finalStringmsg){

showMessage(act,msg,Toast.LENGTH_SHORT);

}

publicstaticvoidshowMessage(finalContextact,finalintmsg){

showMessage(act,msg,Toast.LENGTH_SHORT);

}


publicstaticvoidshowMessage(finalContextact,finalintmsg,

finalintlen){

newThread(newRunnable(){

publicvoidrun(){

handler.post(newRunnable(){

@Override

publicvoidrun(){

synchronized(synObj){

if(toast!=null){

toast.cancel();

toast.setText(msg);

toast.setDuration(len);

}else{

toast=Toast.makeText(act,msg,len);

}

toast.show();

}

}

});

}

}).start();

}

publicstaticvoidcancelCurrentToast(){

if(toast!=null){

toast.cancel();

}

}

}

--------------------------

2月28日追加:

实测 在2.2 2.3中此方法工作良好。

在4.0系统中效果极差

多次触发Toast 无法正常显示

更多相关文章

  1. Android(安卓)Okhttp + Android提交post表单乱码问题
  2. [Android(安卓)相机]Android(安卓)相机开发的基本流程
  3. Android(安卓)知识点积累(一)
  4. android判断是否联网
  5. Java/Android(安卓)Annotation processor实践:greendaoannotation
  6. android 在listview上的 gallery 禁止上下滑动
  7. Android中更详细的log获取方法
  8. RatingBar的使用方法
  9. Android(安卓)input处理机制(一)InputReader

随机推荐

  1. 【android测试】值得学习的android测试知
  2. Android(安卓)Develop Challenge
  3. 【android开发】styles.xml常用的设置属
  4. 在android平台上编译libpcap-0.9.8 和 jn
  5. [转]Android文件管理器介绍
  6. 固定屏幕显示模式 ScreenOrientation
  7. Could not find helloworld.apk
  8. Android(安卓)获取内存信息
  9. Android中如何引入Lambda表达式
  10. android获取经纬度和地方名称