URLConnection.getContentLength() returns -1 on Android KitKat - android

I'm new to Android and developing a file downloading app with a ProgressDialog which shows the downloading percentage.
I use AsyncTask and here is the trouble part of my code.
protected String doInBackground(String... f_url){
int count;
try {
URL url = new URL(f_url[0]);
URLConnection conn = url.openConnection();
conn.connect();
// getting file length
int lenghtOfFile = conn.getContentLength();
// input stream to read file - with 8k buffer
InputStream input = new BufferedInputStream(url.openStream(), 8192);
File direct = new File(folder);
if(!direct.exists()) {
direct.mkdirs();
}
// Output stream to write file
OutputStream output = new FileOutputStream(apkPath);
byte data[] = new byte[1024];
long total = 0;
while ((count = input.read(data)) != -1) {
total += count;
// publishing the progress....
// After this onProgressUpdate will be called
publishProgress(""+(int)((total*100)/lenghtOfFile));
// writing data to file
output.write(data, 0, count);
}
// flushing output
output.flush();
// closing streams
output.close();
input.close();
} catch (Exception e) {
Log.e("Error: ", e.getMessage());
}
return null;
}
My issue is this code works really well on Android API 16 (JB) but not on API 19 (KitKat). On KitKat devices, the progress bar percentage does not update (always 0). After checking the codes, I found conn.getContentLength() returns -1 when I run it on KitKat. So it can not update the progress. But it returns correct file size when I run it on API 16 (JB).
Can somebody please help me to solve this?
Thank you in advance.

Have you read Migrating to WebView in Android 4.4: http://developer.android.com/guide/webapps/migrating.html
Blockquote
If you call methods on WebView from any thread other than your app's UI thread, it can cause unexpected results. For example, if your app uses multiple threads, you can use the runOnUiThread() method to ensure your code executes on the UI thread:
runOnUiThread(new Runnable() {
#Override
public void run() {
// Code for WebView goes here
}
});

You can try this:
conn.setRequestProperty("Accept-Encoding", "identity");

Related

Android - Best Practice for Downloading Medium - Large Files Quickly

