RecyclerView disappearing images

北城以北 提交于 2019-12-04 04:26:18
Clive Jefferies

The one class that I did not think would matter was the one that was causing the issue. I am not sure what the reason is, but it resides in a custom ImageView class that I am using for recycling that I got from the BitmapFun sample.

    public class RecyclingImageView extends ImageView {

    public RecyclingImageView(Context context) {
        super(context);
    }

    public RecyclingImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     * @see android.widget.ImageView#onAttachedToWindow()
     */
    @Override
    protected void onAttachedToWindow() {}

    /**
     * @see android.widget.ImageView#onDetachedFromWindow()
     */
    @Override
    protected void onDetachedFromWindow() {
        // This has been detached from Window, so clear the drawable

        setImageDrawable(null); 

        super.onDetachedFromWindow();
    }

    /**
     * @see android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable)
     */
    @Override
    public void setImageDrawable(Drawable drawable) {
        // Keep hold of previous Drawable
        final Drawable previousDrawable = getDrawable();

        // Call super to set new Drawable
        super.setImageDrawable(drawable);

        // Notify new Drawable that it is being displayed
        notifyDrawable(drawable, true);

        // Notify old Drawable so it is no longer being displayed
        notifyDrawable(previousDrawable, false);
    }

    /**
     * Notifies the drawable that it's displayed state has changed.
     *
     * @param drawable
     * @param isDisplayed
     */
    private static void notifyDrawable(Drawable drawable, final boolean isDisplayed) {
        if (drawable instanceof RecyclingBitmapDrawable) {
            // The drawable is a CountingBitmapDrawable, so notify it
            ((RecyclingBitmapDrawable) drawable).setIsDisplayed(isDisplayed);
        } else if (drawable instanceof LayerDrawable) {
            // The drawable is a LayerDrawable, so recurse on each layer
            LayerDrawable layerDrawable = (LayerDrawable) drawable;
            for (int i = 0, z = layerDrawable.getNumberOfLayers(); i < z; i++) {
                notifyDrawable(layerDrawable.getDrawable(i), isDisplayed);
            }
        }
    }

}

When I replace this with a normal ImageView, I no longer get the problem.

Would it be possible to test something out? Could you use this library to load the images from the URLs ? http://square.github.io/picasso/ It caches everything and it handles everything in an async manner.

Use it something like ...

@Override
public void onBindViewHolder(ViewHolder holder, int position) {

    Picasso.with(mImageView.getContext()).cancelRequest(holder.mImageView);

    String url = mDataset[position];
    Picasso.with(mImageView.getContext()).load(url).placeholder(R.drawable.placeholder).into(holder.mImageView);

}

... and see if it still doesn't display some images. If it does, then at least you'll be 100% sure the problem is not in your downloading mechanism (which I think it might be).

If you're using Android Studio then just add the dependency compile 'com.squareup.picasso:picasso:2.5.2', if not you can add the library you find at the above link.

It's worth a try ...

We can fix the issue by extends LinearLayoutManager and ImageView.

1. Creats a PrecachingLinearLayoutManager

public class PrecachingLinearLayoutManager extends LinearLayoutManager {

    private static final int DEFAULT_EXTRA_LAYOUT_SPACE = 600;

    private int extraLayoutSpace = -1;

    @SuppressWarnings("unused")
    private Context mContext;

    public PrecachingLinearLayoutManager(Context context) {
        super(context);
        this.mContext = context;
    }

    public PrecachingLinearLayoutManager(Context context, int extraLayoutSpace) {
        super(context);
        this.mContext = context;
        this.extraLayoutSpace = extraLayoutSpace;
    }

    public PrecachingLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
        super(context, orientation, reverseLayout);
        this.mContext = context;
    }

    public void setExtraLayoutSpace(int extraLayoutSpace) {
        this.extraLayoutSpace = extraLayoutSpace;
    }

    @Override
    protected int getExtraLayoutSpace(RecyclerView.State state) {
        if (extraLayoutSpace > 0) {
            return (extraLayoutSpace);
        }
        return (DEFAULT_EXTRA_LAYOUT_SPACE);
    }
}

2. Use PrecachingLinearLayoutManager to replace LinearLayoutManager

    DisplayMetrics displayMetrics = new DisplayMetrics();
    getActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
    PrecachingLinearLayoutManager layout = new PrecachingLinearLayoutManager(getActivity());
    layout.setExtraLayoutSpace(displayMetrics.heightPixels);
    recyclerview.setLayoutManager(layout);

3. Creats a RecycleImageView

private Object tag = null;

@Override
protected void onAttachedToWindow() {
    Object tag = getTag();
    if (tag == null || !tag.equals(this.tag)) {
        // Will cause displayed bitmap wrapper to 
        // be 'free-able'
        setImageDrawable(null);
        this.tag = null;
        super.onDetachedFromWindow();
    }
    super.onAttachedToWindow();
}

@Override
protected void onDetachedFromWindow() {
    Object tag = getTag();
    if (tag != null) {
        this.tag = tag;
    } else {
        // Will cause displayed bitmap wrapper to 
        // be 'free-able'
        setImageDrawable(null);
        this.tag = null;
        super.onDetachedFromWindow();
    }
}

4. Use RecycleImageView to replace ImageView

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:extends="http://schemas.android.com/apk/res/com.yourdomain.yourpackage"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/viewgroup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<com.yourdomain.yourpackage.RecycleImageView
    android:id="@+id/photo"
    android:layout_width="40dp"
    android:layout_height="40dp"
    extends:delayable="true"
    android:contentDescription="@string/nothing"
    android:src="@drawable/photo_placeholder" >
</com.yourdomain.yourpackage.RecycleImageView>
</LinearLayout>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!