Android gets error when I try to setRequestProperty to HttpURLConnection
I wrote a simple download manager and I am trying to set RESUME for all downloads. after googleing how to do it. I know there should be setRequestProperty
for the connection, but my code doesn't work and I get this error:
FATAL EXCEPTION: Thread-882
java.lang.IllegalStateException: Cannot set request property after connection is made
at libcore.net.http.HttpURLConnectionImpl.setRequestProperty(HttpURLConnectionImpl.java:510)
My code:
URL url = new URL(downloadPath);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
final int fileSize = connection.getContentLength();
File file = new File(filepath);
if (file.exists() && fileSize == file.length()) {
return;
} else if (file.exists()) {
connection.setRequestProperty("Range", "bytes="+(file.length())+"-");
}else
connection.setRequestProperty("Range", "bytes=" + downloadedSize + "-");
connection.setRequestMethod("GET");
connection.setDoInput(true);
connection.setDoOutput(true);
connection.connect();
how to solve this problem and set setRequestProperty
up the connection correctly ?
The problem is what you are calling connection.getContentLength()
before you are calling setRequestProperty()
. Content length is only available after you have made a request, after which you cannot set the request property ...
It is not entirely clear what you are trying to do, but one option is to use the query HEAD
only to get the length of the content, and then make a separate query if you only need to get a portion of the data. Be aware that it is possible that the length of the content will change between requests , sure.
However, I would prefer to store more metadata somewhere in your download manager, so that when you first start downloading data, you will keep a record of the total size, so you donβt have to make a HEAD
query when you resume - you can only specify from local information, whether you downloaded the file or not. (This has the same problem in terms of changing content, but that's a different matter.)
source to share
I had the same error as OP.
Why The problem is that when you try to set parameters for a request to resume download, you must be disconnected from Http.
The moment you call the method connection.getContentLenght();
, the following happens: connection.connect();
so if you try to set connection properties you will get the mentioned error.
FIX
What I did is that I closed the Http connection after I called the methodlong totalFileSize = connection.getContentLength();
connection.disconnect()
// Disconnect from http
And after that, you can set the parameters you want to connect and call connection.connect()
if needed.
Tip In my particular case, I was trying to download a file and was needed to support resumable downloads, so I did the following for that:
- Check if the file exists.
-
If the file exists, then get the length of the file:
long bytesDownloaded = file.getLenght();
-
Use this length to set it up on the connection so that it can resume at exactly the specified bytes.
-
Write bytes to the end of the file.
source to share
- You must set properties before
getContentLength()
- If you set the range to the existing length of the file, you will get the remaining bytes when called
getContentLength()
, so if the content length is "0" it means the file has been fully loaded.
But if you want to create a download manager, @ Jon Skeet's method would be smart.
Edit:
public abstract long getContentLength ()
Added in API Level 1 Reports the length of the content, if known.
Returns the number of bytes of the content, or negative if unknown. If the length of the content is known but exceeds Long.MAX_VALUE, a negative number is returned.
source to share