Volley ImageLoader在滚动时重新加载加载的图像

时间:2016-06-13 15:00:24

标签: android android-recyclerview image-loading

我使用以下代码从RecyclerView中的服务器加载图像:

    imageLoader = CustomVolleyRequest.getInstance(context).getImageLoader();
    imageLoader.get(image_url, ImageLoader.getImageListener(holder.title_img, R.drawable.reads, android.R.drawable.ic_dialog_alert));
    holder.title_img.setImageUrl(image_url, imageLoader);

问题是,当我再次向上滚动时,重新加载已加载的图像..如何避免这种情况......

3 个答案:

答案 0 :(得分:0)

您应该在设备中缓存图片以防止再次加载图片。

创建一个名为LruBitmapCache.java的类并添加以下代码。该类负责在磁盘上缓存网络映像。

LruBitmapCache.java

import com.android.volley.toolbox.ImageLoader.ImageCache;

import android.graphics.Bitmap;
import android.support.v4.util.LruCache;

public class LruBitmapCache extends LruCache<String, Bitmap> implements
        ImageCache {
    public static int getDefaultLruCacheSize() {
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
        final int cacheSize = maxMemory / 8;

        return cacheSize;
    }

    public LruBitmapCache() {
        this(getDefaultLruCacheSize());
    }

    public LruBitmapCache(int sizeInKiloBytes) {
        super(sizeInKiloBytes);
    }

    @Override
    protected int sizeOf(String key, Bitmap value) {
        return value.getRowBytes() * value.getHeight() / 1024;
    }

    @Override
    public Bitmap getBitmap(String url) {
        return get(url);
    }

    @Override
    public void putBitmap(String url, Bitmap bitmap) {
        put(url, bitmap);
    }
}

创建名为AppController.java的类并粘贴以下内容。这是一个单例类,用于初始化所需类的全局实例。与截击相关的所有对象都在此处初始化:

import YourPakageName.LruBitmapCache;
import android.app.Application;
import android.text.TextUtils;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.Volley;

public class AppController extends Application {

    public static final String TAG = AppController.class.getSimpleName();

    private RequestQueue mRequestQueue;
    private ImageLoader mImageLoader;
    LruBitmapCache mLruBitmapCache;

    private static AppController mInstance;

    @Override
    public void onCreate() {
        super.onCreate();
        mInstance = this;
    }

    public static synchronized AppController getInstance() {
        return mInstance;
    }

    public RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            mRequestQueue = Volley.newRequestQueue(getApplicationContext());
        }

        return mRequestQueue;
    }

    public ImageLoader getImageLoader() {
        getRequestQueue();
        if (mImageLoader == null) {
            getLruBitmapCache();
            mImageLoader = new ImageLoader(this.mRequestQueue, mLruBitmapCache);
        }

        return this.mImageLoader;
    }

    public LruBitmapCache getLruBitmapCache() {
        if (mLruBitmapCache == null)
            mLruBitmapCache = new LruBitmapCache();
        return this.mLruBitmapCache;
    }

    public <T> void addToRequestQueue(Request<T> req, String tag) {
        req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
        getRequestQueue().add(req);
    }

    public <T> void addToRequestQueue(Request<T> req) {
        req.setTag(TAG);
        getRequestQueue().add(req);
    }

    public void cancelPendingRequests(Object tag) {
        if (mRequestQueue != null) {
            mRequestQueue.cancelAll(tag);
        }
    }
}

现在打开AndroidManifest.xml文件并在标记中添加Application.java类:

<application
    android:name="YourPakageName.app.AppController"> ....</application>

转到适配器并添加以下代码后:

    private Context context;
        ImageLoader imageLoader = 
YourPakageName.AppController.getInstance().getImageLoader();
        private RequestQueue queue;
        private LruCache<Integer, Bitmap> imageCache;

    public MyCustommAdapter(Context context, int resource, List<YourModel> objects) {
            super(context, resource, objects);
            this.context = context;
            this.postList = objects;
            final int maxMemory = (int)(Runtime.getRuntime().maxMemory() /1024);
            final int cacheSize = maxMemory / 5;
            imageCache = new LruCache<Integer, Bitmap>(cacheSize);

            queue = Volley.newRequestQueue(context);
}

现在您只需获取网址图片并在列表视图中显示:

 imageLoader.get(image_url, new ImageLoader.ImageListener() {

                @Override
                public void onErrorResponse(VolleyError error) {
                    //Log.e(TAG, "Image Load Error: " + error.getMessage());
                }

                @Override
                public void onResponse(ImageLoader.ImageContainer response, boolean arg1) {
                    if (response.getBitmap() != null) {
                        // load image into imageview
                        holder.title_img.setImageBitmap(response.getBitmap());
                    }
                }
            });

答案 1 :(得分:0)

官方文档表明,当需要编写 LruBitmapCache.java 时,图像内存缓存的核心在以下代码片段中:

    final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

    // Use 1/8th of the available memory for this memory cache.
    final int cacheSize = maxMemory / 8;

Android Caching Bitmap documentation 明确指出

注意:在此示例中,为缓存分配了八分之一的应用程序内存。在普通/ hdpi设备上,这至少约为4MB(32/8)。在800x480分辨率的设备上填充图像的全屏GridView将使用大约1.5MB(800 * 480 * 4字节),因此这将在内存中缓存大约2.5页的图像。

我做了一个像Khaled Rostampour建议的小实验:

maxMemory / 5;

但是将maxMemory设置为较低的数字更适合像Facebook应用体验那样流畅的体验。

我已经用这个Facebook-like app做了一个基本的测试,这是一个很好的教程,可以跟随Volley实现Khalid所建议的内容,但是我无法在maxMemory / 8或者或者max来实现理想的平滑性。即使使用maxMemory / 3。

我终于做出了选择:

maxMemory / 2;

猜猜看,这种体验模仿了Facebook应用程序的流畅程度(甚至更好)。

因此,根据您的需要,您可以在应用程序的各个部分中为视图缓存例程分配多少内存。

构建应用程序时要考虑的最后决定因素就像我引用的示例一样是用户体验因素。这是我在Android开发的第3周,我意识到开发人员需要在性能和用户体验之间取得平衡,我发现这是一个很好的设计模式,我相信,即使是我们经常使用的经验证的应用程序也是如此同样的。

答案 2 :(得分:-1)

图片不会从网址重新加载,而是从缓存重新加载。 recyclerview将图像保存在内存中,然后回收&#34;保存记忆的观点。如果您不想回收需要使用的视图,例如ListView而不是RecyclerView。