我有一个包含很多行的ListView。每行包含文本和图像。
我扩展了BaseAdapter
以创建一个ListAdapter,用于加载Picasso的图像。
她是我的ListAdapter:
public class ServiceCardDtoListAdapter extends BaseAdapter {
...
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return createViewFromResource(position, convertView, parent, mResource);
}
private View createViewFromResource(int position, View convertView, ViewGroup parent,
int resource) {
RoundedImageView imageView = null;
TextView title = null;
TextView location = null;
if (convertView == null) {
convertView = inflater.inflate(resource, parent, false);
}
try {
imageView = (RoundedImageView)convertView.findViewById(R.id.service_card_imageview);
title = (TextView)convertView.findViewById(R.id.service_card_title);
location = (TextView)convertView.findViewById(R.id.service_card_location);
}
catch (Exception e) {
Log.e("ServiceCardDtoListAdapter", "Cannot create view resource IDs are missing", e);
}
// get the correct service_card
ServiceCardDto item = items.get(position);
// fill the view
Picasso.with(context)
.load(item.getImageUrls().get(0))
.placeholder(R.drawable.card_image)
.error(R.drawable.card_image)
.centerCrop()
.fit()
.into(imageView);
title.setText(item.getTitle());
location.setText(item.getCompanyName());
return convertView;
}
}
以下是完整的课程:https://gist.github.com/confile/a6ed64bde15aca44fd06
当向下滚动列表时,我收到很多内存警告,在几张图片后我的列表崩溃了。这是我得到的错误:
10-07 02:41:07.724 4482-4482/? I/art: Clamp target GC heap from 67MB to 64MB
10-07 02:41:07.724 4482-4482/? I/art: Alloc concurrent mark sweep GC freed 3(96B) AllocSpace objects, 0(0B) LOS objects, 1% free, 63MB/64MB, paused 546us total 11.300ms
10-07 02:41:07.724 4482-4482/? E/art: Throwing OutOfMemoryError "Failed to allocate a 15321612 byte allocation with 678832 free bytes and 662KB until OOM"
10-07 02:41:07.724 4482-4482/? D/skia: --- allocation failed for scaled bitmap
10-07 02:41:07.724 4482-4482/? D/AndroidRuntime: Shutting down VM
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: FATAL EXCEPTION: main
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: Process: com.lorentzos.swipecards.example, PID: 4482
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: java.lang.OutOfMemoryError: Failed to allocate a 15321612 byte allocation with 678832 free bytes and 662KB until OOM
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:609)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:444)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:988)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at android.content.res.Resources.loadDrawableForCookie(Resources.java:2474)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at android.content.res.Resources.loadDrawable(Resources.java:2381)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at android.content.res.Resources.getDrawable(Resources.java:787)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at android.content.res.Resources.getDrawable(Resources.java:752)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at com.squareup.picasso.RequestCreator.getPlaceholderDrawable(RequestCreator.java:676)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at com.squareup.picasso.RequestCreator.into(RequestCreator.java:637)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at com.squareup.picasso.RequestCreator.into(RequestCreator.java:601)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at com.lorentzos.swipecards.ServiceCardDtoListAdapter.createViewFromResource(ServiceCardDtoListAdapter.java:84)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at com.lorentzos.swipecards.ServiceCardDtoListAdapter.getView(ServiceCardDtoListAdapter.java:57)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at com.lorentzos.flingswipe.SwipeFlingAdapterView.layoutChildren(SwipeFlingAdapterView.java:158)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at com.lorentzos.flingswipe.SwipeFlingAdapterView.refresh(SwipeFlingAdapterView.java:149)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at com.lorentzos.swipecards.MyActivity$1.onTabSelected(MyActivity.java:78)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at android.support.design.widget.TabLayout.selectTab(TabLayout.java:837)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at android.support.design.widget.TabLayout.selectTab(TabLayout.java:809)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at android.support.design.widget.TabLayout$Tab.select(TabLayout.java:1077)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at android.support.design.widget.TabLayout$1.onClick(TabLayout.java:643)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at android.view.View.performClick(View.java:4780)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at android.view.View$PerformClick.run(View.java:19866)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:739)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:95)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at android.os.Looper.loop(Looper.java:135)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:5257)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at java.lang.reflect.Method.invoke(Method.java:372)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
10-07 02:41:07.725 4482-4482/? E/AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
如何有效地回收ImageView以防止内存泄漏?
答案 0 :(得分:1)
我相信您的问题出在placeholderImage
。您应该检查R.drawable.card_image
的大小。尝试删除占位符并运行一些测试。
关于优化
好吧,为了有效地回收列表并使用新的材料标准,您应该使用RecyclerView。 RecyclerView的核心是模块化和优化。它非常流畅和可扩展。
但这并不意味着您无法优化列表视图。您可以实施 ViewHolder pattern 。你肯定会得到一些记忆。 代码取自Android ViewHolder Pattern Example
// ViewHolder.
static class ViewHolderItem {
TextView textViewItem;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolderItem viewHolder;
// The convertView argument is essentially a "ScrapView" as described is Lucas post
// http://lucasr.org/2012/04/05/performance-tips-for-androids-listview/
// It will have a non-null value when ListView is asking you recycle the row layout.
// So, when convertView is not null, you should simply update its contents instead of inflating a new row layout.
if(convertView==null){
// inflate the layout
LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
convertView = inflater.inflate(layoutResourceId, parent, false);
// well set up the ViewHolder
viewHolder = new ViewHolderItem();
viewHolder.textViewItem = (TextView) convertView.findViewById(R.id.textViewItem);
// store the holder with the view.
convertView.setTag(viewHolder);
}else{
// we've just avoided calling findViewById() on resource everytime
// just use the viewHolder
viewHolder = (ViewHolderItem) convertView.getTag();
}
// object item based on the position
ObjectItem objectItem = data[position];
// assign values if the object is not null
if(objectItem != null) {
// get the TextView from the ViewHolder and then set the text (item name) and tag (item ID) values
viewHolder.textViewItem.setText(objectItem.itemName);
viewHolder.textViewItem.setTag(objectItem.itemId);
}
return convertView;
}
您还应该记住,Android应用程序通常没有太多可用资源。也就是说,您应该始终考虑图像的最终尺寸。始终避免加载大于您需要的图像。 如果您的应用程序将消耗更多内存,那么通常的应用程序可以考虑使用largeHeap
在清单中请求更多资源。 Documentation