【问题标题】:WeakReference to a RecyclerView's View never breaks?对 RecyclerView 的视图的弱引用永远不会中断?
【发布时间】:2016-11-17 15:53:56
【问题描述】:

我在我的异步任务中对 recyclerview 的视图有一个弱引用(该任务会加载要在视图中显示的图像)。通常(如果我使用列表视图)视图在它消失时由 gc 收集,因此任务不会使用它,但在我的情况下(使用 recyclerview)视图永远不会被 gc 收集,因此任务还有它的指向视图的弱引用,它现在有一个新角色(要显示的另一个图像)。我该如何解决?我对情况的理解是否正确?

谢谢!

我希望你能理解,虽然英语不是我的母语...

编辑: 这是 AsyncTask 的代码:

class LoadPictureTask extends AsyncTask<String, Void, Bitmap> {
    private final WeakReference<ImageView> mImageViewReference;
    private final int mImageSize;

    LoadPictureTask(ImageView imageView, int imageSize) {
        // Use a WeakReference to ensure the ImageView can be garbage collected
        mImageViewReference = new WeakReference<>(imageView);
        mImageSize = imageSize;
    }

    @Override
    protected Bitmap doInBackground(String... params) {
        String path = params[0];
        return decodeSampledBitmapFromFile(path, mImageSize, mImageSize);
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if (mImageViewReference.get() != null && bitmap != null) {
            final ImageView imageView = mImageViewReference.get();
            if (imageView != null) {
                imageView.setImageBitmap(bitmap);
            }
        }
    }
...
}

我担心在 onPostExecute 中我使用生成的位图(回收的位图)设置了另一个图像视图

【问题讨论】:

  • 在问题中添加您的代码,以便我们实际帮助您
  • 你对你的异步任务中的活动有弱引用吗?如果您在 Activity 中创建 asyncTask,您已经在泄漏内存。文章-medium.com/google-developer-experts/…
  • RecyclerView 复用视图...所以不会被GC回收。

标签: java android android-asynctask garbage-collection android-recyclerview


【解决方案1】:

所以我测试了上面的案例,确实观点的引用被完全滥用了。 AsyncTask 将图像放到错误的视图中,一切都变得一团糟。 我通过从 ViewHolder 保存指向 AsyncTask 的指针解决了这个问题,然后在 onBindViewHolder 中我取消了之前执行的 AsyncTask 并禁用了视图的可见性,直到它被新的 AsyncTask 再次设置为可见。

代码将阐明我的意图:

package com.teamagam.dailyselfie;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;

class PictureAdapter extends RecyclerView.Adapter<PictureAdapter.PictureViewHolder> {
    private LayoutInflater mInflater;
    private List<PictureInfo> mPictureInfoList;

    PictureAdapter(Context context, List<PictureInfo> pictureInfoList) {
        mInflater = LayoutInflater.from(context);
        mPictureInfoList = pictureInfoList;
    }

    @Override
    public PictureViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = mInflater.inflate(R.layout.layout_picture, parent, false);
        return new PictureViewHolder(view);
    }

    @Override
    public void onBindViewHolder(PictureViewHolder pictureViewHolder, int position) {
        PictureInfo pictureInfo = mPictureInfoList.get(position);
        pictureViewHolder.mTextView.setText(pictureInfo.fileName);
        int imageSize = pictureViewHolder.mImageView
                .getContext()
                .getApplicationContext()
                .getResources()
                .getInteger(R.integer.activity_main_thumbnail_size);
        if (null != pictureViewHolder.mLoadPictureTask) {
            pictureViewHolder.mLoadPictureTask.cancel(true);
        }
        pictureViewHolder.mImageView.setVisibility(View.INVISIBLE);
        pictureViewHolder.mLoadPictureTask = new LoadPictureTask(pictureViewHolder.mImageView, imageSize);
        pictureViewHolder.mLoadPictureTask.execute(pictureInfo.path);
    }

    @Override
    public int getItemCount() {
        return mPictureInfoList.size();
    }

    class PictureViewHolder extends RecyclerView.ViewHolder {
        ImageView mImageView;
        TextView mTextView;
        LoadPictureTask mLoadPictureTask;

        PictureViewHolder(View itemView) {
            super(itemView);
            mImageView = (ImageView) itemView.findViewById(R.id.ivItemListImage);
            mTextView = (TextView) itemView.findViewById(R.id.tvItemListImage);
        }
    }
}

当然还有 AsyncTask 的代码:

package com.teamagam.dailyselfie;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.os.AsyncTask;
import android.view.View;
import android.widget.ImageView;

import java.lang.ref.WeakReference;

class LoadPictureTask extends AsyncTask<String, Void, Bitmap> {
    private final WeakReference<ImageView> mImageViewReference;
    private final int mImageSize;

    LoadPictureTask(ImageView imageView, int imageSize) {
        // Use a WeakReference to ensure the ImageView can be garbage collected
        mImageViewReference = new WeakReference<>(imageView);
        mImageSize = imageSize;
    }

    @Override
    protected Bitmap doInBackground(String... params) {
        String path = params[0];
        return decodeSampledBitmapFromFile(path, mImageSize, mImageSize);
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if (mImageViewReference.get() != null && bitmap != null) {
            final ImageView imageView = mImageViewReference.get();
            if (imageView != null) {
                imageView.setImageBitmap(bitmap);
                imageView.setVisibility(View.VISIBLE);
            }
        }
    }

    private static Bitmap decodeSampledBitmapFromFile(String path, int requiredWidth, int requiredHeight) {

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

        // Calculate inSampleSize
        options.inSampleSize = calculateSampleSize(options, requiredWidth, requiredHeight);

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

    private static int calculateSampleSize(Options options, int requiredWidth, int requiredHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int sampleSize = 1;

        if (height > requiredHeight || width > requiredWidth) {

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

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

        return sampleSize;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-01-18
    • 1970-01-01
    • 1970-01-01
    • 2019-12-13
    • 1970-01-01
    • 2016-04-23
    • 2015-01-11
    相关资源
    最近更新 更多