【问题标题】:How to disconnect an HttpUrlConnection on HTC (Froyo and below) phones?如何断开 HTC(Froyo 及以下)手机上的 HttpUrlConnection?
【发布时间】:2012-08-09 17:34:54
【问题描述】:

在某些情况下,我需要从客户端断开长轮询 http 请求。我对服务器进行的 HttpUrlConnection 的相关部分如下(以下所有代码都在 Thread 的 run() 方法中):

try {
    URL url = new URL(requestURL);

    connection = (HttpURLConnection) url.openConnection();
    connection.setRequestProperty("Accept-Charset", "UTF-8");
    connection.setConnectTimeout(5 * 1000);
    connection.setReadTimeout(60 * 1000);
    connection.setRequestMethod("GET");

    // read the output from the server
    reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
    StringBuilder stringBuilder = new StringBuilder();

    String line = null;
    while ((line = reader.readLine()) != null) {
        stringBuilder.append(line + "\n");
    }
    Log.d(TAG, stringBuilder);
} catch (IOException ioe) {
    Log.e(TAG, ioe);
} finally {
    if (reader != null) {
        try {
            reader.close();
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }
}

这是我第一次启动的方式,然后(经过第二次延迟)尝试取消请求:

pollThread = new PollThread();
pollThread.start();
Log.d(TAG, "pollThread started");

new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        pollThread.cancelRequest();
        Log.d(TAG, "pollThread presumably cancelled");
    }
}, 1000);

这就是 cancelRequest() 方法的样子:

public void cancelRequest() {
    if (connection != null) {
        connection.disconnect();
    }
}

本质上,

  1. 我使用 get 请求启动 HttpUrlConnection,读取超时时间为 1 分钟
  2. 然后一秒钟后,我尝试取消之前的请求
  3. 预期的结果是,当我调用 connection.disconnect() 时,连接应该抛出 IOException

这正是各种模拟器 (2.2 - 4.0.3)、摩托罗拉 Atrix (2.3.7) 和三星 Note (4.0.1) 上发生的情况。但是在一些运行 2.2 的 HTC 设备上,尽管我明确终止了连接,但请求将保持活动状态并收到响应。我用 HTC Desire 和 HTC Wildfire 验证了这一点。

这里发生了什么?如何在所有运行 2.2+ 的设备上安全地取消此类请求?

为了您的方便,这里提供了完整的代码,如果您想自己进行试驾:https://gist.github.com/3306225

【问题讨论】:

    标签: android httpurlconnection android-2.2-froyo disconnect


    【解决方案1】:

    这是怎么回事?

    这是早期 android 版本 (Froyo 2.2) 中的一个已知错误,总的来说,套接字不能被其他线程异步关闭,并已在 Gingerbread 2.3 中修复:

    Issue 11705: impossible to close HTTP connection using HttpURLConnection

    如何在所有运行 2.2+ 的设备上安全地取消此类请求?

    该链接中项目成员的评论:

    适用于当前版本的最佳近似方法是在 HTTP 连接上设置读取和连接超时。

    希望对您有所帮助。

    【讨论】:

    • 很棒的发现,谢谢!这是否意味着,本质上,我无法实现在 2.2 上工作的可中断流连接?
    • 如果您使用 HttpURLConnection API,或者如果您使用套接字编写自己的连接实现,您可以尝试调用socket.shutdownInput();,如相关Issue 7933 中所建议的那样。然而,IMO 最有效的解决方法是在 HTTP 连接上设置读取和连接超时。
    • 不幸的是,即使是 socket.shutdownInput() 也无济于事。唯一的方法是使用 socket.setSoTimeout。您需要将其设置为相对较低的值,并在 while 循环中进行读取。修复这个bug的android核心开发者推荐了这个方法,而且在姜饼之前的环境中似乎是唯一的解决方案。
    【解决方案2】:

    实际上,我建议您使用 Apache HttpClient lib,而不是 android 提供的默认库。

    您可以从以下地址下载:http://code.google.com/p/httpclientandroidlib/

    如果你想“一路走来”,你也可以使用AndroidHttpClient“配置合理的默认设置和Android注册方案”,还可以支持cookie。你可以从here下载它(我不记得我是什么时候找到原始的......)

    这就是你使用“Get”调用的方式,我想你可以弄清楚其余的:

        InputStream isResponse = null;
    
        HttpGet httpget = new HttpGet(strUrl);
        HttpResponse response = getHttpClient().execute(httpget);
    
        HttpEntity entity = response.getEntity();
        isResponse = entity.getContent();
        responseBody = convertStreamToString(isResponse);
    

        /**
     * @return the mClient
     */
    protected AndroidHttpClient getHttpClient() {
        if (mClient == null)
            mClient = AndroidHttpClient.newInstance(mCookieStore);
        return mClient;
    }
    

    关闭连接:

    getHttpClient().close();
    

    【讨论】:

    • 感谢您的建议,但这并不能解决我的问题。由于该错误存在于底层套接字实现中,因此会出现相同的问题(即,我无法异步断开与另一个线程的连接)。
    猜你喜欢
    • 2013-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-04
    相关资源
    最近更新 更多