这是我的代码:
url = paths[0];
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
int length = connection.getContentLength(); // i get negetive length
InputStream is = (InputStream) url.getContent();
byte[] imageData = new byte[length];
int buffersize = (int) Math.ceil(length / (double) 100);
int downloaded = 0;
int read;
while (downloaded < length) {
if (length < buffersize) {
read = is.read(imageData, downloaded, length);
} else if ((length - downloaded) <= buffersize) {
read = is.read(imageData, downloaded, length - downloaded);
} else {
read = is.read(imageData, downloaded, buffersize);
}
downloaded += read;
publishProgress((downloaded * 100) / length);
}
Bitmap bitmap = BitmapFactory.decodeByteArray(imageData, 0,
length);
if (bitmap != null) {
Log.i(TAG, "Bitmap created");
} else {
Log.i(TAG, "Bitmap not created");
}
is.close();
return bitmap;
我在Java文档中查看了这个,由于以下原因,长度为负:
“内容的字节数,如果未知,则为负数。如果内容&gt;长度已知但超过Long.MAX_VALUE,则返回负数。”
这可能是什么原因?我正在尝试下载图像。我想指出这是我尝试下载图像的第四种方法。其他三个被提及here。
修改:
根据要求,这是我正在使用的完整方法。
protected Bitmap getImage(String imgurl) {
try {
URL url = new URL(imgurl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
int length = connection.getContentLength();
InputStream is = (InputStream) url.getContent();
byte[] imageData = new byte[length];
int buffersize = (int) Math.ceil(length / (double) 100);
int downloaded = 0;
int read;
while (downloaded < length) {
if (length < buffersize) {
read = is.read(imageData, downloaded, length);
} else if ((length - downloaded) <= buffersize) {
read = is.read(imageData, downloaded, length
- downloaded);
} else {
read = is.read(imageData, downloaded, buffersize);
}
downloaded += read;
// publishProgress((downloaded * 100) / length);
}
Bitmap bitmap = BitmapFactory.decodeByteArray(imageData, 0,length);
if (bitmap != null) {
System.out.println("Bitmap created");
} else {
System.out.println("Bitmap not created");
}
is.close();
return bitmap;
} catch (MalformedURLException e) {
System.out.println(e);
} catch (IOException e) {
System.out.println(e);
} catch (Exception e) {
System.out.println(e);
}
return null;
}
答案 0 :(得分:24)
默认情况下,HttpURLConnection的这种实现请求服务器使用gzip压缩
由于getContentLength()返回传输的字节数,因此您无法使用该方法来预测可从getInputStream()读取的字节数。
相反,读取该流直到它耗尽:当read()返回-1时
可以通过在请求标头中设置可接受的编码来禁用Gzip压缩:
urlConnection.setRequestProperty("Accept-Encoding", "identity");
所以试试这个:
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("Accept-Encoding", "identity"); // <--- Add this line
int length = connection.getContentLength(); // i get negetive length
来源(效果段落):http://developer.android.com/reference/java/net/HttpURLConnection.html
答案 1 :(得分:11)
简单的答案是内容长度未知。或者更具体地说,服务器没有在响应消息中设置“Content-Length”标头。
您必须更改代码,以便它不预先分配固定大小的字节数组来保存图像。
另一种方法是创建一个本地ByteArrayOutputStream
并将从套接字读取的字节复制到该字节。然后调用toByteArray
来获取完整的字节数组。
如果您可以更改服务器端,另一种方法是在响应中设置内容长度标头。必须在将OutputStream写入响应之前完成此操作。
您现有的代码也在另一方面被打破。如果您收到IOException或其他异常,代码块将“异常退出”而不关闭URLConnection。这将导致文件描述符的泄漏。执行此操作太多次,并且由于文件描述符...或本地端口号耗尽,您的应用程序将失败。
最佳做法是使用try / finally确保关闭外部资源的URLConnections,Sockets,Streams等始终关闭。
答案 2 :(得分:3)
服务器似乎没有在其响应标头中提供 Content-Length ,您是否从响应标头中获得了 Transfer-Encoding = chunked 标头?
我的情况是:我执行 HttpURLConnection 并认为服务器会回复我&#34; Content-Length&#34;具有正值,但它没有,然后我转向 Android HttpClient实现的 AndroidHttpClient ,再次执行相同的请求并获得正确的 Content-Length 。
我使用Wireshark来分析这两个请求,发现请求标题略有不同。
使用AndroidHttpClient的标头列表:
---------------------------------- request headers
Range : bytpe=0-
Host : download.game.yy.com
Connection : Keep-Alive
User-Agent : com.duowan.mobile.netroid
---------------------------------- response headers
Server : nginx
Content-Type : text/plain; charset=utf-8
ETag : "535e2578-84e350"
Cache-Control : max-age=86400
Accept-Ranges : bytes
Content-Range : bytes 0-8708943/8708944
Content-Length : 8708944
使用HttpURLConnection的请求标头列表:
---------------------------------- request headers
Range : bytpe=0-
Host : download.game.yy.com
Connection : Keep-Alive
User-Agent : com.duowan.mobile.netroid
Accept-Encoding : gzip // difference here
---------------------------------- response headers
Server : nginx
Content-Type : text/plain; charset=utf-8
Cache-Control : max-age=86400
Transfer-Encoding : chunked
X-Android-Received-Millis : 1398861612782
X-Android-Sent-Millis : 1398861608538
请求标头的唯一区别是接受编码,我自己没有添加,这是HttpURLConnection的Android默认设置,之后,我将其设置为< strong> identity 然后再次执行请求,下面是完整的标头堆栈:
---------------------------------- request headers
Range : bytpe=0-
Host : download.game.yy.com
Connection : Keep-Alive
User-Agent : com.duowan.mobile.netroid
Accept-Encoding : identity
---------------------------------- response headers
Server : nginx
Content-Type : text/plain; charset=utf-8
ETag : "535e2578-84e350"
Cache-Control : max-age=86400
Accept-Ranges : bytes
Content-Range : bytes 0-8708943/8708944
Content-Length : 8708944
X-Android-Received-Millis : 1398862186902
X-Android-Sent-Millis : 1398862186619
正如您所看到的,在我将Accept-Encoding设置为&#34; identity&#34;替换系统默认值&#34; gzip&#34;,服务器提供&#34;内容长度&#34;积极的,这就是为什么AndroidHttpClient可以采用Content-Length和HttpURLConnection的正确值。
gzip压缩编码可能导致服务器端考虑的分块响应,如果服务器认为您可以接收分块编码响应,则可能不提供 Content-Length 标头,尝试禁用gzip可接受的行为,然后看看有什么不同。
答案 3 :(得分:0)
见这里:http://download.oracle.com/javase/6/docs/api/java/net/URLConnection.html#getContentLength%28%29
它说,
<强>返回:强>
此连接的URL引用的资源的内容长度,如果内容长度未知,则为-1。
它只是表示标题不包含content-length
字段。如果您可以控制服务器代码。你应该以某种方式设置内容长度。像ServletResponse#setContentLength
答案 4 :(得分:0)
我也在我的壁纸应用中遇到了这个问题。问题是因为您的服务器在其http标头中未提供 Content-Length 。以下是有关内容长度的正常http标头的快照。
我正在使用共享主机,因此无法更改服务器配置。在我的应用程序中,我设置了进度对话框最大值,其值为近似值(大于我的实际文件大小),如下所示:
int filesize = connection.getContentLength();
if(filesize < 0) {
progressDialog.setMax(1000000);
} else {
progressDialog.setMax(filesize);
}
您还可以在此处查看我的完整示例源代码: