繁体   English   中英

当Wifi连接丢失时,java.io.InputStream不会抛出IOException

[英]java.io.InputStream will not throw IOException when Wifi connectivity is lost

我的Android应用程序中的一些代码遇到了一个问题,它从URL下载文件,这里是一段代码片段:

int bytesRead = 0;
final byte[] buffer = new byte[32 * 1024];
InputStream stream = httpUrlConnection.getInputStream();

try {
    while ((bytesRead = stream.read(buffer)) > 0) {
        Log.i("TAG", "Read from steam, Bytes Read: " + bytesRead);
    }
} catch (IOException ex) {
    //Recover from lost WIFI connection.
} finally {
    stream.close();
}

如果WiFi连接丢失,我的应用程序依赖于InputStream.read()来抛出IOException Java 8文档中所述, 如果输入流已关闭,或者发生某些其他I / O错误,则此方法应抛出IOException 在Android M中,这会立即发生,我的代码可以处理并从异常中恢复。 在Android N中,不会抛出此异常导致我的应用程序只是挂在read()方法中,它永远不会突破它。 有没有其他人遇到这个问题并以不会破坏向后兼容性的方式解决它? 这是一个新的Android N bug吗?

如果连接断开,从套接字读取可以永久阻止。 您需要使用读取超时。

为了避免重新发明轮子并发现自己弄清楚这个和其他一些常见场景,我会使用像Volley这样的高级库

请参阅: 使用Volley传输网络数据

Volley以非常直接的方式为您提供有趣的事物:

  • 超时控制
  • 易于定制,例如,重试和退避
  • 控制几种错误
  • 取消请求API。 您可以取消单个请求,也可以设置要取消的请求块或范围。
  • 调试和跟踪工具。
  • 等等

发送请求就像这样简单 (来自文档)

  final TextView mTextView = (TextView) findViewById(R.id.text);
...
// Instantiate the RequestQueue.
RequestQueue queue = Volley.newRequestQueue(this);
String url ="http://www.google.com";

// Request a string response from the provided URL.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
            new Response.Listener<String>() {
    @Override
    public void onResponse(String response) {
        // Display the first 500 characters of the response string.
        mTextView.setText("Response is: "+ response.substring(0,500));
    }
}, new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
        mTextView.setText("That didn't work!");
    }
});
// Add the request to the RequestQueue.
queue.add(stringRequest);

设置超时/重试策略非常简单:

stringRequest.setRetryPolicy(new DefaultRetryPolicy(20 * 1000, 1, 1.0f));

参数是:

  • 超时:指定每次重试尝试的套接字超时(毫秒)。
  • 重试次数:尝试重试的次数。
  • Back Off Multiplier:一个乘数,用于确定每次重试尝试设置为套接字的指数时间。

关于错误处理

如您所见,您正在向请求传递一个错误侦听器new Response.ErrorListener() 当出现错误时,Volley调用onErrorResponse回调public void onErrorResponse方法在执行请求时发生错误时传递VolleyError对象的实例。

以下是凌空的例外列表,从这个帖子采取这里

  • AuthFailureError - 如果您尝试执行Http Basic身份验证,则最有可能出现此错误。
  • NetworkError - 套接字断开连接,服务器关闭,DNS问题可能导致此错误。
  • NoConnectionError - 与NetworkError类似,但在设备没有互联网连接时触发,您的错误处理逻辑可以进行
  • NetworkError和NoConnectionError一起对待它们。
  • ParseError - 如果收到的JSON格式错误,则使用JsonObjectRequest或JsonArrayRequest时会生成此异常。 如果你得到这个错误,那么这是一个应该修复而不是被处理的问题。
  • ServerError - 服务器响应错误,很可能是4xx或5xx HTTP状态代码。
  • TimeoutError - 套接字超时,服务器太忙而无法处理请求或存在一些网络延迟问题。 默认情况下,Volley会在2.5秒后超时请求,如果您一直收到此错误,请使用RetryPolicy。

所以你可以做的事情

  if ((error instanceof NetworkError) || (error instanceof NoConnectionError)) {

     //then it was a network error

   }

正如@EJP所说“如果连接断开,从套接字读取可以永久阻塞”,只需将此行添加到代码中,并捕获java.net.SocketTimeoutException:

int bytesRead = 0;
        final byte[] buffer = new byte[32 * 1024];
        InputStream stream = httpUrlConnection.getInputStream();
        httpUrlConnection.setConnectTimeout(5000);

        try {
            while ((bytesRead = stream.read(buffer)) > 0) {
                Log.i("TAG", "Read from steam, Bytes Read: " + bytesRead);
            }
        } catch (java.net.SocketTimeoutException ex) {
            //Recover from lost WIFI connection.
        } finally {
            stream.close();
        }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM