你如何清理ArrayAdapter?

时间:2012-01-04 19:13:50

标签: android out-of-memory android-arrayadapter

当我使用数组适配器并更改屏幕方向时,我会出现内存不足的情况。我已经制作了表现出这个问题的最小的完全正常的代码。

package com.foobar.test;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class TestAppActivity extends Activity {
    protected ArrayList<ListItem> mModel = new ArrayList<ListItem>();
    protected ListAdapter mAdapter = null;
    private static Context mApplicationContext = null;

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

        System.gc();
        setContentView(R.layout.main);

        if (mApplicationContext == null) { mApplicationContext = getApplicationContext(); }

        ListView lv = (ListView) findViewById(R.id.ListList);
        lv.setItemsCanFocus(true);
        mAdapter = new ListAdapter(mApplicationContext, lv, mModel);
        lv.setAdapter(mAdapter);

        if (savedInstanceState == null) {
            Log.i("test", "@@ start");
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        boolean change = true;
                        Thread.sleep(4 * 1000);
                        for (int ii = 0; ii < 200; ii++) {
                            setRequestedOrientation(change ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                            Thread.sleep(4 * 1000);
                            change = !change;
                            Log.i("test", "@@ change: " + (ii+1));
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        Log.i("test", "@@ complete!");
                    }
                }
            }).start();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

// doesn't make any difference.
//        ListView lv = (ListView) findViewById(R.id.ListList);
//        lv.setAdapter(null);
//        adapter.clear();
//        adapter = null;

        unbindDrawables(findViewById(R.id.ListList));
        System.gc();
    }

    private void unbindDrawables(View view) {
        if (view == null) { return; }
        if (view.getBackground() != null) { view.getBackground().setCallback(null); }

        if (view instanceof ViewGroup) {
            for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) { unbindDrawables(((ViewGroup) view).getChildAt(i)); }
            if (!(view instanceof AdapterView)) { ((ViewGroup) view).removeAllViews(); }
        }
    }

    public static class ListItem {
        public int placeholder;
    }

    public static class ListAdapter extends ArrayAdapter<ListItem> implements View.OnClickListener {
        public ListAdapter(Context context, ListView lv, List<ListItem> model) {
            super(context, android.R.layout.simple_list_item_1, model);
        }

        @Override
        public void onClick(View v) { }
    }
}

大约70左右的方向变化后,我得到一个内存不足错误(因为我有一个特别大的背景图像)。我的XML看起来像这样:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:background="@drawable/background">

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />

    <ListView
        android:id="@+id/ListList"
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:choiceMode="singleChoice"
        android:cacheColorHint="#00000000"
        android:dividerHeight="3dp"
        android:overScrollFooter="@null" />

</LinearLayout>

我的简单背景如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="50dp"
    android:orientation="horizontal">
</LinearLayout>

这让我疯狂,因为这非常简单,看起来这应该有用;这是适配器代码中的错误吗?

TIA。


我更简化了我的代码就是这样:

package com.foobar.test;

import java.util.ArrayList;

import android.app.Activity;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;

public class TestAppActivity extends Activity {
    protected ArrayList<ListItem> mModel = new ArrayList<ListItem>();
    protected ListAdapter mAdapter = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        ListView lv = (ListView) findViewById(R.id.ListList);
        lv.setItemsCanFocus(true);
        mAdapter = new ListAdapter(this, lv, mModel);
        lv.setAdapter(mAdapter);

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        View root = findViewById(R.id.RootView);
        ((BitmapDrawable) root.getBackground()).getBitmap().recycle();

        // this doesn't seem to have any affect.
        ListView lv = (ListView) findViewById(R.id.ListList);
        lv.setAdapter(null);
        mAdapter.clear();
        mAdapter = null;

        unbindDrawables(root);
        System.gc();
    }

    private void unbindDrawables(View view) {
        if (view == null) { return; }
        if (view.getBackground() != null) { view.getBackground().setCallback(null); }

        if (view instanceof ViewGroup) {
            for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) { unbindDrawables(((ViewGroup) view).getChildAt(i)); }
            if (!(view instanceof AdapterView)) { ((ViewGroup) view).removeAllViews(); }
        }
    }

}

如果我运行该代码,然后手动更改屏幕方向20次,然后查看Eclipse Memory Analyzer Tool,它会显示20个我的活动实例。

有趣的是,如果我在3.x设备上执行此操作,我就没有这个问题 - 我猜这是在Honeycomb中修复的内容吗?

0 个答案:

没有答案