OutOfMemoryError当我使用Recyclerview加载大量图片时

时间:2017-04-18 02:31:13

标签: android android-recyclerview out-of-memory android-glide

Logcat show:报错日志如下

04-18 10:04:04.987 3345-3345/? E/dalvikvm-heap: Out of memory on a 36480012-byte allocation.
04-18 10:04:05.019 3345-3345/? E/InputEventReceiver: Exception dispatching input event.
04-18 10:04:05.023 3345-3345/? E/MessageQueue-JNI: Exception in MessageQueue callback: handleReceiveCallback
04-18 10:04:05.031 3345-3345/? E/MessageQueue-JNI: java.lang.OutOfMemoryError
                       at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
                       at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:503)
                       at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:356)
                       at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:800)
                       at android.content.res.Resources.loadDrawable(Resources.java:2105)
                       at android.content.res.TypedArray.getDrawable(TypedArray.java:601)
                       at android.widget.ImageView.<init>(ImageView.java:127)
                       at android.support.v7.widget.AppCompatImageView.<init>(AppCompatImageView.java:60)
                       at android.support.v7.widget.AppCompatImageView.<init>(AppCompatImageView.java:56)
                       at android.support.v7.app.AppCompatViewInflater.createView(AppCompatViewInflater.java:106)
                       at android.support.v7.app.AppCompatDelegateImplV9.createView(AppCompatDelegateImplV9.java:1021)
                       at android.support.v7.app.AppCompatDelegateImplV9.onCreateView(AppCompatDelegateImplV9.java:1080)
                       at android.support.v4.view.LayoutInflaterCompatHC$FactoryWrapperHC.onCreateView(LayoutInflaterCompatHC.java:47)
                       at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:684)
                       at android.view.LayoutInflater.rInflate(LayoutInflater.java:755)
                       at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
                       at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
                       at com.chad.library.adapter.base.BaseQuickAdapter.getItemView(BaseQuickAdapter.java:1042)
                       at com.chad.library.adapter.base.BaseQuickAdapter.createBaseViewHolder(BaseQuickAdapter.java:674)
                       at com.chad.library.adapter.base.BaseMultiItemQuickAdapter.onCreateDefViewHolder(BaseMultiItemQuickAdapter.java:48)
                       at com.chad.library.adapter.base.BaseQuickAdapter.onCreateViewHolder(BaseQuickAdapter.java:551)
                       at com.chad.library.adapter.base.BaseQuickAdapter.onCreateViewHolder(BaseQuickAdapter.java:57)
                       at android.support.v7.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:6319)
                       at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5507)
                       at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5392)
                       at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5388)
                       at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2149)
                       at android.support.v7.widget.GridLayoutManager.layoutChunk(GridLayoutManager.java:556)
                       at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1496)
                       at android.support.v7.widget.LinearLayoutManager.scrollBy(LinearLayoutManager.java:1313)
                       at android.support.v7.widget.LinearLayoutManager.scrollVerticallyBy(LinearLayoutManager.java:1058)
                       at android.support.v7.widget.GridLayoutManager.scrollVerticallyBy(GridLayoutManager.java:381)
                       at android.support.v7.widget.RecyclerView.scrollByInternal(RecyclerView.java:1680)
                       at android.support.v7.widget.RecyclerView.onGenericMotionEvent(RecyclerView.java:2932)
                       at android.view.View.dispatchGenericMotionEventInternal(View.java:7479)
                       at android.view.View.dispatchGenericMotionEvent(View.java:7460)
                       at android.view.ViewGroup.dispatchTransformedGenericPointerEvent(ViewGroup.java:1819)
                       at android.view.ViewGroup.dispatchGenericPointerEvent(ViewGroup.java:1772)
                       at android.view.View.dispatchGenericMotionEvent(View.java:7453)
                       at android.view.ViewGroup.dispatchTransformedGenericPointerEvent(ViewGroup.java:1819)
                       at android.view.ViewGroup.dispatchGenericPointerEvent(ViewGroup.java:1772)
                       at android.view.View.dispatchGenericMotionEvent(View.java:7453)
                       at android.view.ViewGroup.dispatchTransformedGenericPointerEvent(ViewGroup.java:1819)
                       at android.view.ViewGroup.dispatchGenericPointerEvent(ViewGroup.java:1772)
                       at android.view.View.dispatchGenericMotionEvent(View.java:7453)
                       at android.view.ViewGroup.dispatchTransformedGenericPointerEvent(ViewGroup.java:1819)
                       at android.view.ViewGroup.dispatchGenericPointerEvent(ViewGroup.java:1772)
                       at android.view.View.dispatchGenericMotionEvent(View.java:7453)
                    at android.view.Vie

布局为:A RecyclerView in a Fragment,and the RecyclerView's item is ImageView

Recyclerview的适配器加载内容(我正在使用BaseRecyclerViewAdapterHelper这个框架):

@Override
protected void convert(BaseViewHolder helper, WechatItem.ResultBean.ListBean item) {
    switch (helper.getItemViewType()) {
        case WechatItem.ResultBean.ListBean.STYLE_BIG:
            helper.setText(R.id.title_wechat_style1, TextUtils.isEmpty(item.getTitle()) ? mContext.getString(R.string.wechat_select) : item.getTitle());
            if (!isNotLoad) {           //Controls whether the image is loaded
                Glide.with(mContext.getApplicationContext())
                        .load(item.getFirstImg())
                        .override(mImgWidth, mImgHeight)
                        .placeholder(R.drawable.lodingview)
                        .error(R.drawable.errorview)
                        .crossFade(1000)
                        .into((ImageView) helper.getView(R.id.img_wechat_style));
            }
            break;
        case WechatItem.ResultBean.ListBean.STYLE_SMALL:
            helper.setText(R.id.title_wechat_style2, TextUtils.isEmpty(item.getTitle()) ? mContext.getString(R.string.wechat_select) : item.getTitle());
            if (!isNotLoad) {
                Glide.with(mContext.getApplicationContext())
                        .load(item.getFirstImg())
                        .placeholder(R.drawable.lodingview)
                        .error(R.drawable.errorview)
                        .override(mImgWidth / 2, mImgWidth / 2)
                        .crossFade(1000)
                        .into((ImageView) helper.getView(R.id.img_wechat_style));
            }
            break;
        default:
            break;
    }
}

当手机内存很大,并且不会出现OOM时,当手机内存很小时,很容易出现OOM。 当手机内存较大时,并不会出现OOM,当手机内存较小时,很容易出现OOM。

2 个答案:

答案 0 :(得分:1)

Log可以清楚地看出,您正在尝试分配比手机更多的字节数。尝试仅在RecyclerView中显示(低质量)缩略图。当用户点击RecyclerView项目时,您可以显示高分辨率图像。

您可以使用以下代码将图片缩小到所需的widthheight

public static Bitmap decodeSampledBitmap(String filePath, int reqWidth, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(filePath, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    Bitmap scaled = BitmapFactory.decodeFile(filePath, options);
    return scaled;
}

public static int calculateInSampleSize(
        BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        final int halfHeight = height / 2;
        final int halfWidth = width / 2;

        // Calculate the largest inSampleSize value that is a power of 2 and keeps both
        // height and width larger than the requested height and width.
        while ((halfHeight / inSampleSize) > reqHeight
                && (halfWidth / inSampleSize) > reqWidth) {
            inSampleSize *= 2;
        }
    }

    return inSampleSize;
}

使用功能decodeSampledBitmap缩小图像。

答案 1 :(得分:1)

尝试为您的应用程序分配大内存,您可以在manifest.xml文件中的应用程序标记上添加android:largeHeap="true"