Android Volley在请求较慢时出现重复提交问题

65

我在网络慢的情况下使用 Volley 发送 POST 请求时遇到问题。每次我在 LogCat 中看到 BasicNetwork.logSlowRequests 时,我的 POST 请求会被执行两次或更多次,导致一个请求产生多个(2个或更多)帖子。我已将重试策略设置为0,但没有帮助。

这是我的 LogCat

03-16 01:31:35.674: D/Volley(5984): [19807] BasicNetwork.logSlowRequests: HTTP response for request=<[ ] http://[myserver]/api/places 0xfa7d0c33 NORMAL 1> [lifetime=3824], [size=313], [rc=200], [retryCount=0] 03-16 01:31:35.704: D/Volley(5984): [1] Request.finish: 3853 ms: [ ] http://[myserver]/api/places 0xfa7d0c33 NORMAL 1

这是我的代码

JSONObject body = new JSONObject();
try {
    body.put(PROTO_BODY_AUTHORIZATION, Sessions.getActiveSession().getToken());
} catch (JSONException e) {
    e.printStackTrace();
}

JsonObjectRequest request = new JsonObjectRequest(
        Request.Method.POST,
        context.getResources().getString(R.string.server_address) + "/places",
        body,
        callback,
        new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Toast.makeText(context, error.getMessage(), Toast.LENGTH_LONG).show();
            }
        }
);

request.setRetryPolicy(
        new DefaultRetryPolicy(
                DefaultRetryPolicy.DEFAULT_TIMEOUT_MS,
                0,
                DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
    getRequestQueue().add(request);

请帮忙,我拼命寻找解决这个问题的方法。


你的网络请求超时时间和重试策略超时时间是相同的吗? - tolgap
我在哪里可以获取网络请求超时时间?如果我从LogCat中看到,请求的生命周期为3825ms。重试策略超时时间为2500ms(DefaultRetryPolicy.DEFAULT_TIMEOUT_MS)。 - aristo_sh
1
如果我查看Volley的源代码,我会发现大多数超时时间都设置为5000毫秒。我猜你的帖子是重复的,因为您的重试在请求超时之前发生,实际上发送了两次。 - tolgap
在这个讨论中已经解决了 https://stackoverflow.com/questions/47936955/i-am-unable-to-make-a-network-call-using-volley-i-have-tried-many-solutions-but/47937201?noredirect=1#comment82844782_47937201 - Basim Majeed
18个回答

52

将以下数值添加到您的请求对象中:

request.setRetryPolicy(new DefaultRetryPolicy(
    DefaultRetryPolicy.DEFAULT_TIMEOUT_MS * 2,
    DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
    DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));

这里:request是你的JsonObjectRequest对象。根据Volley中DefaultRetryPolicy类中的DEFAULT TIMEOUT VALUE更改multiplicator的值。

你也可以将第一个参数设置为0,如下所示:

request.setRetryPolicy(new DefaultRetryPolicy(
    0,
    DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
    DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));

仍然出现重复项..求助? - deejay
你可以将默认缓存设置为false。 - Droid_Mechanic
1
请求.setRetryPolicy(new DefaultRetryPolicy(0,0, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));将DefaultRetryPolicy.DEFAULT_MAX_RETRIES设置为0。 - Droid_Mechanic
你的第二个答案将第一个值设置为0,解决了我的问题。谢谢伙计。 - deejay
那肯定对我的代码不起作用!已经尝试了3个月了,但是糟糕!没有用!截至今天,我仍然面临着这个问题! - sud007

22

仅仅将RetryPolicy中的超时时间设置为0是不够的。在检查源代码后,你需要将最大重试次数设置为小于0,这是因为它正在检查当前次数是否小于等于最大值...

我通过将策略设置为以下内容来解决了双重发布的问题

new DefaultRetryPolicy(0, -1, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));

1
我相信这是正确的答案。虽然你也可以设置超时值。 - portfoliobuilder

9
我找到了双重发布的解决方案,只需要将超时时间设置为0即可。

2
你能详细说明一下吗?将超时设置为0可能会导致更多的请求触发,对吧? - Pratik Mandrekar
6
看起来不是这样,似乎0表示没有超时。我发现如果Volley达到超时时间,它会发送另一个请求。因此,将超时时间设置为0可以防止Volley发送另一个请求。 - aristo_sh
3
我对此不太确定。我刚刚将超时时间增加到了30000毫秒,只是为了暂时延迟一些事情。 - Pratik Mandrekar
1
这是一个非常糟糕的解决方案,在我的情况下,启动画面活动向服务器发送了一个POST请求,当用户没有互联网连接时,POST请求从未失败,导致用户被阻塞。我认为Droid_Mechanic的答案更好。 - Hani

4

我找到了解决多重发布错误的方法。

更改RetryPolicy。我将超时值设置为50000毫秒,效果很好。像这样:

  request.setRetryPolicy(
                new DefaultRetryPolicy(
                        500000,
                        DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
                        DefaultRetryPolicy.DEFAULT_BACKOFF_MULT
                )
        );

4
您必须将RetryPolicy设置为0次重试,并确保超时时间大于服务器超时时间。
setRetryPolicy(new DefaultRetryPolicy("bigger than server timeout",
                                      0,
                                      DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));

3
我可以通过两种方式解决这个问题。
第一种方法是更改RetryPolicy。 简单地将超时值设置为默认超时时间的两倍。这个方法很有效。你也可以尝试其他数值。
request.setRetryPolicy(new DefaultRetryPolicy(DefaultRetryPolicy.DEFAULT_TIMEOUT_MS * 2, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));

另一种方法是在openConnection方法的HurlStack类中设置connection.setChunkedStreamingMode(0); 我是这样创建我的RequestQueue的:requestQueue = Volley.newRequestQueue(context, new HurlStack()); 希望它有所帮助 :)

