当我使用数组适配器并更改屏幕方向时,我会出现内存不足的情况。我已经制作了表现出这个问题的最小的完全正常的代码。
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中修复的内容吗?