I need to download a few large zip files into my application (each approx 25mb) however it seems quite slow (5 minutes +) and when we test the same files being downloaded on an iPad it's downloading several times faster. I've considered using Volley, however it seems asynctask is the best for large files (from what I've read).
Does anyone have any suggestions or ideas on how I might be able to download/write these files faster?
My current implementation is show below:
My AsyncTaskExample:
#Override
protected String doInBackground(String... sUrl) {
InputStream input = null;
OutputStream output = null;
HttpURLConnection connection = null;
try {
URL url = new URL(sUrl[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
// expect HTTP 200 OK, so we don't mistakenly save error report
// instead of the file
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
return "Server returned HTTP " + connection.getResponseCode()
+ " " + connection.getResponseMessage();
}
// this will be useful to display download percentage
// might be -1: server did not report the length
int fileLength = connection.getContentLength();
// download the file
input = connection.getInputStream();
output = new FileOutputStream("/sdcard/file_name.extension");
byte data[] = new byte[1024];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
// allow canceling with back button
if (isCancelled()) {
input.close();
return null;
}
total += count;
// publishing the progress....
if (fileLength > 0) // only if total length is known
publishProgress((int) (total * 100 / fileLength));
output.write(data, 0, count);
}
} catch (Exception e) {
return e.toString();
} finally {
try {
if (output != null)
output.close();
if (input != null)
input.close();
} catch (IOException ignored) {
}
if (connection != null)
connection.disconnect();
}
return null;
}
AsyncTask should be used only for relatively short background processes (i.e. processes that last a few seconds). From the docs:
AsyncTask is designed to be a helper class around Thread and Handler
and does not constitute a generic threading framework. AsyncTasks
should ideally be used for short operations (a few seconds at the
most.) If you need to keep threads running for long periods of time,
it is highly recommended you use the various APIs provided by the
java.util.concurrent package such as Executor, ThreadPoolExecutor and
FutureTask.
For long operations you should use a Service:
A Service is an application component representing either an
application's desire to perform a longer-running operation while not
interacting with the user or to supply functionality for other
applications to use.

Check integrity of Database SQLite Android

I have a SQLite database file in my server, and from time to time my Android App checks if there is a new SQLite database file. If true the App downloads the File and replaces the old database.
The problem is, that some times the new database file gets corrupted and the App start to crashing and never recovers if I dont manualy clean the app in the Android Settings.
My question is, there is a way to check the integrity of SQLite Database after the Downloaded?
This is my code for download the new Database from the server this code is placed in an AssyncTask :
protected Boolean doInBackground(String... Url) {
try {
URL url = null;
if(Url[0].equals("")){
mSyncDate = mConnectionManager.getSyncDate();
url = new URL(Constants.HF_SERVER_DATABASE+"db_fxbus_"+convertDateToFormatYYYYMMDD(mSyncDate.getServerDate())+".sqlite");
}else{
url = new URL(Url[0]);
}
URLConnection connection = url.openConnection();
connection.connect();
// this will be useful so that you can show a typical 0-100% progress bar
int fileLength = connection.getContentLength();
mDB.getReadableDatabase();
// download the file
InputStream input = new BufferedInputStream(url.openStream());
Log.i(TAG, "Path:"+mContext.getDatabasePath("HorariosDoFunchal").getAbsolutePath());
OutputStream output = new FileOutputStream(mContext.getDatabasePath("HorariosDoFunchal").getAbsolutePath());
startWriting = true;
byte data[] = new byte[1024];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
total += count;
// publishing the progress....
publishProgress((int) (total * 100 / fileLength));
output.write(data, 0, count);
//Log.i(TAG, "Executing ...");
}
//Log.i(TAG, "Finish ...");
output.flush();
output.close();
input.close();
} catch (Exception e) {
Log.e(TAG, e.toString());
return false;
}
return true;
}
Look into:
pragma integrity_check;
it will scan the Database and check it for errors and other things too.
More info(and more commands) can be found at this link:
http://www.sqlite.org/pragma.html
also check out the documentation of isDatabaseIntegrityOk().
You could try to use PRAGMA integrity_check (or Android's equivalent isDatabaseIntegrityOk()), but this checks only the database structure for errors, and can detect only errors where it can prove that the structure is wrong.
To be able to detect all errors (especially in your own data), you need to compute a checksum for the entire database file.

Android Check if connection was interrupted

My app needs to download a database from the internet. This is done in an AsyncTask so when the database is being downloaded it't is being shown a Progress Dialog.
This is the code for the database download:
public void downloadDB(String dbFile, String dbFileName) {
int count;
try {
URL url = new URL(dbFile);
URLConnection conection = url.openConnection();
conection.connect();
InputStream input = new BufferedInputStream(url.openStream(), 8192);
OutputStream output = new FileOutputStream(ctx.getApplicationInfo().dataDir + "/databases/" + dbFileName);
byte data[] = new byte[1024];
while ((count = input.read(data)) != -1) {
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
} catch (IOException e) {
Log.e("Error: ", e.getMessage());
}
}
}
I'm doing some tests and when the database is being downloaded I turn off the internet connection. The problem is that the Progress Dialog doesn't terminate (it's in an infinite loop). I was expecting that after turning off the internet, there would be the IOException, the function returned to the doInBackground method of AsyncTask and executed the onPostExecute method where I dismiss the Progress Dialog.
The strange thing is that if I have my phone disconnected from the computer, the progress dialog is never dismissed, the same thing if I'm running the app with phone connected to computer and looking at the log cat. If I enter debug mode, the downloadDB ends and is returned to the caller and then, the progress dialog is dismissed.
What can I do to return from the downloadDB function when the network is turned off?

AsyncTask - slow download

I am using AsyncTask to download ~50 MB files from internet. Sometimes, when I download this file, progress bar gain is very slow (even when I am on Wi-Fi). And after minute, phone shows me, download complete, but the file itself has only ~100kB, no more. But when I restart device, and try to download file, download is executed briefly and quick. Has anyone faced same problem? Do I need to erase same download memory before downloading new file? I am downloading file to Environment.externalStoryDirectory().
Thx
Calling download from activity:
mProgressDialog = new ProgressDialog(ItemDetails.this);
mProgressDialog.setTitle("Downloading");
mProgressDialog.setMessage("Downloading sth...");
mProgressDialog.setIndeterminate(false);
mProgressDialog.setMax(100);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
DownloadMapTask downloadFile = new DownloadMapTask(ItemDetails.this);
downloadFile.execute(web_location_url);
mProgressDialog.show();
Download Async Task (two methods):
#Override
protected String doInBackground(String... urls) {
int count;
PATH=maps_loc+"/Android/data/test/maps/";
try {
URL url = new URL(urls[0]);
HttpURLConnection connection2 = (HttpURLConnection) url.openConnection();
connection2.setRequestMethod("GET");
connection2.setDoOutput(true);
connection2.connect();
int lenghtOfFile = connection2.getContentLength();
File apkdir = new File(PATH);
apkdir.mkdirs();
File newInstall = new File(PATH, name+".tmp");
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream(newInstall);
byte data[] = new byte[1024];
long total = 0;
while ((count = input.read(data)) != -1 && running==true) {
total += count;
publishProgress((int) (total * 100 / lenghtOfFile));
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public void onProgressUpdate(Integer... args) {
ItemDetails.mProgressDialog.setProgress(args[0]);
}
Some servers will close the connection if the client has slow speed and the download takes long time, which can be the case if your program is connected to the Internet through mobile data not Wi-Fi.
You should consider supporting download resume in your program to not start from scratch every time.
I do not think there is sort of download memory that you need to clear. I have an app that can easily downloads over 50MB with no problems.
Also, you might consider obtaining a lock for both Wi-Fi and processor to keep your program running until the download finishes.
Edit
In your code, try to print the value lenghtOfFile after the line int lenghtOfFile = connection2.getContentLength(); to make sure that it is the same as the actual file size you are downloading.
Below is alternative example code which supports resume that I am using in my projects. (it is just to illustrate the idea, you will need to modify the code to your needs)
HttpClient httpClient = new DefaultHttpClient();
HttpGet request = new HttpGet(new URI(fileURL)));
HttpResponse response;
InputStream is = null;
FileOutputStream fos = null;
try {
boolean continueDownloading = false;
String tmpFileName = fileName + "_tmp";
outputFile = new File(downloadFolder, tmpFileName);
if (outputFile.exists()) {
localFileLength = outputFile.length();
if (localFileLength > 0) {
continueDownloading = true;
}
if (continueDownloading) {
request.addHeader("Range", "bytes=" + localFileLength + "-");
}
response = httpClient.execute(request);
long remoteFileLength = 0;
Header contentLengthHeader = response.getFirstHeader("Content-Length");
if (contentLengthHeader != null) {
remoteFileLength = Integer.parseInt(contentLengthHeader.getValue());
}
long downloaded = 0;
if (continueDownloading) {
downloaded = localFileLength;
}
long fullFileLength = downloaded + remoteFileLength;
fos = new FileOutputStream(outputFile, true);
is = response.getEntity().getContent();
byte[] buffer = new byte[DOWNLOAD_BUFFER_SIZE];
int len = 0;
while ((len = is.read(buffer)) != -1 && isDownloading) {
fos.write(buffer, 0, len);
downloaded += len;
}
fos.flush();
boolean success = downloaded == fullFileLength;
if (success) {
outputFile.renameTo(new File(downloadFolder, fileName));
}
} catch (Throwable ex) {
ex.printStackTrace();
} finally {
// clean up resources
}
Try using downloadManager instead of downloading manually , there are many advantages to using it.
Here is an example for it : DownloadManager Example
and take a look at the documentations : DownloadManager

Android: download file from server and show the download progress in the notification bar using AsyncTask

I am using this example to download a file from a server using AsycTask and to show the downlaod progress in a notification bar. I just modified the doInBackground method in order to downoad my file:
#Override
protected Void doInBackground(String... Urls) {
//This is where we would do the actual download stuff
//for now I'm just going to loop for 10 seconds
// publishing progress every second
try {
URL url = new URL(Urls[0]);
URLConnection connection = url.openConnection();
connection.connect();
// this will be useful so that you can show a typical 0-100%
// progress bar
int fileLength = connection.getContentLength();
// download the file
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream( _context.getFilesDir() + "/file_name.apk");
byte data[] = new byte[1024];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
total += count ;
// publishing the progress....
publishProgress((int) (total * 100 / fileLength));
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
}
catch (Exception e){
e.printStackTrace();
}
return null;
}
protected void onPreExecute() {
// Create the notification in the statusbar
mNotificationHelper.createNotification();
}
protected void onPostExecute(Void result) {
// The task is complete, tell the status bar about it
mNotificationHelper.completed();
}
protected void onProgressUpdate(Integer... progress) {
// This method runs on the UI thread, it receives progress updates
// from the background thread and publishes them to the status bar
mNotificationHelper.progressUpdate(progress[0]);
}
Everything is going ok except that I cannot pull down the notification bar. Why?
Following is picked from the comments.
can you please put an sleep(1000) method before publishProgress and
check. just a guess
-
yes, it works, but the download is slowing
Hope you understood the problem. Since you are updating the Notification bar very frequently, you cant be able to pull it down. By increasing the chunk size of data or by updating the progress bar on every 4 or more kb instead of 1kb, you can avoid this problem.
Above will not slow down the data download.
You should override onProgressUpdate method to update your UI.

Categories

Resources