Reputation: 161
I have been trying to figure out this issue for two days now and I am completly stumped. For some reason I am sending one request to the queue but volley is returning it twice, which is calling the listener twice and doubling the results in my listview. I turned on the logging for Volley and I can see the request being added to the queue and returned, then a few seconds later the same request is also returned. Log below
V/Volley(14666): [188] CacheDispatcher.run: start new dispatcher
11-15 12:29:30.152: V/Volley(14666): [1] RequestQueue.add: Request for cacheKey=http://reallylongurl is in flight, putting on hold.
11-15 12:29:39.722: V/Volley(14666): [1] RequestQueue.finish: Releasing 1 waiting requests for cacheKey=http://reallylongurl.
11-15 12:29:39.722: D/Volley(14666): [1] MarkerLog.finish: (9809 ms) [ ] http://reallylongurl 0xd68d6603 NORMAL 1
11-15 12:29:39.732: D/Volley(14666): [1] MarkerLog.finish: (+0 ) [ 1] add-to-queue
11-15 12:29:39.732: D/Volley(14666): [1] MarkerLog.finish: (+2169) [188] cache-queue-take
11-15 12:29:39.742: D/Volley(14666): [1] MarkerLog.finish: (+37 ) [188] cache-hit
11-15 12:29:39.742: D/Volley(14666): [1] MarkerLog.finish: (+6878) [188] cache-hit-parsed
11-15 12:29:39.742: D/Volley(14666): [1] MarkerLog.finish: (+0 ) [188] post-response
11-15 12:29:39.752: D/Volley(14666): [1] MarkerLog.finish: (+725 ) [ 1] done
A few other requests get queued here.
11-15 12:29:48.405: D/Volley(14666): [1] MarkerLog.finish: (18302 ms) [ ] http://reallylongurl 0xd68d6603 NORMAL 2
11-15 12:29:48.412: D/Volley(14666): [1] MarkerLog.finish: (+0 ) [ 1] add-to-queue
11-15 12:29:48.412: D/Volley(14666): [1] MarkerLog.finish: (+15164) [188] cache-queue-take
11-15 12:29:48.412: D/Volley(14666): [1] MarkerLog.finish: (+220 ) [188] cache-hit
11-15 12:29:48.432: D/Volley(14666): [1] MarkerLog.finish: (+2299) [188] cache-hit-parsed
11-15 12:29:48.432: D/Volley(14666): [1] MarkerLog.finish: (+0 ) [188] post-response
11-15 12:29:48.442: D/Volley(14666): [1] MarkerLog.finish: (+619 ) [ 1] done
As you can see it never says another request was added nor does it say more then one request was in flight. If I clear out the cache I get the same result, just the first request is from network and the second is returned from cache. I have tried debugging and stepping through my code but I never see the request being enqueued more then once. Has anyone seen this before? Any where else I should look?
Thanks
Edit: Here is the code where I start up volley and where I call it.
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState == null) {
TextView emptyView = new TextView(getActivity());
emptyView.setLayoutParams(new LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
emptyView.setText("Loading....");
emptyView.setTextSize(20);
emptyView.setGravity(Gravity.CENTER_VERTICAL
| Gravity.CENTER_HORIZONTAL);
((ViewGroup) mListView.getParent()).addView(emptyView);
mListView.setEmptyView(emptyView);
}
mAdapter = new OttoArrayAdapter(mContext);
mListView.setOnScrollListener(onScrollListener);
mListView.setAdapter(mAdapter);
String url = Util.getURL("", mContext);
HttpRequest request = new HttpRequest(url);
request.setTag(mContext);
VolleyLoader.getInstance(mContext).getRequestQueue().add(request);
}
public class VolleyLoader {
private static VolleyLoader mInstance = null;
private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;
private VolleyLoader(Context context) {
OkHttpStack stack = new OkHttpStack();
mRequestQueue = Volley.newRequestQueue(context, stack);
mImageLoader = new ImageLoader(this.mRequestQueue, new LruBitmapCache(
Util.getCacheSize(context)));
}
public static VolleyLoader getInstance(Context context) {
if (mInstance == null) {
mInstance = new VolleyLoader(context);
}
return mInstance;
}
public RequestQueue getRequestQueue() {
return this.mRequestQueue;
}
public ImageLoader getImageLoader() {
return this.mImageLoader;
}
}
Upvotes: 10
Views: 8871
Reputation: 759
Okay I faced the issue and came up with a solution. In my custom class i created a global variable on top as you can see in below code
MyRequest extends StringRequest {
private boolean mDelivered; //boolean to deliver response only once
then in constructor i initialsed it
public MyRequest(String url, Listener<String> listener,
ErrorListener errorListener, Context ctx) {
super(url, listener, errorListener);
mContext = ctx.getApplicationContext();
mDelivered = false;
DefaultRetryPolicy retryPolicy = new DefaultRetryPolicy(5000, 1, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
setRetryPolicy(retryPolicy);
}
and finally i overrided deliverResponse method. For first time mDelivered will be false and once it's delivered it'll be true. if response delivered from cache then cancel network request
@Override
protected void deliverResponse(String response) {
if (!mDelivered) {
mDelivered = true;
cancel(); //if cache delivers response better to cancel scheduled network request
super.deliverResponse(response);
}
}
Hope this helps
Upvotes: 2
Reputation: 1023
To stop the multiple request you can configure retry policy for your request object by using the setRetryPolicy() method of the request object. I managed to do this with following code:
req.setRetryPolicy(new DefaultRetryPolicy(20 * 1000, 0,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
With the above code, i reduced the timeout to 2 seconds and set the number of retries to 0.
Upvotes: -1
Reputation: 161
I believe I have figured it out after stepping through the code more. I believe it is the softttl that is causing this behavior. In the Volley cachedispatcher
if (!entry.refreshNeeded()) {
// Completely unexpired cache hit. Just deliver the response.
mDelivery.postResponse(request, response);
} else {
// Soft-expired cache hit. We can deliver the cached response,
// but we need to also send the request to the network for
// refreshing.
request.addMarker("cache-hit-refresh-needed");
request.setCacheEntry(entry);
// Mark the response as intermediate.
response.intermediate = true;
// Post the intermediate response back to the user and have
// the delivery then forward the request along to the network.
mDelivery.postResponse(request, response, new Runnable() {
@Override
public void run() {
try {
mNetworkQueue.put(request);
} catch (InterruptedException e) {
// Not much we can do about this.
}
}
});
This posts the response then sends it to the network which posts another response to the same listener.
Upvotes: 6