RecyclerView Lazy Loading (Universal Image Loader)

谁说胖子不能爱 提交于 2020-01-02 04:53:05

问题


Using Android Universal Image Loader and RecyclerView to asynchronously load images, I'm getting the same error as other people, where the images get mixed up; until they have all loaded an are cached.

Code for the adapter:

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.media.Image;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.TextView;

import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
import com.nostra13.universalimageloader.utils.MemoryCacheUtils;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import romina.theftest.connectivity.ImgDownloader;

/**
 * Created by romin on 18/1/2016.
 */
public class ProductRecyclerViewAdapter extends RecyclerView.Adapter {
    private List<Product> mValues;
    private Context mContext;
    private View.OnClickListener mListener;
    // Allows to remember the last item shown on screen
    private int lastPosition = -1;
    private final String OLD_DOMAIN = "";
    private final String NEW_DOMAIN = "";

    public ProductRecyclerViewAdapter(Context mContext, View.OnClickListener mListener) {
        this.mContext = mContext;
        this.mListener = mListener;
    }

    public ProductRecyclerViewAdapter(List<Product> mValues, Context mContext, View.OnClickListener mListener) {
        this(mContext, mListener);
        this.mListener = mListener;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.product_list_item, parent, false);

        Log.d(ProductRecyclerViewAdapter.class.getSimpleName(), "onCreateViewHolder");
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        ViewHolder actualViewHolder = (ViewHolder) holder;
        actualViewHolder.mItem = mValues.get(position);
        actualViewHolder.mIdView.setText("" + mValues.get(position).getName());
        Log.d(ProductRecyclerViewAdapter.class.getSimpleName(), "onBindViewHolder pos " + position);

        ImageLoader imageLoader = ImageLoader.getInstance(); // Get singleton instance
        final String finalImgURL = mValues.get(position).getImgURL().toString().replaceAll(OLD_DOMAIN, NEW_DOMAIN);
            imageLoader.displayImage(finalImgURL, actualViewHolder.mImgView);

        setAnimation(actualViewHolder.mContentView, position);
    }

    public void setDataSet(List<Product> newValues) {
        mValues = newValues;
        notifyDataSetChanged();
    }


    @Override
    public int getItemCount() {
        return mValues == null ? 0 : mValues.size();
    }

    /**
     * Here is the key method to apply the animation
     */
    private void setAnimation(View viewToAnimate, int position) {
        // If the bound view wasn't previously displayed on screen, it's animated
        if (position > lastPosition) {
            Animation animation = AnimationUtils.loadAnimation(mContext, android.R.anim.slide_in_left);
            viewToAnimate.startAnimation(animation);
            lastPosition = position;
        }
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        public final View mView;
        public final TextView mIdView;
        public final ImageView mImgView;
        public final TextView mContentView;
        public Product mItem;

        public ViewHolder(View view) {
            super(view);
            mView = view;
            mIdView = (TextView) view.findViewById(R.id.product_quantity_title);
            mContentView = (TextView) view.findViewById(R.id.product_quantity_title);
            mImgView = (ImageView) view.findViewById(R.id.product_quantity_image);

            mView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (null != mListener) {
                        mListener.onClick(v);
                    }
                }
            });
        }

        @Override
        public String toString() {
            return super.toString() + " '" + mContentView.getText() + "'";
        }
    }
}

I know it has to be something in onBindViewHolder , since it's called for updating every view but I'm not updating the ImageView properly.

It doesn't have to do with the library. The same behaviour was happening when doing lazy loading without caching the images. The error is because I don't know how to update the ImageView in onBindViewHolder .

Thanks!


回答1:


You need to make sure you init the ImageLoader only once in the App. Create a class and extend it with Application and then put in the AndroidManifest.xml like:

<application
        android:name=".App"
.../>

Application class

public class App extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        // UNIVERSAL IMAGE LOADER SETUP
        DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()
                .resetViewBeforeLoading(true)
                .cacheOnDisk(true)
                .cacheInMemory(true)
                .imageScaleType(ImageScaleType.EXACTLY)
                .displayer(new FadeInBitmapDisplayer(300))
                .build();

        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
                .defaultDisplayImageOptions(defaultOptions)
                .memoryCache(new WeakMemoryCache())
                .diskCacheSize(100 * 1024 * 1024)
                .build();

        ImageLoader.getInstance().init(config);
        // END - UNIVERSAL IMAGE LOADER SETUP
    }
}

For onBindViewHolder which you want to know:

@Override
public void onBindViewHolder(final CategoryHolder holder, final int i) {

    holder.categoryImage.setImageBitmap(null);

    if (mRow.get(i).getImage() != null && !mRow.get(i).getImage().equals("")) {
        final File image = DiskCacheUtils.findInCache(mRow.get(i).getImage(), imageLoader.getDiskCache());
        if (image!= null && image.exists()) {
            Picasso.with(getActivity()).load(image).fit().centerCrop().into(holder.categoryImage);
        } else {
            imageLoader.loadImage(mRow.get(i).getImage(), new ImageLoadingListener() {
                @Override
                public void onLoadingStarted(String s, View view) {
                    holder.categoryImage.setImageBitmap(null);
                }

                @Override
                public void onLoadingFailed(String s, View view, FailReason failReason) {

                }

                @Override
                public void onLoadingComplete(String s, View view, final Bitmap bitmap) {
                    Picasso.with(getActivity()).load(s).fit().centerCrop().into(holder.categoryImage);

                }

                @Override
                public void onLoadingCancelled(String s, View view) {

                }
            });
        }
    }else {
        holder.categoryImage.setImageBitmap(null);
    }

    holder.categoryName.setText(mRow.get(i).getName().toUpperCase());

}



回答2:


I believe the error is due to multiple instances of image loader:

ImageLoader imageLoader = ImageLoader.getInstance(); 

Try creating a single instance of the same for the adapter. Declare it with other class variables. You are creating multiple instances of image loader by calling it in onBindViewHolder().



来源:https://stackoverflow.com/questions/34866965/recyclerview-lazy-loading-universal-image-loader

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!