简体   繁体   中英

Monitoring BufferedInputStream download progress

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?

Wrap URL input stream with you own InputStream that just reads bytes and "monitors" the status, eg 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.

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]));
        }

    }


}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM