在try catch块中没有捕获多个IOException子类

时间:2011-09-08 08:40:42

标签: java android

我正在使用以下方法从服务器下载图像以在Android应用程序中提供。

public static void downloadToFile(File file, URL url, int connectTimeout, 
        int readTimeout) throws IOException {
    InputStream in = null;
    OutputStream out = null;
    try {
        URLConnection ucon = url.openConnection();
        ucon.setConnectTimeout(connectTimeout);
        ucon.setReadTimeout(readTimeout);

        in = ucon.getInputStream();
        out = new FileOutputStream(file);
        byte[] buffer = new byte[BUFFER_SIZE];
        int count = 0;
        while ((count = in.read(buffer)) != -1) {
            out.write(buffer, 0, count);
        }
        out.flush();
    } finally {
        if (in != null) {
            in.close();
        }
        if (out != null) {
            out.close();
        }
    }
}

当一个文件从服务器中删除但我尝试下载它时,我收到一个FileNotFoundException,这是完全有效的。在我的应用程序中,对此方法的调用包含在try catch中,处理IOException和Exception,因此我可以继续。

问题是在Android Developer Console中我收到了一些崩溃报告,FileNotFoundException似乎忽略了catch块并强行关闭了应用程序。

java.io.FileNotFoundException: http://foo.org/1234.jpg
at   org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:1162)
at com.package.IOUtil.downloadToFile(Unknown Source)

Unknown Source是因为Proguard,但是我可以在测试时通过放入不存在的文件URL来强制执行异常。当我在手机(SGS2 2.3.3)和平板电脑(TF101 3.2)上测试时,try catch块确实捕获了异常。下面的堆栈跟踪指向URL#getInputStream()作为抛出异常的内容,但这并不能解释为什么它没有被某些(只有少数)捕获。

java.io.FileNotFoundException: http://foo.org/1234.jpg
at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:521)
at com.package.IOUtil.downloadToFile(IOUtil.java:142)

我也遇到了来自同一方法/被调用者的SocketException同样的问题。

java.net.SocketTimeoutException: Connection timed out
at org.apache.harmony.luni.platform.OSNetworkSystem.connect(Native Method)
at dalvik.system.BlockGuard$WrappedNetworkSystem.connect(BlockGuard.java:357)
at org.apache.harmony.luni.net.PlainSocketImpl.connect(PlainSocketImpl.java:204)
at org.apache.harmony.luni.net.PlainSocketImpl.connect(PlainSocketImpl.java:437)
at java.net.Socket.connect(Socket.java:1002)
at org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnection.<init>(HttpConnection.java:75)
at org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnection.<init>(HttpConnection.java:48)
at org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnection$Address.connect(HttpConnection.java:322)
at org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnectionPool.get(HttpConnectionPool.java:89)
at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.getHttpConnection(HttpURLConnectionImpl.java:285)
at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.makeConnection(HttpURLConnectionImpl.java:267)
at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.retrieveResponse(HttpURLConnectionImpl.java:1018)
at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:512)
at com.package.IOUtil.downloadToFile(Unknown Source)

如果重要的话,下载是在后台线程中完成的。

我错过了什么吗?它可能是手机专用的,还是Proguard(即使它几乎被其他所有人抓住了)?

编辑:捕获的代码

private void download(List<URL> urls, int attempts) {
    List<URL> failedDownloads = new ArrayList<URL>();
    for (URL url : urls) {
        if (isInterrupted()) {
            return;
        }

        String imageName = Util.getImageName(url);
        File cacheFile = cache.getCacheFile(imageName);
        try {
            // Bad downloads often don't throw an IOException but
            // leave the file with a length of 0.
            if (cacheFile.length() == 0) {
                Util.safeDelete(cacheFile);
            }

            if (!cacheFile.exists()) {
                IOUtil.downloadToFile(cacheFile, url);

                if (cacheFile.length() == 0) {
                    //See above
                    Util.safeDelete(cacheFile);
                    failedDownloads.add(url);
                } else {
                    if (putToCache) {
                        cache.get(imageName);
                    }
                    handler.sendEmptyMessage(0);
                }
            } else {
                // Exists already, move it to cache
                if (putToCache) {
                    cache.get(imageName);
                }
            }
        } catch (IOException ioe) {
            Util.safeDelete(cacheFile);
            failedDownloads.add(url);
        } catch (Exception e) {
            // Continue on to next download - don't bother trying this
            // URL again.
        }
    }

    if (!failedDownloads.isEmpty() && attempts < maxAttempts) {
        attempts++;
        download(failedDownloads, attempts);
    }
}

Util.safeDelete只是一个包含在try catch中的删除,因此不应该相关。

4 个答案:

答案 0 :(得分:1)

首先,不要抓住并挤压Exception不要这样做。 永远不会。如果出现意外情况,你就会丢掉所有的证据。

其次,使用包含的调试信息重新编译代码,您将在stacktrace中获取方法的文件名和行号。在开发/测试时摆脱Proguard。 (最好完全摆脱它,因为它没有给你任何真正的保护。)

最后,download方法(因为你复制了它)不可能导致未被捕获的IOException。如果是的话:

  • 你明确地抓住了例外,
  • 该方法会出现编译错误,因为它没有声明IOException
  • download方法将成为堆栈跟踪的一部分,并且

因此它必须是......

  • 您已声明并将另一个 IOException类导入该文件,或
  • 罪魁祸首是您的safeDelete方法,或
  • download方法过载,异常发生在不同的重载或
  • 您在downloadToFile以外的某个地方致电download,或
  • 您复制的代码不准确,或
  • 你在编译/部署代码时犯了一个错误;例如忘了在编辑后重新编译。

答案 1 :(得分:0)

  

如果重要的话,下载是在后台线程中完成的。

是的,这很重要。异常被抛出在后台线程中,并且有效地消失在空气中。

我认为解决方案可以在这里找到: How to throw a checked exception from a java thread? 将后台线程放在Callable中的答案可能是最好的方法

欢呼声

答案 2 :(得分:0)

很奇怪catch异常没有捕获FileNotFoundException。看起来你已经在下载方法中遇到了异常。

您可以尝试在downloadToFile中捕获异常,看看会发生什么。看看它是否是其他地方的错误......

答案 3 :(得分:0)

解决方案(在我的情况下)

如果服务器响应代码为&gt; = HTTP_BAD_REQUEST(大于400) 方法getInputStream(),类HttpURLConnectionImpl抛出 FileNotFoundException (因此您无法打开输入流)。

即使此文件存在,您的对象也不会为您提供输入流,因为服务器响应代码为&gt; = 400 - 更改服务器上的响应代码使用其他类强>连接。

09-07 16:08:08.749: WARN/System.err(360): at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:1162)

源代码片段: http://www.docjar.com/html/api/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnectionImpl.java.html

  867       @Override
  868       public InputStream getInputStream() throws IOException {
  869           if (!doInput) {
  870               throw new ProtocolException(Messages.getString("luni.28")); //$NON-NLS-1$
  871           }
  872   
  873           // connect before sending requests
  874           connect();
  875           doRequest();
  876   
  ...
  883           if (responseCode >= HTTP_BAD_REQUEST) {
  884               throw new FileNotFoundException(url.toString());
  885           }
  886   
  887           return uis;
  888       }