1
我们如何在HurlStack类的openConnection方法中设置connection.setChunkedStreamingMode(0);?我尝试扩展HurlStack但失败了。我也尝试了你的第一个解决方案,但它也失败了。 - Justin
在您的Volley库项目中,您可以在工具箱包中看到HurlStack。第一个解决方案应该有效,请尝试使用不同的超时值进行实验。 - Arun Badole
是的,我确实看到了HurlStack类,但我找不到任何方法来设置connection.setChunkedStreamingMode(0);。你能发一些演示代码吗?关于第一个解决方案,我尝试了所有情况,包括更改超时时间、将重试更改为0和System.setProperty("http.keepAlive", "false"),但仍然无法解决问题。 - Justin

2
这对我来说有效。
public class MyRetryPolicyWithoutRetry implements RetryPolicy
{
    @override
    public int getCurrentTimeout()
    {
        return CONNECTION_TIME_OUT; /200000/
    }

    @Override
    public int getCurrentRetryCount()
    {
        return 0;
    }

    @Override
    public void retry(VolleyError error) throws VolleyError
    {
        throw(error);
    }
}

使用方法:

request.setRetryPolicy(new MyRetryPolicyWithoutRetry());

2

请增加setRetryPolicy的时间。

request.setRetryPolicy(new DefaultRetryPolicy(
                    30000,
                    DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
                    DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
            Volley.newRequestQueue(this).add(equest);

2

我在这里提出了类似的问题:

当重试策略设置为0时,Android Volley向服务器发送2个请求

我通过在Android内部将keep-alive属性设置为false来解决了这个问题,例如:

System.setProperty("http.keepAlive", "false")

我将这行代码添加到导入requestqueue并发出请求的类中。

另外,请检查您的服务器是否具有keep-alive头。

这篇帖子帮助我找到了解决方案。


2
唯一让双重请求停止的方法是将重试策略设置为-1。
request.setRetryPolicy(new DefaultRetryPolicy(0, -1, 0));

我认为这是因为DefaultRetryPolicy的尝试剩余逻辑在hasAttemptRemaining()方法中返回true,如果retryCount为0且Max retries也为0:

protected boolean hasAttemptRemaining() {
    return this.mCurrentRetryCount <= this.mMaxNumRetries;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接