Question

I'm writing an app targeting Android API 10 (Gingerbread 2.3.3). If I rotate the device while the options menu is open I get a WindowLeaked exception. Why is this happening and how can I prevent it?

The exception goes away if I target API level 11 or higher, but I need API 10 for this particular app.

Exception log:

04-18 00:51:19.025  27934-27934/com.example.menuexample E/WindowManager﹕ android.view.WindowLeaked: Activity com.example.menuexample.MenuExampleActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView{41df94a0 V.E..... ......I. 0,0-768,156} that was originally added here
at android.view.ViewRootImpl.<init>(ViewRootImpl.java:348)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:248)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69)
at com.android.internal.policy.impl.PhoneWindow.openPanel(PhoneWindow.java:672)
at com.android.internal.policy.impl.PhoneWindow.onKeyUpPanel(PhoneWindow.java:879)
at com.android.internal.policy.impl.PhoneWindow.onKeyUp(PhoneWindow.java:1630)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1969)
at android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent(ViewRootImpl.java:3852)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:3826)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3399)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3449)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3418)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3525)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3426)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3582)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3399)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3449)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3418)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3426)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3399)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3449)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3418)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3558)
at android.view.ViewRootImpl$ImeInputStage.onFinishedInputEvent(ViewRootImpl.java:3718)
at android.view.inputmethod.InputMethodManager$PendingEvent.run(InputMethodManager.java:2010)
at android.view.inputmethod.InputMethodManager.invokeFinishedInputEventCallback(InputMethodManager.java:1704)
at android.view.inputmethod.InputMethodManager.finishedInputEvent(InputMethodManager.java:1695)
at android.view.inputmethod.InputMethodManager$ImeInputEventSender.onInputEventFinished(InputMethodManager.java:1987)
at android.view.InputEventSender.dispatchInputEventFinished(InputEventSender.java:141)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:138)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:5017)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
at dalvik.system.NativeStart.main(Native Method)

Here is a very minimal Activity that will recreate the Exception:

package com.example.menuexample;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;

public class MenuExampleActivity extends Activity
{
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu, menu);
        return true;
    }
}

Give the app a simple menu.xml:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/menu_something"
          android:title="something" />
</menu>

And set the minSdkVersion to 10 in AndroidManifest.xml:

<uses-sdk android:minSdkVersion="10"/>

Rotating the device with the options menu open will cause the exception.

Was it helpful?

Solution

Add this to your manifest:

android:configChanges="orientation|keyboardHidden

Then in your activity add this somewhere:

   @Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT)
{
    Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
    setContentView(R.layout.activity_hls_port);
}
 if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE)
{
    Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
    setContentView(R.layout.activity_hls_port );
} 
}

I'm not quite sure why the error is being caused, though when I tested it does not throw the exception--I wouldn't call it a fix but more of a workaround.

The line in the manifest file prevents the activity from being restarted when the device is rotated. Then when you override onConfigurationChanged(), a method that's called when the device is rotated, and since your're overriding it you have to specify the correct layout for portrait/orientation.

Note that onConfigurationChanged() may not just be called when the device is rotated--there are many others times this may be called, you can see the complete list at the android docs. As such, it may not be good to perform whatever is done in that method when, say, the locale (language) has changed. You can read more about this here.

Also note that the without android:configChanges in your manifest the onConfigurationChanged() method does nothing.

Best of luck!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top