this is my first post - so I hope did everything right concerning code-formatting.
Maybe you can help me with the following problem:
With API-Level 10 and above, all my HttpURLConnections are working fine, but with API-Level 8 some (or sometimes most) of my attempts to download the content of a file (txt, html…) fails.
I worked around this by just repeating the download whenever the server returned the response code “-1”. This is not very satisfying but it works (more or less) – but I guess it only works because of the fact that the content I receive is very short (max 100 chars) – and sometimes I think some chars at the end were omitted, too.
But now I tried to implement an update routine (downloading and installing an apk-File) which most of the times fails, because the apk file is fragmented (I guess), so I get a “Parsing error” when trying to install the file.
What am I doing wrong?
Thank you for any help (and staying friendly if you are better than me g)!
Here’s the code of my update routine (which – as you can see – has no repeating mechanism as described above):
String download_url = "http://url/";
String download_file = "name.apk";
//Local
String update_file = download_file;
File update_file_stream = context.getFileStreamPath(update_file);
//Connect
URL url = new URL(download_url + download_file);
HttpURLConnection c = (HttpURLConnection) url.openConnection();
c.setRequestMethod("GET");
c.setDoOutput(true);
c.connect();
//Delete local File?
if(update_file_stream.exists()){
update_file_stream.delete();
}
//Download File
FileOutputStream fos = context.openFileOutput(update_file, Context.MODE_WORLD_READABLE);
InputStream is = c.getInputStream();
byte[] buffer = new byte[4096];
int len1 = 0;
while ((len1 = is.read(buffer)) != -1) {
fos.write(buffer, 0, len1);
}
fos.close();
is.close();
//Install
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(update_file_stream), "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
Look like Network on Main Thread issue.
In the previous android sdk version (maybe 8) you can do some network on Main Thread
but after ICS or Honeycomb you can't do any network stuff on Main Thread.
Related
I have an android app that downloads and uses a file at runtime. The file is valid as I can download it via the browser and open it up, etc. However my app kept reporting that the file is corrupted.
After investigation I discovered the server (which I have no control over) is returning an incorrect "Content-Length:" (~180 vs ~120000). The header is the culprit as I confirmed the issue by downloading the file with curl - which also resulted in a truncated file.
After some research I concluded that my use of BufferedInputStream to append to a ByteArrayBuffer is autosizing the byte array to the url connections content length. To circumvent this, I tried to use ByteArrayOutputStream instead, however this solved nothing.
Anybody know of a way to download a file if the Content-Length is incorrectly set? A browser can.
Here's my latest attempt:
public static void downloadFileFromRemoteUrl(String urlString, String destination){
try {
URL url = new URL(urlString);
File file = new File(destination);
URLConnection urlConnection = url.openConnection();
InputStream inputStream = urlConnection.getInputStream();
byte[] buffer = new byte[1024];
int curLength = 0;
int newLength = 0;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
while((newLength = inputStream.read(buffer))>0)
{
curLength += newLength;
byteArrayOutputStream.write(buffer, 0, newLength);
}
FileOutputStream fos = new FileOutputStream(file);
fos.write(byteArrayOutputStream.toByteArray());
fos.close();
android.util.Log.d("DB UPDATE", "Done downloading database. Size: " + byteArrayOutputStream.toByteArray().length);
}
catch (MalformedURLException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
After some research I concluded that my use of BufferedInputStream to append to a ByteArrayBuffer is autosizing the byte array to the url connections content length.
Nonsense. You are crediting those classes with paranormal powers. How could an output stream possibly become aware of the Content-length header? The URLConnection's input stream is being terminated at the content-length. Correctly.
To circumvent this, I tried to use ByteArrayOutputStream instead, however this solved nothing.
Of course not.
Anybody know of a way to download a file if the Content-Length is incorrectly set?
You could use a Socket and engage in HTTP yourself, which is less trivial than it sounds. But the problem is at the server and that's where it should be fixed. Complain. Or else #Zong Yu is correct and the page is HTML containing JavaScript, say.
NB You don't need to read the entire file into memory:
while((newLength = inputStream.read(buffer))>0)
{
curLength += newLength;
fos.write(buffer, 0, newLength);
}
My final "solution" was to realize I was dealing with a 301 redirect response and not the actual resource! I updated the section that handles my url, checking for a 301 and if exists, update the url. The new url contained the Content-Length that corresponded with the file I was downloading.
// start by creating an http url connection object
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
// determine if this is a redirect
boolean redirect = false;
int status = httpURLConnection.getResponseCode();
if (status != HttpURLConnection.HTTP_OK) {
if (status == HttpURLConnection.HTTP_MOVED_TEMP
|| status == HttpURLConnection.HTTP_MOVED_PERM
|| status == HttpURLConnection.HTTP_SEE_OTHER)
redirect = true;
}
// if it is, we need a new url
if (redirect) {
String newUrl = httpURLConnection.getHeaderField("Location");
httpURLConnection = (HttpURLConnection) new URL(newUrl).openConnection();
}
Try Fetch. Fetch is an in app download manager for Android. It's very easy to use. Find the GitHub page here. The project comes with several demos that you can try out. Disclaimer: I'm the creator of Fetch, and it is open source.
Welcome
I need to download sycnronously (one at time) a lot of small remote images (between 50kb and 100kb) from a server and to store them as PNG in the device. I need to achieve this without third party libraries and I'm using this code but it is too munch slow:
URL javaUrl = new URL(URLParser.parse(this.url));
URLConnection connection = javaUrl.openConnection();
InputStream input = new BufferedInputStream(javaUrl.openStream());
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte data[] = new byte[1024];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
total += count;
output.write(data, 0, count);
}
// conversion to bitmap
InputStream in = new ByteArrayInputStream(output.toByteArray());
Bitmap original = BitmapFactory.decodeStream(in);
// storing bitmap as PNG file
FileOutputStream out = new FileOutputStream(filename);
original.compress(Bitmap.CompressFormat.PNG, 90, out);
output.flush();
output.close();
input.close();
in.close();
original.recycle();
The problem is that the download is very slow. With very fast WIFI internet in the device (13MB, download speed of 1.4mbytes/s), it is taking 3-4 seconds to download the image in the device, but only 100-200ms to download the image in my PC using google chrome for example.
It is something wrong in my download algorithm? can be improved?
Thanks
You have a totally unnecessary byte array in the middle.
BitmapFactory.decodeStream() accepts an InputStream and you get an InputStream from URL.openStream().
It might not give you the speed boost you're looking for, but it'll at least get rid of a completely useless step in your code.
in my Android app I need to download a ~40 MB file, and I'm testing the code in my phone but the download speed is REALLY slow, I tried to download from different sources that are fast when using my PC.
Here is the code I use in the download service:
URLConnection conexion;
URL url;
int lenghtOfFile = 0;
try {
url = new URL("<URL>");
conexion = url.openConnection();
conexion.connect();
lenghtOfFile = conexion.getContentLength();
try {
File f = new File(Environment.getExternalStorageDirectory() + "/testing");
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream(f.getAbsolutePath());
byte data[] = new byte[1024];
long total = 0;
while ((count = input.read(data)) != -1) {
total += count;
notification.contentView.setProgressBar(R.id.status_progress, 100, (int) (total * 100 / lenghtOfFile), false);
notification.contentView.setTextViewText(R.id.status_text, Long.toString(total * 100 / lenghtOfFile));
notificationManager.notify(42, notification);
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
} catch (Exception e) {
e.getCause();
e.getMessage();
}
} catch (Exception e) {
}
}
Is it possible that this code is the reason of the slow dl speeds? Any ideas on how to make the download speed faster?
change this
byte data[] = new byte[1024];
to
byte data[] = new byte[4096];
and as commonsware said,
update your download progress notification in less frequencies.
for eg:
use a simple counter variable in your loop, and update progress when it reaches 10, and then resetting it..!
Maybe you would be better served using DownloadManager.
Android will download the file for you.
if DownloadProvider does not suit you, You could atleast benchmark your code.
You are performing IPC every 1KB of download, as you update your Notification. For a 40MB file, this means you are performing approximately 40,000 IPC calls. Please update your Notification much less frequently.
I suspect that the core problem is the network bandwidth / data rate that your (Android phone's) ISP is providing is much less than your PC gets via its LAN / broadband connection. It could be that your phone is getting a weak signal from the local cell, or that the cell is overloaded, or the backbone is overloaded, or that your ISP has poor peering arrangements.
If that is the problem, there's not much you can do about it except (maybe) change phone carriers or reconfigure your (home?) networking so that your phone can use WiFi to talk to your local WiFi router.
I have an app that is downloading a zip file and then copying this file to a temporary file on the sd card on the phone, but it is being very very slow.
InputStream in = new BufferedInputStream(url.openStream(), 1024);
File tempFile = File.createTempFile("arc", ".zip", targetDir); //target dir is a file
String tempFilePath = tempFile.getAbsolutePath();
OutputStream out = new BufferedOutputStream(new FileOutputStream(tempFile));
//copying file (in different void)
byte[] buffer = new byte[8192];
int len;
len = in.read(buffer);
enter code here
//it loops here for AGES
while (len >= 0) {
out.write(buffer, 0, len);
len = in.read(buffer);
}
in.close();
out.close();
My file is about 20MB, initially I had the buffer size of 1024, and changed it to 8192 thinking it may speed it up but it seemed to make no difference? I always finishes, and I get no errors it just takes ages!
I have searched to try and find a solution but I'm not coming up with anything so I may be going about this totally the wrong way?
Can anyone see what I'm doing wrong?
Bex
Donot increase buffer size. That may cause your application MemoryOutOfBoundsException.
There are varous factors for which your download will be slow. Weak internet connection, Weak file transfer and receiveing mode is also responsible. It also depend on capacity of device. Check whether you are using following code to create inputstream
URL u = new URL("enter url url here");
HttpURLConnection c = (HttpURLConnection) u.openConnection();
c.setRequestMethod("GET");
c.setDoOutput(true);
c.connect();
InputStream in = c.getInputStream();
Thanks
Deepak
I would like to implement a function where you send a URL of a photo and my server will automatically download and store it in a specified folder.
I studied some use cases, but as a beginner in this area of the web, I was a bit lost. I thought about FTP but is not exactly what I want.
Like that, function on my webservice (using Java + Tomcat + AXIS2)
void getPhoto(URL url){
//receive a photo and store at folder /photos
}
but, I don't know what use, I was looking for some httppost or httpget, should I still looking for in this way? Has a dummie sample, to show me the basic way?
I would like to implement a function where you send a URL of a photo and my server will automatically download and store it in a specified folder.
That's not exactly "uploading", but just "downloading".
Just call openStream() on the URL and you've an InputStream which you can do anything with. Writing to a FileOutputStream for example.
InputStream input = url.openStream();
// ...
hey use this code to download.
try {
URL url = new URL(url of file );
URLConnection conection = url.openConnection();
conection.connect();
InputStream input = new BufferedInputStream(url.openStream());
String downloadloc = "D:\"; // or anything
OutputStream output = new FileOutputStream(downloadloc
+ "\name of file.ext");
byte data[] = new byte[1024];
long total = 0;
while ((count = input.read(data)) != -1) {
total += count;
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
} catch (Exception e) {
}
You want to look at using an HttpURLConnection, call it's 'connect' and 'getInputStream' methods, continually reading from that stream and writing that data to a file with e.g. a FileOutputStream.
To download a file using a URL, as an alternative to what suggested by others, you can take a look to Apache Commons HttpClient.
There is also a well written tutorial.