Reputation: 208012
What is this error, and why does it happen?
05-17 18:24:57.069: ERROR/WindowManager(18850): Activity com.mypkg.myP has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@44c46ff0 that was originally added here
05-17 18:24:57.069: ERROR/WindowManager(18850): android.view.WindowLeaked: Activity ccom.mypkg.myP has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@44c46ff0 that was originally added here
05-17 18:24:57.069: ERROR/WindowManager(18850): at android.view.ViewRoot.<init>(ViewRoot.java:231)
05-17 18:24:57.069: ERROR/WindowManager(18850): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:148)
05-17 18:24:57.069: ERROR/WindowManager(18850): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
05-17 18:24:57.069: ERROR/WindowManager(18850): at android.view.Window$LocalWindowManager.addView(Window.java:424)
05-17 18:24:57.069: ERROR/WindowManager(18850): at android.app.Dialog.show(Dialog.java:239)
05-17 18:24:57.069: ERROR/WindowManager(18850): at com.mypkg.myP$PreparePairingLinkageData.onPreExecute(viewP.java:183)
05-17 18:24:57.069: ERROR/WindowManager(18850): at android.os.AsyncTask.execute(AsyncTask.java:391)
05-17 18:24:57.069: ERROR/WindowManager(18850): at com.mypkg.myP.onCreate(viewP.java:94)
05-17 18:24:57.069: ERROR/WindowManager(18850): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
05-17 18:24:57.069: ERROR/WindowManager(18850): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2544)
05-17 18:24:57.069: ERROR/WindowManager(18850): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2621)
05-17 18:24:57.069: ERROR/WindowManager(18850): at android.app.ActivityThread.access$2200(ActivityThread.java:126)
05-17 18:24:57.069: ERROR/WindowManager(18850): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1932)
05-17 18:24:57.069: ERROR/WindowManager(18850): at android.os.Handler.dispatchMessage(Handler.java:99)
05-17 18:24:57.069: ERROR/WindowManager(18850): at android.os.Looper.loop(Looper.java:123)
05-17 18:24:57.069: ERROR/WindowManager(18850): at android.app.ActivityThread.main(ActivityThread.java:4595)
05-17 18:24:57.069: ERROR/WindowManager(18850): at java.lang.reflect.Method.invokeNative(Native Method)
05-17 18:24:57.069: ERROR/WindowManager(18850): at java.lang.reflect.Method.invoke(Method.java:521)
05-17 18:24:57.069: ERROR/WindowManager(18850): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
05-17 18:24:57.069: ERROR/WindowManager(18850): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
05-17 18:24:57.069: ERROR/WindowManager(18850): at dalvik.system.NativeStart.main(Native Method)
Upvotes: 1307
Views: 707654
Reputation: 120
If you just deal with the problem of Dialog
in Activity.onConfigurationChanged
//If `android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"` has been configured in `AndroidManifest.xml`, you do not need to set this item
Acticity/Context.registerComponentCallbacks(object : ComponentCallbacks {
override fun onConfigurationChanged(newConfig: Configuration) {
dialog?.dismiss()
}
override fun onLowMemory() {
}
})
It is safer to destroy in on Destroy
override fun onDestroy() {
super.onDestroy()
DialogManager.dismiss()
}
Maybe this is useful for you 👉 https://github.com/javakam/DialogManager
Upvotes: 0
Reputation: 909
There was a database operation inside the dialog method, that caused the Activity to blow up.
Probably at times this log message can be deceptive.
private fun showDialog() {
val customDialog = Dialog(requireActivity())
customDialog.setContentView(R.layout.dialog_custom)
customDialog.window?.setLayout(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
val btnGenerate = customDialog.findViewById(R.id.btnGenerate) as TextView
val etScheduleNumber = customDialog.findViewById(R.id.etScheduleNo) as AutoCompleteTextView
val etTripNumber = customDialog.findViewById(R.id.etTripNumber) as AutoCompleteTextView
viewModel.getBreakdownScheduleNumbers { scheduleNumberList->
val adapter = CustomAdapter(requireContext(),
scheduleNumberList as ArrayList<String>)
etScheduleNumber.setAdapter(adapter)
}
btnGenerate.setOnClickListener {
}
customDialog.show()
}
Upvotes: 0
Reputation: 614
Might it help to someone who visit this question.
You should check safe condition for activity and dialog before show()
and dismiss()
dialog.
Add below condition before showing dialog
if (!isFinishing && !isDestroyed && !dialog.isShowing) {
dialog.show()
}
Add below condition before dismiss dialog
if (!isFinishing && !isDestroyed && dialog.isShowing) {
dialog.dismiss()
}
isFinishing
and isDestroyed
will give surety about activity(from where Dialog
is initiated) is not in isFinishing
or isDestroyed
state. Sometimes we try to open Dialog when dialog hosting activity is going to destroy and we facing "leaked window" issue
dialog.isShowing
to check dialog state before show()
or dismiss()
dialog.
Upvotes: 7
Reputation: 511
Other that hiding your dialog, dismiss it instead.
Replace .hide()
with .dismiss()
Upvotes: 2
Reputation: 170
Much later than the previous answers, in 2022 where people use Kotlin, we also get the error when Kotlin coroutine tries to modify a popup window from the wrong (non-Main) coroutine context.
Produces error:
CoroutineScope(Dispatchers.IO).launch{
someCodeThatNeedsOtherContext()
someViewBinding.someAttribute = someValue // We get the error here
}
Does not produce error:
CoroutineScope(Dispatchers.IO).launch{
someCodeThatNeedsOtherContext()
CoroutineScope(Dispatchers.Main).launch{
someViewBinding.someAttribute = someValue // No error here
}
}
Upvotes: 0
Reputation: 99
This is how I solved this bottomSheetDialog.dismiss() the dialog before the finesh() of the activity
startActivity(Intent(this, Activity::class.java))
bottomSheetDialog.dismiss()
finish()
Upvotes: 0
Reputation: 261
A only answer is
@Override
public void onBackPressed() {
exit_popup();
// super.onBackPressed(); remove this line
}
Upvotes: 0
Reputation: 1148
I was using Jetpack Compose and no dialogues so most of these answers were not applicable to me. It turned out that I was accessing out of range array index in a Kotlin coroutine.
I wrapped all the coroutine calls in try
and catch
.
try {
viewModelScope.launch(Dispatchers.IO) {
....
}
} catch (e: Exception) {
Log.e("Exception: ", e.message.toString())
}
And finally found the error (or should I say my mistake :P).
Upvotes: 1
Reputation: 4930
dismiss progressBar before activity destroyed
@Override
protected void onDestroy() {
try {
if (progressDialog != null)
progressDialog.dismiss();
} catch (Exception e) {
e.printStackTrace();
}
super.onDestroy();
}
Upvotes: 2
Reputation: 2659
I am making a scientific app that is already close to 45 thousand lines and I use asynchronous tasks in order to be able to interrupt long tasks, if so desired, with a certain click of the user.
Thus, there is a responsive user interface and sometimes a long task in parallel.
When the long task is over, I need to run a routine that manages the user interface.
So, at the end of an asynchronous task, I do a following action that involves the interface, which cannot be performed directly, otherwise it gives an error. So I use
this.runOnUiThread(Runnable { x(...)}) // Kotlin
Many times, this error occurs in some point of function x
.
If function x
was called outside a thread
x(...) // Kotlin
Android Studio
would show a call stack with the error line and one easily could fix the problem in few minutes.
As my source code is tamed, and there is no serious structural problem (many answers above describe this kind of errors), the reason for this scary error message is more gross and less important.
It's just any fool mistake in this execution linked to a thread (like, for example, accessing a vector beyond the defined length), as in this schematic example:
var i = 10 // Kotlin
...
var arr = Array(5){""}
var element = arr[i] // 10 > 5, it's a index overflow
Regarding this stupid error, Android Studio
unfortunately doesn't point to it.
I even consider it a bug, because Android Studio
knows that there is an error, where it is located, but, for some unknown reason, it gets lost and gives a random message, totally disconnected from the problem, i.e, a weird message with no hint showing up.
The solution: Have a lot of patience to run step by step in the debugger until reaching the error line, which Android Studio
refused to provide.
This has happened to me several times and I guess it's an extremely common mistake on Android projects. I had never before given this kind of error to me before I used threads.
Nobody is infallible and we are liable to make small mistakes. In this case, you cannot count on the direct help of Android Studio
to discover where is your error!
Upvotes: 0
Reputation: 333
here is a solution when you do want to dismiss AlertDialog but do not want to keep a reference to it inside activity.
solution requires you to have androidx.lifecycle dependency in your project (i believe at the moment of the comment it's a common requirement)
this lets you to delegate dialog's dismiss to external object (observer), and you dont need to care about it anymore, because it's auto-unsubscribed when activity dies. (here is proof: https://github.com/googlecodelabs/android-lifecycles/issues/5).
so, the observer keeps the reference to dialog, and activity keeps reference to observer. when "onPause" happens - observer dismisses the dialog, and when "onDestroy" happens - activity removes observer, so no leak happens (well, at least i dont see error in logcat anymore)
// observer
class DialogDismissLifecycleObserver( private var dialog: AlertDialog? ) : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun onPause() {
dialog?.dismiss()
dialog = null
}
}
// activity code
private fun showDialog() {
if( isDestroyed || isFinishing ) return
val dialog = AlertDialog
.Builder(this, R.style.DialogTheme)
// dialog setup skipped
.create()
lifecycle.addObserver( DialogDismissLifecycleObserver( dialog ) )
dialog.show()
}
Upvotes: 12
Reputation: 6205
If you are dealing with LiveData, when updating value instead of using liveData.value = someValue
try to do liveData.postValue(someValue)
Upvotes: 0
Reputation: 2350
Maybe you used findViewById
in activity instead of dialog.findViewById
and set afterwards an OnClickListener
on a null
instance and that probably caused the original error.
Upvotes: 0
Reputation: 792
Got this error when trying to display a Toast from Background thread. It was solved by running the UI related code on the UI thread
Upvotes: 3
Reputation: 5327
Best solution is put this before showing progressbar
or progressDialog
if (getApplicationContext().getWindow().getDecorView().isShown()) {
//Show Your Progress Dialog
}
Upvotes: 4
Reputation: 849
Generally this issue occurs due to progress dialog : you can solve this by using any one of the following method in your activity:
// 1):
@Override
protected void onPause() {
super.onPause();
if ( yourProgressDialog!=null && yourProgressDialog.isShowing() )
{
yourProgressDialog.cancel();
}
}
// 2) :
@Override
protected void onDestroy() {
super.onDestroy();
if ( yourProgressDialog!=null && yourProgressDialog.isShowing()
{
yourProgressDialog.cancel();
}
}
Upvotes: 10
Reputation: 353
Not only try to show an alert but it can also be invoked when you finish a particular instance of activity and try to start new activity/service or try to stop it.
Example:
OldActivity instance;
oncreate() {
instance=this;
}
instance.finish();
instance.startActivity(new Intent(ACTION_MAIN).setClass(instance, NewActivity.class));
Upvotes: 6
Reputation: 1881
I was having the same problem and found this page, and while my situation was different I called finish
from a if
block before it defined the alert box.
So, simply calling dismiss
wouldn't work (as it hasn't been made yet) but after reading Alex Volovoy's answer and realizing it was the alert box causing it. I tried to add a return statement right after the finish inside that if
block and that fixed the issue.
I thought once you called finish it stopped everything and finished right there, but it doesn't. It seem to go to the end of the block of code it's in then finishes.
So, if you want to implement a situation where sometimes it'll finish before doing some code you do gotta put a return statement right after the finish or it'll keep on going and and act like the finish was called at the end of the block of code not where you called it. Which is why I was getting all those weird errors.
private picked(File aDirectory){
if(aDirectory.length()==0){
setResult(RESULT_CANCELED, new Intent());
finish();
return;
}
AlertDialog.Builder alert= new AlertDialog.Builder(this); // Start dialog builder
alert
.setTitle("Question")
.setMessage("Do you want to open that file?"+aDirectory.getName());
alert
.setPositiveButton("OK", okButtonListener)
.setNegativeButton("Cancel", cancelButtonListener);
alert.show();
}
If you don't put the return right after I called finish in there, it will act as if you have called it after the alert.show();
and hence it would say that the window is leaked by finishing just after you made the dialog appear, even though that's not the case, it still think it is.
I thought I'd add this as here as this shows the finish command acted differently then I thought it did and I'd guess there are other people who think the same as I did before I discovered this.
Upvotes: 12
Reputation: 2028
Best solution is just add dialog in try catch and dismiss dialog when exception occur
Just use below code
try {
dialog.show();
} catch (Exception e) {
dialog.dismiss();
}
Upvotes: 4
Reputation: 68474
You're trying to show a Dialog after you've exited an Activity.
[EDIT]
This question is one of the top search on google for android developer, therefore Adding few important points from comments, which might be more helpful for future investigator without going in depth of comment conversation.
Answer 1 :
You're trying to show a Dialog after you've exited an Activity.
Answer 2
This error can be a little misleading in some circumstances (although the answer is still completely accurate) - i.e. in my case an unhandled Exception was thrown in an AsyncTask, which caused the Activity to shutdown, then an open progressdialog caused this Exception.. so the 'real' exception was a little earlier in the log
Answer 3
Call dismiss() on the Dialog instance you created before exiting your Activity, e.g. in onPause() or onDestroy()
Upvotes: 1729
Reputation: 7571
The answers to this question were all correct, but a little confusing for me to actually understand why. After playing around for around 2 hours the reason to this error (in my case) hit me:
You already know, from reading other answers, that the has X has leaked window DecorView@d9e6131[]
error means a dialog was open when your app closed. But why?
It could be, that your app crashed for some other reason while your dialog was open
This lead to your app closing because of some bug in your code, which lead to the dialog remaining open at the same time as your app closed due to the other error.
So, look through your logical. Solve the first error, and then the second error will solve itself
One error causes another, which causes another, like DOMINOS!
Upvotes: 66
Reputation: 39470
The "Activity has leaked window that was originally added...
" error occurs when you try show an alert after the Activity
is effectively finished
.
You have two options AFAIK:
dismiss()
on the dialog
before actually exiting your activity.dialog
in a different thread and run it on that thread
(independent of the current activity
).Upvotes: 5
Reputation: 71
You have to make Progressdialog
object in onPreExecute
method of AsyncTask
and you should dismiss
it on onPostExecute
method.
Upvotes: 4
Reputation: 158
I was getting these logs in my video player application. These messages were thrown while the video player was closed. Interestingly, I used to get these logs once in a few runs in a random manner. Also my application does not involve in any progressdialog
. Finally, I got around this issue with the below implementation.
@Override
protected void onPause()
{
Log.v("MediaVideo", "onPause");
super.onPause();
this.mVideoView.pause();
this.mVideoView.setVisibility(View.GONE);
}
@Override
protected void onDestroy()
{
Log.v("MediaVideo", "onDestroy");
super.onDestroy();
}
@Override
protected void onResume()
{
Log.v("MediaVideo", "onResume");
super.onResume();
this.mVideoView.resume();
}
Override the OnPause
with call to mVideoView.pause()
and the set visibility
to GONE
. This way I could resolve the "Activity has leaked window
" log error issue.
Upvotes: 12
Reputation: 29
I have the same kind of problem. the error was not in the Dialog
but in a EditText
. I was trying to change the value of the Edittext
inside of a Assynctask
. the only away i could solve was creating a new runnable
.
runOnUiThread(new Runnable(){
@Override
public void run() {
...
}
});
Upvotes: 1
Reputation: 393
The issue according to me is you are trying to call a dialog right after an activity is getting finished so according me what you can do is give some delay using Handler and you issue will be solved for eg:
Handler handler=new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
dialog.show();
//or
dialog.dismiss();
}
},100);
Upvotes: 1
Reputation: 6971
I was also facing this problem for some time but I realized it's not because of dialog
in my case it's because of ActionMode
. So if you are trying to finish activity when an ActionMode
is open it will cause this problem. In your activity's onPause
finish the action mode.
private ActionMode actionMode;
@Override
public void onActionModeStarted(ActionMode mode) {
super.onActionModeStarted(mode);
actionMode = mode;
}
@Override
protected void onPause() {
super.onPause();
if (actionMode != null) actionMode.finish();
}
Upvotes: 0
Reputation: 919
if (mActivity != null && !mActivity.isFinishing() && mProgressDialog != null && mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
}
Upvotes: 2
Reputation: 397
I also encounter the WindowLeaked problem when run monkey test.The logcat is below.
android.support.v7.app.AppCompatDelegateImplV7$ListMenuDecorView@4334fd40 that was originally added here
android.view.WindowLeaked: Activity com.myapp.MyActivity has leaked window android.support.v7.app.AppCompatDelegateImplV7$ListMenuDecorView@4334fd40 that was originally added here
at android.view.ViewRootImpl.<init>(ViewRootImpl.java:409)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:312)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:224)
at android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java:149)
at android.view.Window$LocalWindowManager.addView(Window.java:554)
at android.support.v7.app.AppCompatDelegateImplV7.openPanel(AppCompatDelegateImplV7.java:1150)
at android.support.v7.app.AppCompatDelegateImplV7.onKeyUpPanel(AppCompatDelegateImplV7.java:1469)
at android.support.v7.app.AppCompatDelegateImplV7.onKeyUp(AppCompatDelegateImplV7.java:919)
at android.support.v7.app.AppCompatDelegateImplV7.dispatchKeyEvent(AppCompatDelegateImplV7.java:913)
at android.support.v7.app.AppCompatDelegateImplBase$AppCompatWindowCallbackBase.dispatchKeyEvent(AppCompatDelegateImplBase.java:241)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:2009)
at android.view.ViewRootImpl.deliverKeyEventPostIme(ViewRootImpl.java:3929)
at android.view.ViewRootImpl.deliverKeyEvent(ViewRootImpl.java:3863)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:3420)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:4528)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:4506)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:4610)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:171)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:125)
at android.os.Looper.loop(Looper.java:124)
at android.app.ActivityThread.main(ActivityThread.java:4898)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1008)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:775)
at dalvik.system.NativeStart.main(Native Method)
My Activity is AppCompatActivity.And I resovled it with the below code in the Activity.
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
// added by sunhang : intercept menu key to resove a WindowLeaked error in monkey-test.
if (event.getKeyCode() == KeyEvent.KEYCODE_MENU) {
return true;
}
return super.dispatchKeyEvent(event);
}
Upvotes: 1