Question

I'm trying to download a file using an AsyncTask on Android. I want to display a ProgressDialog which should have a progress bar to show the status of the download. I'm using the onProgressUpdate() function for that and implemented a call to publishProgress() in my doInBackground() function. However, the progress dialog only pops up after downloading the file. My code:

protected Long doInBackground(URL...urls) {
    for (int i = 0; i < urls.length; i++) {
        url = urls[i];
        try {
            URLConnection conn = url.openConnection();
            conn.connect();
            totalSize = conn.getContentLength();

            BufferedInputStream bis = new BufferedInputStream(url.openStream());
            FileOutputStream fos = new FileOutputStream(Environment.getExternalStorageDirectory().getPath() + "/forvo_temp.mp3");
            BufferedOutputStream bos = new BufferedOutputStream(fos,1024);
            byte [] data = new byte[1024];

            int x=0; int c=0;
            while((x=bis.read(data,0,1024))>=0){
                bos.write(data,0,x);
                c += 1024;
                publishProgress(c);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    return 0L; // Don't know what to do with this
}

protected void onProgressUpdate(Integer...args) {
    pd = ProgressDialog.show(context, "Downloading...", "Downloading...", true, false);
    pd.setProgress(args[0] / totalSize);
}

I guess the whole file is downloaded when I call new BufferedInputStream(url.openStream()). How can I monitor the download progress?

Was it helpful?

Solution 2

This code is useful showing download items totol size and downloaded size.

private static final int DOWNLOAD_ONPROGRESS = 1;

@Override
protected Dialog onCreateDialog(int id) {
    switch (id) {
    case DOWNLOAD_ONPROGRESS:
        progressDialog = new ProgressDialog(this);

        progressDialog.setMessage("Downloading latest ...");
        progressDialog.setCancelable(true);
        progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        try {
            progressDialog.show();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return progressDialog;
    default:
        return null;
    }
}

You can use AsyncTask for downloading the version in background.

private class DownLoad extends AsyncTask<String, String, String> {

    @Override
    protected void onPreExecute() {
        // TODO Auto-generated method stub
        super.onPreExecute();
        logger.info("LoadDataAsync onPreExecute");
        showDialog(DOWNLOAD_ONPROGRESS);
    }

    @Override
    protected String doInBackground(String... aurl) {
        int count = 0;

        try {
            URL url = new URL(aurl[0]);
            URLConnection urlConnection = url.openConnection();
            urlConnection.connect();

            int contentlength = urlConnection.getContentLength();
            progressDialog.setMax(contentlength);
            String PATH = "";
            File file = null;
            if (android.os.Environment.getExternalStorageState().equals(
                    android.os.Environment.MEDIA_MOUNTED)) {
                PATH = Environment.getExternalStorageDirectory()
                        + "/download/";
                file = new File(PATH);

                file.mkdirs();

                File outputFile = new File(file, "telfaz.apk");
                OutputStream fos = new FileOutputStream(outputFile);

                InputStream is = new BufferedInputStream(url.openStream());

                byte[] buffer = new byte[1024];
                long len1 = 0;
                while ((count = is.read(buffer)) != -1
                        && !downLoad.isCancelled()) {
                    len1 += count;
                    publishProgress("" + len1);
                    fos.write(buffer, 0, count);
                }
                fos.flush();
                fos.close();
                is.close();

            }
            logger.info("Success -> file downloaded succesfully. returning 'success' code");
            return Util.APK_DOWNLOAD_SUCCESS;

        } catch (IOException e) {
            logger.error("Exception in update process : "
                    + Util.getStackTrace(e));
        }
        logger.info("Failed -> file download failed. returning 'error' code");
        return Util.APK_DOWNLOAD_FAILED;
    }

    @Override
    protected void onPostExecute(String result) {
        logger.info("on DownLoad onPostExecute. result : " + result);
        progressDialog.dismiss();
        removeDialog(DOWNLOAD_ONPROGRESS);
        if (result.equalsIgnoreCase(Util.APK_DOWNLOAD_SUCCESS)) {
            Update();

        } else {
            Toast.makeText(DownloadAllContentsActivity.this,
                    getString(R.string.updateApplicationFailed),
                    Toast.LENGTH_LONG).show();

            loadDataAsync.execute();

        }

    }

    @Override
    protected void onProgressUpdate(String... values) {
        if (values != null && values.length > 0) {
            progressDialog.setProgress(Integer.parseInt(values[0]));
        }

    }


}

OTHER TIPS

Wrap URL input stream with you own InputStream that just reads bytes and "monitors" the status, e.g. sends notifications.

It is simple: InputStream is an abstract class with only one abstract method:

public abstract int read() throws IOException;

In your case it should read bytes from stream that it wraps.

public class NotifcationInputStream extends InputStream {
    private InputStream in;
    private int count;
    private Collection<ByteListener> listeners = new ArrayList<ByteListener>();

    NotificationInputStream(InputStream in) {
         this.in = in;
    }

    public int read() throws IOException {
        int b = in.read(); 
        byteReceived(b);
        return b;
    }

    public void addListener(ByteListener listener) {
        listeners.add(listener);
    }

    private void byteReceived(int b) {
        for (ByteListener l : listeners) {
             l.byteReceived(b, ++count);
        }
    }
}


public interface ByteListener extends EventListener {
    public void byteReceived(int b, int count);
}

The problem here is how to show the process bar: you have to know total number of bytes. You can get it from HTTP header content-length if your resource is static. Otherwise you need appropriate server support or heuristics.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top