我正在使用以下方法从服务器下载图像以在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中的删除,因此不应该相关。
答案 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;
即使此文件存在,您的对象也不会为您提供输入流,因为服务器响应代码为&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)
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 }