Android BadTokenException 问题解决

前言

今天测试过程中发现了“android.view.WindowManager$BadTokenException”问题,这里记录一下解决方法。(PS:第一款应用上线了,感觉BUG还是比较多,感觉因为这个应用,能不能过试用期都是问题了,只能坚持加油了)。

问题分析

这种问题其实在错误日志中都能给出很好的提示,下面贴一下部分有用的错误日志,如下所示:
android.view.WindowManager$BadTokenException,ViewRootImpl.java,android.view.ViewRootImpl,setView,640,android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@444628b8 is not valid, is your activity running? 
通过日志,可以知道,这种问题一般是因为在AsyncTask中的onPostExecute中执行了启动Dialog操作,但是当前的Activity已经被销毁了,写一个错误代码复现一下该问题:
package com.example.testlibrary;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.AsyncTask;
import android.os.Bundle;

public class MainActivity extends Activity {
	private UpdateUIAsyncTask asyncTask;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);


		updateUIProcess();
	}

	private void updateUIProcess() {
		asyncTask = new UpdateUIAsyncTask();
		asyncTask.execute();
	}
	
	private class UpdateUIAsyncTask extends AsyncTask<Void, Void, Boolean> {

		@Override
		protected void onPostExecute(Boolean result) {
			if (!isCancelled() && result) {
				AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this)
				.setTitle("标题")
				.setMessage("这是内容")
				.setPositiveButton("确定", new OnClickListener() {
					
					@Override
					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
					}
				})
				.setNegativeButton("取消", new OnClickListener() {
					
					@Override
					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
					}
				});
				
				AlertDialog dialog = builder.create();
				dialog.show();
			}
		}

		@Override
		protected Boolean doInBackground(Void... params) {
			if (!isCancelled()) {
				try {
					Thread.sleep(6000);
				} catch (InterruptedException e) {
					return false;
				}

				return true;
			}
			return true;
		}

	}
}
启动应用程序,并且在6s以内退出应用程序,返回建即可,就会发现应用程序出现了异常:
Android BadTokenException 问题解决

解决方案

如果当前Activity已经被销毁(无论是调用finish()或者按back、home键),但是Activity中的AsyncTask异步任务并没有结束,并且在onPostExecute中调用了alertDialog.show()就会出现:
android.view.WindowManager$BadTokenException: Unable to add window — token android.os.BinderProxy@4272a800 is not valid; is your activity running?.
解决方法也很简单:在alertDialog.show()执行之前,判断当前的Activity是否已经销毁了,可以使用android提供的isFinishing()方法。同时,在Activity中也应该增加清理AsyncTask的操作,示例代码如下:
package com.example.testlibrary;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.AsyncTask;
import android.os.Bundle;

public class MainActivity extends Activity {
	private UpdateUIAsyncTask asyncTask;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);


		updateUIProcess();
	}

	@Override
	protected void onDestroy() {
		// 增加清理AysncTask操作
		if (asyncTask != null && asyncTask.getStatus() != AsyncTask.Status.FINISHED) {
			asyncTask.cancel(true);
		}
		
		super.onDestroy();
	}



	private void updateUIProcess() {
		asyncTask = new UpdateUIAsyncTask();
		asyncTask.execute();
	}
	
	private class UpdateUIAsyncTask extends AsyncTask<Void, Void, Boolean> {

		@Override
		protected void onPostExecute(Boolean result) {
			// show dialog之前增加判断当前Activity是否finish操作
			if (!isCancelled() && result && MainActivity.this != null && !MainActivity.this.isFinishing()) {
				AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this)
				.setTitle("标题")
				.setMessage("这是内容")
				.setPositiveButton("确定", new OnClickListener() {
					
					@Override
					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
					}
				})
				.setNegativeButton("取消", new OnClickListener() {
					
					@Override
					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
					}
				});
				
				AlertDialog dialog = builder.create();
				dialog.show();
			}
		}

		@Override
		protected Boolean doInBackground(Void... params) {
			if (!isCancelled()) {
				try {
					Thread.sleep(6000);
				} catch (InterruptedException e) {
					return false;
				}

				return true;
			}
			return true;
		}

	}
}




Android BadTokenException 问题解决,布布扣,bubuko.com

Android BadTokenException 问题解决

上一篇:HDU 4925 Apple Tree (瞎搞)


下一篇:HDU4925-Apple Tree