我有一个FragmentActivity,FragmentMediaOverview
包含MediaItemView
s列表(每个都有一个imageview和一些文本),然后点击其中一个项目打开一个细节片段。
现在当我从列表到细节片段多次返回(通过后退按钮)和向前(单击listitem)时,我最终遇到了OOM-Errors。我使用SoftReference
s作为listitems中的位图以及详细信息片段中的位图。
根据MAT,有MediaItemView
个FragmentMediaOverview
个实例以及null
实例,但我无法弄清楚原因。
我读了这个Android: AlertDialog causes a memory leak,但无法解决它MediaAdapter
听众。
这是我的代码:
FragmentMediaOverview.java
(这不是ListFragment,因为对于平板电脑布局,public class FragmentMediaOverview extends Fragment {
private static String TAG = FragmentMediaOverview.class.getSimpleName();
private MediaAdapter adapter;
private OnMediaSelectedListener selListener;
private ArrayList<BOObject> mediaItems;
private ViewGroup layoutContainer;
private AdapterView itemContainer; // list or gridview
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.d(TAG, "onCreateView");
layoutContainer = (ViewGroup) inflater.inflate(R.layout.fragment_media_overview, null);
return layoutContainer;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
selListener = (OnMediaSelectedListener) activity;
}
@Override
public void onDestroy() {
super.onDestroy();
itemContainer.setOnItemClickListener(null);
selListener = null;
adapter = null;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initUi(layoutContainer);
displayMedia();
}
private void initUi(ViewGroup layoutContainer) {
itemContainer = (AdapterView) layoutContainer.findViewById(android.R.id.list);
itemContainer.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
BOMedia mediaItem = ((BOMedia) mediaItems.get(position));
//the FragmentActivity is coordinating the FragmentTransactions
selListener.onMediaSelected(mediaItem);
}
});
}
private void displayMedia() {
Log.d(TAG, "Displaying List");
if (mediaItems == null) {
loadMedia();
return;
}
Log.d(TAG, "List: " + mediaItems.size() + ", adapter: " + itemContainer.getAdapter());
if (adapter == null) {
Log.d(TAG, "Create Adapter with " + mediaItems.size());
adapter = new MediaAdapter(getActivity(), mediaItems);
}
if (itemContainer.getAdapter() == null) {
itemContainer.setAdapter(adapter);
} else {
adapter.setItems(mediaItems);
adapter.notifyDataSetChanged();
}
}
private void loadMedia() {
FragmentHelper.showProgressSpinner(layoutContainer, android.R.id.list);
DbHelper.getInstance().getMedia(mediaType, new DbQueryFinishListener() {
@Override
public void onDbCallFinish(ArrayList<BOObject> objects) {
if (!getActivity().isFinishing()) {
mediaItems = objects;
Collections.sort(mediaItems, new Comparator<BOObject>() {
final Collator c = Collator.getInstance(Locale.GERMAN);
@Override
public int compare(BOObject s1, BOObject s2) {
if (s2 != null && ((BOMedia) s2).getTitle() != null && s1 != null
&& ((BOMedia) s1).getTitle() != null) {
return c.compare(((BOMedia) s1).getTitle(),((BOMedia) s2).getTitle());
} else {
return 0;
}
}
});
displayMedia();
FragmentHelper.hideProgressSpinner(layoutContainer, android.R.id.list);
}
}
@Override
public void onDbCallException(Exception exception) {
if (!getActivity().isFinishing()) {
FragmentHelper.hideProgressSpinner(layoutContainer, android.R.id.list);
}
}
});
}
}
需要连接到gridview)
public class MediaAdapter extends BaseAdapter {
private static final String TAG = MediaAdapter.class.getSimpleName();
private Context context;
private ArrayList<BOObject> mediaItems;
public MediaAdapter(Context c, ArrayList<BOObject> mediaItems) {
super();
context = c;
this.mediaItems = mediaItems;
}
@Override
public int getCount() {
return mediaItems.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = new MediaItemView(context);
}
((MediaItemView)convertView).initialize((BOMedia) mediaItems.get(position));
return convertView;
}
public void setItems(ArrayList<BOObject> mediaItems) {
this.mediaItems = mediaItems;
}
}
MediaAdapter.java
public class MediaItemView extends LinearLayout {
private static final String TAG = MediaItemView.class.getSimpleName();
private BOMedia item;
private SoftReference<Bitmap> bm;
private ImageView iv;
private Context ctx;
public MediaItemView(Context context) {
super(context);
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
layoutInflater.inflate(R.layout.view_media_item, this);
this.ctx = context;
}
/** Init the view with a new BOMedia object
* @param mediaItem
*/
public void initialize(BOMedia mediaItem) {
this.item = mediaItem;
initUI();
}
private void initUI() {
TextView title = (TextView) findViewById(R.id.itemText);
iv = (ImageView) findViewById(R.id.itemImage);
title.setText(Html.fromHtml(item.getTitle()));
iv.setImageBitmap(null);
bm = null;
System.gc();
iv.invalidate();
if (item.getFilepathThumb() != null && !item.getFilepathThumb().equals("")) {
ExpansionPackManager.getInstance().getBitmapResource(item.getFilepathThumb(), false,
new BitmapReadListener() {
@Override
public void onFileRead(BitmapResponseMessage message) {
Log.d(TAG, "Bitmap read: " + message.getFilepath());
Bitmap image = message.getBitmap();
if (image != null && message.getFilepath().equals(item.getFilepathThumb())) {
bm = new SoftReference<Bitmap>(image);
iv.setImageBitmap(bm.get());
Log.d(TAG, "image set");
} else {
Log.d(TAG, "image too late: " + image);
}
}
@Override
public void onFileException(Throwable exception) {
Log.d(TAG, "image exception");
}
});
}
}
}
MediaItemView.java
{{1}}
答案 0 :(得分:2)
在MediaItemView中,位图的大小必须太大。如果位图为600x600并且您想要显示大小为50x50的图像,则可以使用Bitmap.createScaledBitmap
。您还应该在加载位图时使用位图缓存。
答案 1 :(得分:1)
这是因为当您滚动浏览时,View
中的rach子项的ListView
会重新创建。这对资源非常重。为避免这种情况,请使用适配器getView()
中的holder类来保存和重用视图。这称为Efficient Adapter
。例如,请参阅Efficient List Adapter
中的API demos
。 http://developer.android.com/tools/samples/index.html
答案 2 :(得分:0)
您也可以使用:
android:hardwareAccelerated = true
从Android 3.0 (API level 11)
开始,Android 2D
渲染管道旨在更好地支持硬件加速。硬件加速使用GPU
执行在View画布上执行的所有绘制操作。
了解更多信息http://developer.android.com/guide/topics/graphics/hardware-accel.html