针对一个请求,Android Volley返回结果两次

时间:2013-11-17 06:43:04

标签: android android-volley

我一直试图弄清楚这个问题两天了,而且我完全难以理解。出于某种原因,我正在向队列发送一个请求,但是volley返回两次,这是两次调用侦听器并在listview中将结果加倍。我打开了Volley的日志记录,我可以看到请求被添加到队列并返回,然后几秒钟后也会返回相同的请求。记录下面

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

正如你所看到的,它从未说过添加了另一个请求,也没有说更多的请求在飞行中。如果我清除缓存,我得到相同的结果,只是第一个请求来自网络,第二个请求从缓存返回。我已经尝试过调试并单步执行我的代码,但我从未看到请求被排队多次一次。谁看过这个吗?还有什么地方我应该看看?

由于

编辑:这是我开始排球的代码以及我称之为的地方。

@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;
    }

}

3 个答案:

答案 0 :(得分:6)

我相信在更多地逐步完成代码后我已经弄明白了。我认为导致这种行为的是softttl。在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.
                        }
                    }
                });

这会发布响应,然后将其发送到网络,该网络会向同一个侦听器发布另一个响应。

答案 1 :(得分:1)

好的,我遇到了这个问题,想出了一个解决方案。在我的自定义类中,我在顶部创建了一个全局变量,如下面的代码所示

MyRequest extends StringRequest {
    private boolean mDelivered;  //boolean to deliver response only once

然后在构造函数中我初始化它

    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);
}

最后我重写了deliverResponse方法。第一次mDelivered将是虚假的,一旦它被传递,它将是真的。如果响应从缓存传递,则取消网络请求

    @Override
protected void deliverResponse(String response) {
    if (!mDelivered) {
        mDelivered  = true;
        cancel();   //if cache delivers response better to cancel scheduled network request
        super.deliverResponse(response);
    }
}

希望这有帮助

答案 2 :(得分:0)

要停止多个请求,可以使用请求对象的setRetryPolicy()方法为请求对象配置重试策略。我设法使用以下代码执行此操作:

req.setRetryPolicy(new DefaultRetryPolicy(20 * 1000, 0,
      DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));

使用上面的代码,我将超时时间减少到2秒,并将重试次数设置为0。