Error when using custom loadingDialog in AsyncTask: DecorView not attached to window manager

After the project was connected to Umeng's statistics, many problems that were not detected by test colleagues and were not easy to reproduce were found. One of the problems that occurred quite often was the abnormality reported by the dialog as shown in the title.

The exception log is as follows:


The literal translation of DecorView not attached to window manager means that DecorView is not attached to the window manager.

The creation and management of all windows in Android are attached to the window manager. You can see the creation of dialog by querying the source code. A window object is created in the dialog's constructor, and window is used in the dialog's show method. The object constructs a DecorView, and the dialog finally attaches the DecorView to the window manager through the addView method to display it.

After consulting a lot of blog posts and materials, it is determined that the reason for the above error is that the activity to which the dialog is attached is killed and restarted by the system during the display of the loading box, that is, when the user can see the dialog . However, the restarted activity is not the one that the dialog is attached to, and then when the task ends and dialog.dismiss() needs to be called, the source code shows that the window manager will check whether the activity to which the dialog belongs has changed. If it is not the original activity, it will The above exception is reported.

Knowing the cause of the problem, it should be easy to solve, but the solution given by most blog posts on the Internet is to bind the life cycle of the dialog's life cycle activity, and handle the display and destruction of the dialog in the activity. Or use the dialog control method that comes with the activity, for example:

private LoadingDialog loadingDialog;

/**
 * show progress bar
 */
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();
}

/**
 * Cancel the login progress bar
 */
public void dismissProgress() {
	loadingDialog.dismiss();
}

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

But these methods are not applicable to my project, because my AsyncTask asynchronous request may be called in different activities, and there must be an asynchronous request termination button in the dialog, and in the same AsyncTask to distinguish which activity is this way is obviously not advisable.

After studying the source code of the dialog, I finally found a better solution, as follows:

	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();
			}
		}
		
	}

Before calling the dialog's dismiss() method in my custom LoadingDialog, call dialog.getOwnerActivity() to check whether the activity to which the current dialog belongs exists.

It should be noted that the custom dialog needs to call dialog.setOwnerActivity() before calling the dialog.getOwnerActivity() method, otherwise it will return null.

This perfectly solves this exception. Comments and corrections are welcome, thank you!


                                                                                        

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326447394&siteId=291194637