在AsyncTask中使用自定义loadingDialog时报错:DecorView not attached to window manager

项目接入友盟统计后着实发现了不少测试同事没有测出来也不太容易复现的问题,其中出现次数相当多的一个就是如题所示使用dialog报的异常。

异常日志如下:


DecorView not attached to window manager 这句话直译的意思就是DecorView 并没有附加在window manager管理器中。

在Android中所有窗口的创建和管理都是依附于window manager的,查询源码可以看到dialog的创建也不例外,在dialog的构造函数中创建了一个window对象,而在dialog的show方法中使用window对象构造了一个DecorView,dialog最终将这个DecorView通过addView的方法依附于window manager来展示。

查阅很多博文与资料之后确定,出现上述错误的原因是由于加载框在展示期间也就是用户能看到这个dialog的时候,这个dialog所依附的activity因为某种原因被系统杀掉又重新启动了,但是重新启动后的activity并不是dialog所依附的那个了,而后当任务结束需要调用dialog.dismiss()时,通过源码可知window manager会去检查dialog所属的activity是否更改,如果不是原来的activity就会报出上述异常。

知道了问题出现的原因,也就应该容易解决了,但是网上大多数博文给出的解决办法是将dialog的生命周期activity的生命周期绑定在一起,在activity中处理dialog的展示与销毁,或者使用activity自带的dialog控制方法,例如:

private LoadingDialog loadingDialog;

/**
 * 显示进度条
 */
public void showProgress() {

	loadingDialog = new LoadingDialog(this, "请稍候", true);
	loadingDialog.setCancelable(false);
	loadingDialog.getStopButton().setOnClickListener(new OnClickListener() {

		@Override
		public void onClick(View v) {
			loadingDialog.dismiss();
		}
	});
	loadingDialog.show();
}

/**
 * 取消登陆进度条
 */
public void dismissProgress() {
	loadingDialog.dismiss();
}

@Override
protected void onDestroy() {
	if (loadingDialog != null && loadingDialog.isShowing()) {
		loadingDialog.dismiss();
	}
	super.onDestroy();
}

但是这些办法都不适用与我的项目中,因为我的AsyncTask异步请求可能在不同的activity都会调用,并且dialog中必须要有异步请求终止按钮,而在同一个AsyncTask去区分是哪一个activity这种方式显然是不可取的。

经过研究dialog的源码,终于发现更优的解决办法,如下:

	dialog.setOwnerActivity((Activity) context);
	
	public void show() {
		if (dialog != null ) {  
		    Activity activity = dialog.getOwnerActivity();  
		    if (activity != null && !activity.isFinishing() ) {  
		    	dialog.show();  
		    }  
		}  
	}

	public void dismiss() {
		if (dialog != null && dialog.isShowing()) {
			Activity activity = dialog.getOwnerActivity();
			if (activity != null && !activity.isFinishing()) {
				dialog.dismiss();
			}
		}
		
	}

在我自定义的LoadingDialog中调用dialog的dismiss()方法前先调用dialog.getOwnerActivity()检查当前dialog所属的activity是否存在。

需要注意的是,自定义的dialog调用dialog.getOwnerActivity()方法前需要先调用dialog.setOwnerActivity(),否则会返回null。

这样就完美解决了这个异常,欢迎批评指正,谢谢大家!


                                                                                        

猜你喜欢

转载自blog.csdn.net/cunjicsdn/article/details/78028629
今日推荐