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



我正在使用以下方法从服务器下载图像以在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开发者控制台我收到了一些崩溃报告和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)

未知源是由于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);
    }
}

跑龙套。safeDelete只是一个在try catch中封装的delete操作,所以它们之间不应该有关联。

首先,不要抓住并压制Exception别这样。。如果出现了意想不到的问题,你就是在抛弃所有的证据。

其次,重新编译包含调试信息的代码,您将在堆栈跟踪中获得方法的文件名和行号。在开发/测试过程中摆脱Proguard。(最好完全摆脱它,因为它不能给你任何真正的保护。)

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

  • 你清楚地捕获异常,并且
  • 会有一个编译错误的方法,因为它没有声明IOException,和
  • download方法将是堆栈跟踪的一部分,而

因此它一定是类似于…

  • 您已经声明并导入了另一个 IOException类到该文件中,或者
  • 罪魁祸首是你的safeDelete方法,或者
  • download方法重载,异常发生在不同的重载中,或者
  • 您正在调用download之外的downloadToFile,或者
  • 您复制的代码不准确,或者
  • 你在编译/部署代码时犯了错误;例如:编辑后忘记重新编译

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

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

我认为解决方案可以在这里找到:如何抛出一个检查异常从java线程?把后台线程放到Callable中可能是最好的方法

欢呼

奇怪的是,catch异常没有捕获FileNotFoundException。看来你已经在下载方法中捕获了异常。

你可以尝试在downloadToFile中捕捉异常,看看会发生什么。

解决方案(在我的案例中)

当服务器响应代码>= HTTP_BAD_REQUEST(大于400)时,

In case 方法gettinputstream(),类HttpURLConnectionImpl抛出FileNotFoundException(所以你不能打开输入流).

即使这个文件存在,你的对象也不会给你输入流,因为服务器的响应代码是>=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       }

最新更新