案例:今天修改公司一个项目BUG,有个效果是进APP首页,APP弹出弹窗广告,广告内容是实时从服务器获取的,(一般APP不推荐这么做,很多都是每次次进入获取下次要显示的广告),因为是实时获取,可能在这过程中网络不好,用户误点到某个模块进行跳转,那么已经开始show的dialog或者popupwindow就会出现BadTokenException.

异常信息:android.view.WindowManager&BadTokenException:Unable to add window这个错误,说reference on a null performance


正确异常出现原因:

1.由于dialog和popupwindow都要依附于activity,所以dialog和popupwindow在show之前,activity的实例都要存在,不能被销毁.

2.因为是开启线程进行联网耗时操作,耗时操作完毕再showdialog和popupwindow.用户在实际操作的时候,很有可能没有等到dialog和popupwindow在show之前就进行页面跳转,销毁上一个依赖的activity实例.导致在showdialog的时候报错.

因此解决思路就很明朗了.那就是:在activityfinish进行跳转的时候,在onDestroy里面去killprogess(); 即杀掉进程下所有的线程.


解决方法:
1.看了网上杀线程的方法.很多都在说android.os.Process.killProcess(android.os.Process.myPid());这个方法是杀掉当前所有的进程和线程.直接上代码,在跳转的时候直接全杀,在onDestroy的时候去实现跳转.

因为笔者,只想到了这么做,无论是跳转前和跳转后去杀线程,都会导致整个APP程序关闭.只有这样才能实现杀了在跳转的效果.

但是,这样做非常不好.第一.用户体验很差,跳转的时候会出现一瞬间黑屏.第二,跳转完成之后,你还得考虑之前被误杀的在后台跑的线程重启的问题,如果是需要在后台挂长连接的APP,这么做会很影响性能,且效果很低,所以,相当不推荐这个做法.简直是误导人.

protected void killprogess() {android.os.Process.killProcess(android.os.Process.myPid());}
@Overrideprotected void onDestroy() {super.onDestroy();startActivity(new Intent(MainActivity.this, SecondActivity.class));finish();}
2 .第二种方法,笔者经过综合考虑,还是觉得比较合适.推荐用这种方法.主要还是通过主线程的handler去remove掉当前跑的runnable.这样做不会有连带的影响,直接上代码,很简单,相信大家都能看懂.不解释了.

/** * 进主界面有个广告弹窗,弹窗内容需要联网获取. * --------------这边可以设计成,首次登陆去获取下次要弹出的广告,一般的APP都推荐这么做, 不过我们公司有点逆天,反正需求是要每次都实时去获取------ * 在跳转的时候,关闭activity下面的线程,避免出现异常 * 有两种实现方式,推荐用handler.removeCallbacks关闭执行的线程 * @author max * */public class MainActivity extends Activity {private static final String TAG = "com.max.threadshutdowndemo";private Handler mHandler = new Handler();Runnable runnable = new Runnable() {@Overridepublic void run() {//显示广告弹窗的dialogshowAD();}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//我用postdelayed来模拟联网获取广告的告示操作mHandler.postDelayed(runnable, 3000);Button button = (Button) findViewById(R.id.first_button);//如果用户在中途误点了某个模块,发生了页面跳转.那么久先啥子当前activity的线程,在跳转,避免出现异常崩溃button.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {killprogess();}});}/** * 第一种方式,杀死当前的进程以及下面的线程 */protected void killprogess() {startActivity(new Intent(MainActivity.this, SecondActivity.class));finish();}/** * 显示一个dialog或者popupwindow * 弹窗显示的内容有可能是需要用thread去联网获取的耗时操作 * 这里为了方便用postDelayed来表示耗时操作 */protected void showAD() {//这边为了保险起见,加入了try catch捕获异常,避免崩溃,不过已经remove了子线程,这样做是多余的.有兴趣的童鞋可以尝试哈try {Dialog dialog = new AlertDialog.Builder(MainActivity.this).create();dialog.show();dialog.setCanceledOnTouchOutside(false);Window window = dialog.getWindow();window.setContentView(R.layout.dialog_main);} catch (Exception e) {Log.e(TAG, e.getMessage());e.printStackTrace();}}/** * 在ondestroy中执行关闭子线程的操作 */@Overrideprotected void onDestroy() {super.onDestroy();//这个方法极力不推荐.//android.os.Process.killProcess(android.os.Process.myPid());//关键的操作,当前页面finish的时候,关闭下面还在跑得线程,防止出现异常.//也可以用try catch捕获异常防止crash掉mHandler.removeCallbacks(runnable);}}


最后是源码,效果我就不截图了,这边有兴趣的童鞋,可以下源码自己泡一下.源码下载请点击这里.

更多相关文章

  1. Android(安卓)NDK——必知必会之Native线程操作及线程同步全面详
  2. Android(安卓)ANR分析
  3. android并发网络请求的处理
  4. android 四大控件之ContentProvider
  5. 线程方法Android:异步调用详解
  6. 金九银十中,看看这31道Android面试题
  7. Google 发布 Android(安卓)性能优化典范
  8. Android(安卓)Handler 作用以及使用
  9. 移动端启动速度

随机推荐

  1. 通过SQL绘制杨辉三角的实现方法介绍
  2. 基于SQL Server中如何比较两个表的各组数
  3. order by newid() 各种数据库随机查询的
  4. SQL2000 事务回滚问题探讨
  5. 关于PowerDesigner初体验的使用介绍
  6. 基于存储过程的详细介绍
  7. sql动态行转列的两种方法
  8. SQL中的ISNULL函数使用介绍
  9. 关于sql server批量插入和更新的两种解决
  10. 基于Sql Server通用分页存储过程的解决方