Android内存泄漏使用ActionBar和Spinner导航

时间:2012-02-13 23:05:18

标签: android memory-leaks android-fragments android-4.0-ice-cream-sandwich

我的代码在方向更改时出现大量内存泄漏。旋转手机一到两次后堆已满。我试图追踪泄漏两天,但没有成功。

该应用程序使用SDK 15(分14)。

MainActivity显示带有列表导航(NAVIGATION_MODE_LIST)的ActionBar。导航微调器会替换显示的片段。

代码有效。

ListNavigationItem,其中包含实例化片段所需的信息:

public class ListNavigationItem
{
    public final String fragmentClass;
    public final String title; // Used as fragment tag and as title

    public ListNavigationItem(String fragmentClass, String title)
    {
        this.fragmentClass = fragmentClass;
        this.title = title;
    }

    @Override
    public String toString()
    {
        return title;
    }
}

最后我的(简体)MainActivity

public class MainActivity extends Activity implements OnNavigationListener
{
    private MyApplication app;
    private ArrayAdapter<ListNavigationItem> adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        app = (MyApplication) getApplicationContext();

        ActionBar actionBar = getActionBar();
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
        actionBar.setDisplayShowTitleEnabled(false);
        actionBar.setDisplayShowHomeEnabled(false);

        adapter = new ArrayAdapter<ListNavigationItem>(this, android.R.layout.simple_spinner_dropdown_item);
        adapter.add(new ListNavigationItem(FirstFragment.class.getName(), "First"));
        adapter.add(new ListNavigationItem(SecondFragment.class.getName(), "Second"));

        actionBar.setListNavigationCallbacks(adapter, this);
    }

    public boolean onNavigationItemSelected(int itemPosition, long itemId)
    {
        ListNavigationItem item = adapter.getItem(itemPosition);
        if (item == null)
            return false;

        Fragment f = getFragmentManager().findFragmentByTag(item.title);

        if (f == null)
            f = Fragment.instantiate(this, item.fragmentClass);
        else if (f.isAdded())
            return true;

        FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
        fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
        fragmentTransaction.replace(R.id.main_content, f, item.title);
        fragmentTransaction.commit();

        return true;
    }

    @Override
    protected void onDestroy()
    {
        adapter = null; // Do I need this?
        app = null;
        super.onDestroy();
    }
}

清单:

<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="at.company.app"
    android:versionCode="1"
    android:versionName="1.0">

    <uses-sdk android:minSdkVersion="14" />
    <uses-sdk android:targetSdkVersion="15" />

    <application
        android:name=".Application"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name">

        <activity
            android:name=".MainActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>

</manifest>

MAT堆分析表明类android.content.res.Resources占可用内存的57%,而android.graphics.Bitmap占12%。但是,我的片段只包含一个简单的TextView

MAT直方图显示MainActivity有4个对象(实例,我假设?)。此外,logcat显示在更改方向(GC_CONCURRENT)后,堆经常被清空。

官方开发指南不鼓励使用android:configChanges="orientation"。 (Source

我对Java和Android平台相对较新,我将不胜感激。

3 个答案:

答案 0 :(得分:0)

这将取决于你的清单配置,但测试你可以完成onConfigurationChanged ..否则它只会创建一个新的活动而不会破坏旧的活动..

答案 1 :(得分:0)

我不知道为什么,如何,或者这是否是我的问题。但是,当我删除片段事务的setTransition时,我似乎停止获取“增长堆”输出。试试吧?

答案 2 :(得分:0)

内存泄漏的常见原因是在上下文引用中引用Activity而不是Application。使用this(例如adapter = new ArrayAdapter<ListNavigationItem>(this)可能导致内存泄漏,如question中所述,因此请尝试将其替换为getApplicationContext()以引用Application而不是上下文。