I have a strangle behavior when implementing AsynTask and ProgressDialog. When i download small file, everything works fine, the progress status is updated from 0% to 100%. But when i download larger files, the number on ProgressDialog runs to 6 or 7% then it is not updated anymore. But after 2,3 minutes, i receive a messge that asyntask task finished the downloading process.
public class DownloadHelper extends AsyncTask<String, Integer, Long> implements DialogInterface.OnDismissListener{
private volatile boolean running = true;
private PhonegapActivity _ctx = null;
private ProgressDialog _progressDialog = null;
private String _title = null;
private File _root = null;
private File _destination = null;
private DatabaseHelper _dbHelper = null;
private Cursor _cursorMedia = null;
public DownloadHelper(String title, File root, File destination, DatabaseHelper dbHelper, PhonegapActivity ctx){
_title = title;
_ctx = ctx;
_root = root;
_destination = destination;
_dbHelper = dbHelper;
}
@Override
protected void onPreExecute() {
if (_progressDialog != null)
{
_progressDialog.dismiss();
_progressDialog = null;
}
_progressDialog = new ProgressDialog(_ctx);
_progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
_progressDialog.setTitle("Downloading");
_progressDialog.setMessage(_title);
_progressDialog.setCancelable(true);
_progressDialog.setMax(100);
_progressDialog.setProgress(0);
/*_progressDialog.setOnCancelListener(
new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) {
_progressDialog = null;
running = false;
}
});
_progressDialog.setOnDismissListener(
new DialogInterface.OnDismissListener() {
public void onDismiss(DialogInterface dialog) {
Log.d("DownloadHelper", "canceled inside listener");
_progressDialog = null;
running = false;
}
}
);*/
_progressDialog.show();
running = true;
}
@Override
protected Long doInBackground(String... sUrl) {
try {
Log.d("DownloadHelper", "Start download from url " + sUrl[0]);
long total = 0;
total = _download(sUrl[0], _destination);
return total;
} catch (Exception ex2) {
ex2.printStackTrace();
Log.d("DownloadHelper", "Failed to download test file from " + sUrl[0] + " to " + _destination.getAbsolutePath().toString());
_closeProgressDialog();
}
return null;
}
protected void onCancelled(Long result) {
Log.d("DownloadHelper", "CANCELLED result = " + result);
_closeProgressDialog();
}
protected void onProgressUpdate(Integer... progress) {
if (_progressDialog != null && running)
{
Log.d("DownloadHelper", "UPDATED progess = " + progress[0]);
_progressDialog.setProgress(progress[0]);
}
else //cancel the task
{
Log.d("DownloadHelper", "onProgressUpdate cancelled");
cancel(true);
}
}
protected void onPostExecute(Long result) {
Log.d("DownloadHelper", "FINISHED result = " + result);
// Close the ProgressDialog
_closeProgressDialog();
running = false;
if (result != null) //OK
{
_showAlertDialog("Test has been downloaded successfully.", "Message", "OK");
}
else // error
{
_showAlertDialog("Can not download the test. Please try again later.", "Error", "OK");
}
}
@Override
protected void onCancelled() {
running = false;
}
public void onDismiss(DialogInterface dialog) {
Log.d("DownloadHelper", "Cancelled");
this.cancel(true);
}
protected void _closeProgressDialog(){
if (_progressDialog != null)
{
_progressDialog.dismiss();
_progressDialog = null;
}
}
protected void _showAlertDialog(final String message, final String title, final String buttonLabel){
AlertDialog.Builder dlg = new AlertDialog.Builder(_ctx);
dlg.setMessage(message);
dlg.setTitle(title);
dlg.setCancelable(false);
dlg.setPositiveButton(buttonLabel,
new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
dlg.create();
dlg.show();
}
protected Cursor _checkMedia() {
_dbHelper.openDatabase(_destination.getAbsolutePath());
Log.d("DownloadHelper", "Database is opened");
String[] columns = {"type, size, location, location_id, url"};
Cursor cursor = _dbHelper.get("media", columns);
_dbHelper.closeDatabase();
_dbHelper.close();
_dbHelper = null;
return cursor;
}
protected long _download(String sUrl, File destination) throws IOException {
URL url = new URL(sUrl);
URLConnection conexion = url.openConnection();
conexion.connect();
// this will be useful so that you can show a tipical 0-100% progress bar
int lenghthOfFile = conexion.getContentLength();
Log.d("DownloadHelper", "length of File = " + lenghthOfFile);
// downlod the file
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream(destination);
byte data[] = new byte[1024];
long total = 0;
int count;
// Reset the progress
_progressDialog.setProgress(0);
// Start downloading main test file
while ((count = input.read(data)) != -1 && running) {
total += count;
Log.d("DownloadHelper", "total = " + total);
// publishing the progress....
this.publishProgress((int)(total*100/lenghthOfFile));
output.write(data, 0, count);
}
if (running == false)
{
this.cancel(true);
}
output.flush();
output.close();
input.close();
return total;
}
}
I also add a Log.d message inside onProgressUpdate(), the debug messages show until the progress reaches 6 or 7% then nothing comes out anymore in the console (but the app still works because i don’t receive any error messages and the message of Gabrage Collector still shows in the console).
Here is my code
Does anyone have the some problems?
Edited
I changed the buffer size to 1MB as suggestion of DArkO, but it still doesn’t work. I think something is wrong with my while loop. I use log.d inside my while loop and have some like this in console:
D/DownloadHelper( 1666): length = **3763782**; total = 77356; percent = 2; save_percent = 0
D/DownloadHelper( 1666): UPDATED progess = 2
D/DownloadHelper( 1666): length = 3763782; total = 230320; percent = 6; save_percent = 0
D/DownloadHelper( 1666): UPDATED progess = 6
D/dalvikvm( 1666): GC freed 10241 objects / 1087168 bytes in 88ms
*D/DownloadHelper( 1666): FINISHED result = **230320***
The “FINISHED message” comes from onPostExecute(). This message came 1,2 minutes later after the progress dialog had stopped. As you can see the file is not downloaded completely.
I debug the my app with debug tool of eclipse, i can see that the asynctask thread hangs at this function
OSNetworkSystem.receiveStreamImpl(FileDescriptor, byte[], int, int, int) line: not available [native method]
you are updating it too often it cant display the updates in time and it blocks the ui thread.
consider using a handler with postDelayed to send a publishProgress update maybe every second or 2.
or alternatevely you can increase the buffer size so the loop isnt happening that often, right now you have it on 1024 bytes so maybe half a MB or something like that, but i would still go with the handler method instead. that way your updates and memory consumption doesnt depend on the progress updates.
EDIT:
here is the code i was using for one of my projects to download files. i have tested this with quite large files (between 50 and 100 mb) so it is definitely working. try it out.
you will notice i am using the notification’s bar to do the updates instead of a progress bar but the rest should be the same.