列表适配器中的 Volley Plus OutOfMemoryError

Posted

技术标签:

【中文标题】列表适配器中的 Volley Plus OutOfMemoryError【英文标题】:Volley Plus OutOfMemoryError in List Adapter 【发布时间】:2015-01-28 10:57:15 【问题描述】:

我正在使用Volley Plus 库。我正在显示带有图像和文本视图的 ListView 没有错误,但是当我在此列表视图中上下滚动很多时间时,它会得到 OutOfMemoryError 并使应用程序崩溃。

这里是 LogCat :

java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Try again
        at java.lang.Thread.nativeCreate(Native Method)
        at java.lang.Thread.start(Thread.java:1063)
        at com.android.volley.RequestQueue.start(RequestQueue.java:135)
        at com.android.volley.cache.plus.SimpleImageLoader.newRequestQueue(SimpleImageLoader.java:353)
        at com.android.volley.cache.plus.SimpleImageLoader.<init>(SimpleImageLoader.java:130)
        at com.symnepal.adapter.ProductListAdapter.getView(ProductListAdapter.java:73)
        at android.widget.AbsListView.obtainView(AbsListView.java:2344)
        at android.widget.ListView.makeAndAddView(ListView.java:1864)
        at android.widget.ListView.fillDown(ListView.java:698)
        at android.widget.ListView.fillGap(ListView.java:662)
        at android.widget.AbsListView.trackMotionScroll(AbsListView.java:4968)
        at android.widget.AbsListView.scrollIfNeeded(AbsListView.java:3398)
        at android.widget.AbsListView.onTouchMove(AbsListView.java:3774)
        at android.widget.AbsListView.onTouchEvent(AbsListView.java:3612)
        at android.view.View.dispatchTouchEvent(View.java:8388)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2424)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2158)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2430)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2172)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2430)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2172)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2430)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2172)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2430)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2172)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2430)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2172)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2430)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2172)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2430)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2172)
        at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2314)
        at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1692)
        at android.app.Activity.dispatchTouchEvent(Activity.java:2739)
        at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2275)
        at android.view.View.dispatchPointerEvent(View.java:8578)
        at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4021)
        at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:3887)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3449)
        at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3502)
        at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3468)
        at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3578)
        at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3476)
        at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3635)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3449)
        at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3502)
        at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3468)
        at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3476)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3449)
        at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:5701)
        at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:5675)
        at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:5646)
        at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:5791)
        at android.view.InputEventReceiver.

这是我的适配器类:

public class ProductListAdapter extends BaseAdapter 

private Context mContext;
private List<Products> dataArray;

public ProductListAdapter(Context context, List<Products> d) 
    mContext = context;
    dataArray = d;


@Override
public View getView(final int position, View convertView, ViewGroup parent) 

    View rowView = convertView;
    if (rowView == null) 
        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        rowView = inflater.inflate(R.layout.list_row_item_products, null);

        ViewHolder viewHolder = new ViewHolder();
        viewHolder.title = (TextView) rowView.findViewById(R.id.tvName);
        viewHolder.image = (ImageView) rowView.findViewById(R.id.list_image);

        rowView.setTag(viewHolder);
    

    Products list;
    list = dataArray.get(position);

    ViewHolder holder = (ViewHolder) rowView.getTag();
    holder.title.setText(list.getName());

    DiskLruBasedCache.ImageCacheParams cacheParams = new DiskLruBasedCache.ImageCacheParams(mContext, "CacheDirectory");
    cacheParams.setMemCacheSizePercent(0.5f);
    SimpleImageLoader mImageFetcher = new SimpleImageLoader(mContext, null, cacheParams);
    mImageFetcher.get(list.getThumb(), holder.image);

    return rowView;


static class ViewHolder 
    TextView title;
    ImageView image;


请帮助我摆脱这个问题。

【问题讨论】:

【参考方案1】:

问题是您一直在加载图像,但它们填充的内存在之后没有释放。如果图像是位图,您可以简单地回收行测试,然后在其上调用recycle()。 你可能会使用这样的东西:

if (rowView == null) 
        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        rowView = inflater.inflate(R.layout.list_row_item_products, null);

        ViewHolder viewHolder = new ViewHolder();
        viewHolder.title = (TextView) rowView.findViewById(R.id.tvName);
        viewHolder.image = (ImageView) rowView.findViewById(R.id.list_image);

        rowView.setTag(viewHolder);

else 
    ViewHolder holder = (ViewHolder) rowView.getTag();
    if(holder.image.getDrawable() instanceof BitmapDrawable)
        ((BitmapDrawable) holder.image.getDrawable).getBitmap().recycle();

【讨论】:

【参考方案2】:

您应该在 Activity 的onCreate() 或其他地方创建 SimpleImageLoader

    DiskLruBasedCache.ImageCacheParams cacheParams = new DiskLruBasedCache.ImageCacheParams(mContext, "CacheDirectory");
    cacheParams.setMemCacheSizePercent(0.5f);
    SimpleImageLoader mImageFetcher = new SimpleImageLoader(mContext, null, cacheParams);

如果您仍然面临OOM异常,那么您可以使用NetworkImageView

详细示例见 github sample

【讨论】:

【参考方案3】:

这里是这个问题的解决方案,改变了适配器类。我在其中放置了

    DiskLruBasedCache.ImageCacheParams cacheParams = new DiskLruBasedCache.ImageCacheParams(mContext, "CacheDirectory");
    cacheParams.setMemCacheSizePercent(0.5f);
    SimpleImageLoader mImageFetcher = new SimpleImageLoader(mContext, null, cacheParams);

if (rowView == null) 内部,可防止在 Adabpter 类中重复使用上述代码。

【讨论】:

以上是关于列表适配器中的 Volley Plus OutOfMemoryError的主要内容,如果未能解决你的问题,请参考以下文章

使用 ArrayAdapter 将 volley 响应传递给 listview

另一个 ListView 中的 ListView

Androiid_Volley+Image-Loader+RecyclerView实现网络下载图片瀑布流

Android_Volley+Image-Loader+RecyclerView实现网络下载图片瀑布流

Android_Volley+Image-Loader+RecyclerView实现网络下载图片瀑布流

跪求高手指点!!!SQL plus登不上,出现协议适配器错误。PLSQL Developer可以登录