3

I have a RecyclerView.

<android.support.v7.widget.RecyclerView android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1"/>

I have CardView as a listItem of my RecyclerView

<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
    android:orientation="vertical"
    android:background="@android:color/white"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <com.android.volley.toolbox.NetworkImageView
        android:id="@+id/networkImageView"
        android:adjustViewBounds="true"
        android:scaleType="fitXY"
        android:layout_width="match_parent"
        android:layout_height="130dp"/>
</android.support.v7.widget.CardView>

and in onBindViewHolder of recyclerAdapter I am loading the NetworkImageView with the an image on the network

ImageLoader imageLoader =    RequestUtil.getInstance(_context).getImageLoader();
    String imageUrl = "http://someinterneturl/asdfaas/dsawes.png"; // I get these URL for images from a service.
    networkImageView.setImageUrl(imageUrl,imageLoader);

I have RequestUtil class from where I get my ImageLoader

public class RequestUtil {

private static RequestUtil _instance;
private RequestQueue _requestQueue;
private static Context _ctx;
private ImageLoader _ImageLoader;
private static final String DEFAULT_CACHE_DIR = "volley";
private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 8;

private RequestUtil(Context context) {
    _ctx = context;
}

public static synchronized RequestUtil getInstance(Context context) {
    if(_instance == null) {
        _instance = new RequestUtil(context);
    }

    return _instance;
}

public RequestQueue getRequestQueue() {
    if(_requestQueue == null) {
        //_requestQueue = Volley.newRequestQueue(_ctx.getApplicationContext());
        _requestQueue = getNewRequestQueue();
    }

    return _requestQueue;
}

public <T> void addToRequestQueue(Request<T> request) {
    getRequestQueue().add(request);
}

public ImageLoader getImageLoader() {

    if (_ImageLoader == null) {
        _ImageLoader = new ImageLoader(this.getRequestQueue(),
                new LruBitmapCacheUtil());
    }
    return this._ImageLoader;
}

private RequestQueue getNewRequestQueue(){
    Context context = _ctx.getApplicationContext();
    File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
    HttpStack stack= new HurlStack();
    Network network = new BasicNetwork(stack);
    RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network,DEFAULT_NETWORK_THREAD_POOL_SIZE);
    queue.start();
    return queue;

}

}

This works fine but when I scroll the RecyclerViewList fast then sometimes in one NetworkImageView on the screen the image does not load. I see several below logs in android studio

W/art: Long monitor contention with owner Thread-6 (8925) at com.android.volley.Response com.android.volley.toolbox.ImageRequest.parseNetworkResponse(com.android.volley.NetworkResponse)(ImageRequest.java:124) waiters=5 in com.android.volley.Response com.android.volley.toolbox.ImageRequest.parseNetworkResponse(com.android.volley.NetworkResponse) for 279ms

most of the times I also see the below logs even for this images that were displayed.

D/Volley: [416] BasicNetwork.logSlowRequests: HTTP response for request=<[ ] "http://someinterneturl/asdfaas/dsawes.png" 0xe48e98af LOW 249> [lifetime=10978], [size=867672], [rc=200], [retryCount=2]

Please help me in fixing this problem by loading all the images when the scrolling stops and removing the above two warnings from the log. Let me know if you need more information.

Evgeniy Mishustin
  • 2,858
  • 2
  • 31
  • 68
  • 3
    When the viewholder is recycled, you should cancel the image load if it hasn't started (or finished) yet. When you scroll fast, all the items are requesting an image load and it floods your queue with requests even though many of them no longer need to be shown. – Karakuri Jan 08 '17 at 07:47

3 Answers3

1

I faced the same issue in my previous project and replaced the volley library with Picasso.

It worked like a charm and it have excellent mapping downloaded images to corresponding views and also optimised caching technique.

Refer http://square.github.io/picasso/ for usage and complete tutorial.

Hope it helps.

ChaitanyaAtkuri
  • 1,615
  • 9
  • 15
1

Don't use NetworkImageView. NetworkImageView is a nice shortcut, but its inflexible. By doing the loading yourself, you can take control over the loading of the image via ImageRequest or ImageLoader. For example, if you detect that the recycler view is scrolling rapidly you can stop making requests until it stops. But NetworkImageView was written for the simplest case- it assumes you really want the image and loads it immediately without a cancel. Use it for things where you aren't recycling.

Gabe Sechan
  • 77,740
  • 9
  • 79
  • 113
0

You should prefetch the images in the recyclerview, so that when you scroll fast, the images will appear immediately. There are many ways to do it, but none of them is easy. Glide has example on how to prefetch images in recyclerview: https://github.com/bumptech/glide/tree/master/integration/recyclerview

  • This isn't practical for a recycler view with more than a small number of items. Memory isn't free. Even if you prefetch only to disk, disk space isn't free either. You can prefetch the next few items, but rapid scrolling will outpace the number you can realistically download. – Gabe Sechan Jan 08 '17 at 08:44
  • If you use Glide, it will take care of memory issues. – Abhi Muktheeswarar Jan 08 '17 at 09:44