6

I started Android development a few weeks ago and went through creating menu in Activity and read up about Activity life cycle. I kept running into this memory leak error when I have the pop up menu open and rotate the device.

I originally had this problem on a bigger project but to make it simple for recreating the problem, one can follow the steps:

  • I create a My Application project in Android Studio, leave it check for Phone and Tablet minimum SDK API 16 -> choose Basic Activity Template -> leave at default (MainActivity and such ...)

  • Without modifying the code, I ran it on my Nexus 5 phone (Android 6.0 installed on device) (screenshot)

  • Click on the setting menu (screenshot) then rotate my phone

  • Then I see this error appeared in the Android Monitor window.

com.example.myapplication E/WindowManager: android.view.WindowLeaked: Activity com.example.myapplication.MainActivity has leaked window android.widget.PopupWindow$PopupDecorView{36b6390 V.E...... ......ID 0,0-588,144} that was originally added here ...

I know this related to the Activity went through onPause(), onStop() and onDestroyed() during the device rotation process and PopupWindow$PopupDecorView did not get closed. In a sense it is similar the question here [PopupMenu PopupWindow$PopupViewContainer leak] (PopupMenu PopupWindow$PopupViewContainer leak) However I can't figure out how to solve it since I don't have a reference to the menu in those life cycle methods to have it dismissed.

My other question is that Should Android be take care of this automatically be cause menu is widely used? I went through several tutorials on how to create menu everybody show how the menu can be created without mentioning the above problem.

Hope somebody can give me the lead to solve this annoying problem or at least how to close down the pop up menu in one of the life cycle method.

MainActivity.java

package com.example.myapplication;

import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show();
        }
    });
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}

@Override
protected void onPause() {
    super.onPause();
}
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>

<android.support.design.widget.AppBarLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:theme="@style/AppTheme.AppBarOverlay">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        app:popupTheme="@style/AppTheme.PopupOverlay" />

</android.support.design.widget.AppBarLayout>

<include layout="@layout/content_main" />

<android.support.design.widget.FloatingActionButton
    android:id="@+id/fab"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom|end"
    android:layout_margin="@dimen/fab_margin"
    app:srcCompat="@android:drawable/ic_dialog_email" />

</android.support.design.widget.CoordinatorLayout>

menu_main.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.example.myapplication.MainActivity">
<item
    android:id="@+id/action_settings"
    android:orderInCategory="100"
    android:title="@string/action_settings"
    app:showAsAction="never" />
</menu>
Community
  • 1
  • 1
Tri Le
  • 61
  • 2

1 Answers1

-5

Add

android:configChanges="orientation|screenSize"

in <activity> tag in manifest file that error will not occur. It works for me try it and let me know.

Mr Lister
  • 45,515
  • 15
  • 108
  • 150
Preetika Kaur
  • 1,991
  • 2
  • 16
  • 23
  • Thanks, I did try it before and the error went away but after research I wonder if it is a good practice since it stopped the life cycle methods being called when rotating. If I have the menu open then change to other app and let the system killed my application then will it still have that error? I think my point here is how to safely handle the pop up to prevent memory leak. – Tri Le Sep 16 '16 at 04:42
  • When you are handling config changes then this is the safe approach and it does not stop life cycle methods as on rotation activity recreates so at that time configuration changes and it just handles memory leakages thats it. – Preetika Kaur Sep 16 '16 at 04:49
  • Ok ill try this later today when i am back and let you know – Tri Le Sep 16 '16 at 05:38
  • 1
    I tried to put `android:configChanges="orientation|screenSize"` that in again in the manifest file and it basically did not call the lifecycle methods onPause(), onStop() and onDestroyed(). The leak came after onDestroyed() is called which is understandable. I noticed the stock Calculator app from Google is has the same leak when rotated. I'll do more investigation on the problem. The link here explained when what to do when configuration change -> [Handling Runtime Changes](https://developer.android.com/guide/topics/resources/runtime-changes.html) – Tri Le Sep 16 '16 at 09:43
  • Still, I could not find a way to gracefully close the open options menu in onPause() or onStop() though – Tri Le Sep 16 '16 at 09:46
  • This is not a good solution. It will stop the log message but cause other problems with your application if a configuration change occurs. Setting configChanges is a very heavyweight change that should not be taken lightly. – Mark Herscher Dec 15 '16 at 20:40
  • @MarkHerscher CAn you tell me how it stops log messages and I amusing the same thing and did not find any problem so far. – Preetika Kaur Dec 16 '16 at 03:45