Kindle Fire: утечка PopupMenu$OrientationChangeListener

У меня есть небольшое всплывающее меню, которое привязывается к кнопке на панели действий. Это хорошо работает на вкладках Xoom и Galaxy версии 3.0/3.1, а также на Nexus 7 версии 4.1.

Однако на 7-дюймовом Fire HD (этот), при выходе из приложения получаю ошибку об утечке приемника намерений.Ошибка возникает только в том случае, если во время этого запуска меню не открывалось.

OrientationChangeListener не упоминается в единственная копия источника, которую я нашел; Я подозреваю, что у Amazon другая реализация.

Вопросы:

  • Кто-нибудь сталкивался с этим?
  • Кто-нибудь знает обходной путь или исправление?
  • (Где) я могу найти исходный код Amazon?
  • Наконец, (вздрагиваю), насколько важно, чтобы я не пропустил приемник при выходе из приложения?

Вот xml меню:

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

</menu>

Вот где я его регистрирую:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.main_menu, menu);

    MenuItem login = menu.findItem(R.id.menu_login);
    Button button = (Button) login.getActionView().findViewById(R.id.login);
    button.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            profileMenu.show();
        }
    });


    // profileMenu is an instance field
    profileMenu = new PopupMenu(this, button);
    inflater.inflate(R.menu.profile_menu, profileMenu.getMenu());
    profileMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
        public boolean onMenuItemClick(MenuItem item) {
            // there was code here, but I removed it all and the problem persists
            return false;
        }
    });

    return true;
}

Вот полная трассировка стека:

10-21 20:55:28.461: E/ActivityThread(4526): Activity **.app.ListActivity has leaked IntentReceiver android.widget.PopupMenu$OrientationChangeListener@422d77e0 that was originally registered here. Are you missing a call to unregisterReceiver()? 
10-21 20:55:28.461: E/ActivityThread(4526): android.app.IntentReceiverLeaked: Activity **.app.ListActivity has leaked IntentReceiver android.widget.PopupMenu$OrientationChangeListener@422d77e0 that was originally registered here. Are you missing a call to unregisterReceiver()? 
10-21 20:55:28.461: E/ActivityThread(4526):     at android.app.LoadedApk$ReceiverDispatcher.<init>(LoadedApk.java:826) 
10-21 20:55:28.461: E/ActivityThread(4526):     at android.app.LoadedApk.getReceiverDispatcher(LoadedApk.java:621) 
10-21 20:55:28.461: E/ActivityThread(4526):     at android.app.ContextImpl.registerReceiverInternal(ContextImpl.java:1072) 
10-21 20:55:28.461: E/ActivityThread(4526):     at android.app.ContextImpl.registerReceiver(ContextImpl.java:1059) 
10-21 20:55:28.461: E/ActivityThread(4526):     at android.app.ContextImpl.registerReceiver(ContextImpl.java:1053) 
10-21 20:55:28.461: E/ActivityThread(4526):     at android.content.ContextWrapper.registerReceiver(ContextWrapper.java:357) 
10-21 20:55:28.461: E/ActivityThread(4526):     at android.widget.PopupMenu.<init>(PopupMenu.java:81) 
10-21 20:55:28.461: E/ActivityThread(4526):     at **.app.ListActivity.onCreateOptionsMenu(ListActivity.java:350) 
10-21 20:55:28.461: E/ActivityThread(4526):     at android.app.Activity.onCreatePanelMenu(Activity.java:2558) 
10-21 20:55:28.461: E/ActivityThread(4526):     at com.android.internal.policy.impl.PhoneWindow.preparePanel(PhoneWindow.java:398) 
10-21 20:55:28.461: E/ActivityThread(4526):     at com.android.internal.policy.impl.PhoneWindow.invalidatePanelMenu(PhoneWindow.java:883) 
10-21 20:55:28.461: E/ActivityThread(4526):     at com.android.internal.policy.impl.PhoneWindow$2.run(PhoneWindow.java:3008) 
10-21 20:55:28.461: E/ActivityThread(4526):     at android.os.Handler.handleCallback(Handler.java:605) 
10-21 20:55:28.461: E/ActivityThread(4526):     at android.os.Handler.dispatchMessage(Handler.java:92) 
10-21 20:55:28.461: E/ActivityThread(4526):     at android.os.Looper.loop(Looper.java:137) 
10-21 20:55:28.461: E/ActivityThread(4526):     at android.app.ActivityThread.main(ActivityThread.java:4491) 
10-21 20:55:28.461: E/ActivityThread(4526):     at java.lang.reflect.Method.invokeNative(Native Method) 
10-21 20:55:28.461: E/ActivityThread(4526):     at java.lang.reflect.Method.invoke(Method.java:511) 
10-21 20:55:28.461: E/ActivityThread(4526):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784) 
10-21 20:55:28.461: E/ActivityThread(4526):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) 
10-21 20:55:28.461: E/ActivityThread(4526):     at dalvik.system.NativeStart.main(Native Method)

person dokkaebi    schedule 22.10.2012    source источник


Ответы (1)


Я решил эту конкретную проблему, просто создав PopupMenu при первом нажатии кнопки привязки. Поскольку утечка произошла только при выходе из активности перед отображением меню, я решил, что устранение этого состояния было бы достойным вариантом.

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.main_menu, menu);

    MenuItem login = menu.findItem(R.id.menu_login);
    final Button button = (Button) login.getActionView().findViewById(R.id.login);
    button.setOnClickListener(new View.OnClickListener() {
        public void onClick(View item) {
            if (profileMenu == null) {
                profileMenu = new PopupMenu(ListActivity.this, button);
                inflater.inflate(R.menu.profile_menu, profileMenu.getMenu());
                profileMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
                    public boolean onMenuItemClick(MenuItem item) {
                        // do something with item
                        return false;
                    }
                });
            }
            profileMenu.show();
        }
    });
    return true;
}

Остается один крайний случай, который приводит к утечке окна PopupMenu. Я опубликую это в новом вопросе и вскоре свяжу его здесь. Однако я не думаю, что решу эту проблему, не переписав PopupMenu с нуля.

person dokkaebi    schedule 24.10.2012