By Tom Leese


2010-06-12 10:22:56 8 Comments

I am trying to write a simple application that gets updated. For this I need a simple function that can download a file and show the current progress in a ProgressDialog. I know how to do the ProgressDialog, but I'm not sure how to display the current progress and how to download the file in the first place.

12 comments

@Cristian 2010-06-12 12:30:25

There are many ways to download files. Following I will post most common ways; it is up to you to decide which method is better for your app.

1. Use AsyncTask and show the download progress in a dialog

This method will allow you to execute some background processes and update the UI at the same time (in this case, we'll update a progress bar).

This is an example code:

// declare the dialog as a member field of your activity
ProgressDialog mProgressDialog;

// instantiate it within the onCreate method
mProgressDialog = new ProgressDialog(YourActivity.this);
mProgressDialog.setMessage("A message");
mProgressDialog.setIndeterminate(true);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressDialog.setCancelable(true);

// execute this when the downloader must be fired
final DownloadTask downloadTask = new DownloadTask(YourActivity.this);
downloadTask.execute("the url to the file you want to download");

mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {

    @Override
    public void onCancel(DialogInterface dialog) {
        downloadTask.cancel(true); //cancel the task
    }
});

The AsyncTask will look like this:

// usually, subclasses of AsyncTask are declared inside the activity class.
// that way, you can easily modify the UI thread from here
private class DownloadTask extends AsyncTask<String, Integer, String> {

    private Context context;
    private PowerManager.WakeLock mWakeLock;

    public DownloadTask(Context context) {
        this.context = context;
    }

    @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[4096];
            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;
    }

The method above (doInBackground) runs always on a background thread. You shouldn't do any UI tasks there. On the other hand, the onProgressUpdate and onPreExecute run on the UI thread, so there you can change the progress bar:

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        // take CPU lock to prevent CPU from going off if the user 
        // presses the power button during download
        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
             getClass().getName());
        mWakeLock.acquire();
        mProgressDialog.show();
    }

    @Override
    protected void onProgressUpdate(Integer... progress) {
        super.onProgressUpdate(progress);
        // if we get here, length is known, now set indeterminate to false
        mProgressDialog.setIndeterminate(false);
        mProgressDialog.setMax(100);
        mProgressDialog.setProgress(progress[0]);
    }

    @Override
    protected void onPostExecute(String result) {
        mWakeLock.release();
        mProgressDialog.dismiss();
        if (result != null)
            Toast.makeText(context,"Download error: "+result, Toast.LENGTH_LONG).show();
        else
            Toast.makeText(context,"File downloaded", Toast.LENGTH_SHORT).show();
    }

For this to run, you need the WAKE_LOCK permission.

<uses-permission android:name="android.permission.WAKE_LOCK" />

2. Download from Service

The big question here is: how do I update my activity from a service?. In the next example we are going to use two classes you may not be aware of: ResultReceiver and IntentService. ResultReceiver is the one that will allow us to update our thread from a service; IntentService is a subclass of Service which spawns a thread to do background work from there (you should know that a Service runs actually in the same thread of your app; when you extends Service, you must manually spawn new threads to run CPU blocking operations).

Download service can look like this:

public class DownloadService extends IntentService {
    public static final int UPDATE_PROGRESS = 8344;

    public DownloadService() {
        super("DownloadService");
    }
    @Override
    protected void onHandleIntent(Intent intent) {

        String urlToDownload = intent.getStringExtra("url");
        ResultReceiver receiver = (ResultReceiver) intent.getParcelableExtra("receiver");
        try {

            //create url and connect
            URL url = new URL(urlToDownload);
            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(connection.getInputStream());

            String path = "/sdcard/BarcodeScanner-debug.apk" ;
            OutputStream output = new FileOutputStream(path);

            byte data[] = new byte[1024];
            long total = 0;
            int count;
            while ((count = input.read(data)) != -1) {
                total += count;

                // publishing the progress....
                Bundle resultData = new Bundle();
                resultData.putInt("progress" ,(int) (total * 100 / fileLength));
                receiver.send(UPDATE_PROGRESS, resultData);
                output.write(data, 0, count);
            }

            // close streams 
            output.flush();
            output.close();
            input.close();

        } catch (IOException e) {
            e.printStackTrace();
        }

        Bundle resultData = new Bundle();
        resultData.putInt("progress" ,100);

        receiver.send(UPDATE_PROGRESS, resultData);
    }
}

Add the service to your manifest:

<service android:name=".DownloadService"/>

And the activity will look like this:

// initialize the progress dialog like in the first example

// this is how you fire the downloader
mProgressDialog.show();
Intent intent = new Intent(this, DownloadService.class);
intent.putExtra("url", "url of the file to download");
intent.putExtra("receiver", new DownloadReceiver(new Handler()));
startService(intent);

Here is were ResultReceiver comes to play:

private class DownloadReceiver extends ResultReceiver{

    public DownloadReceiver(Handler handler) {
        super(handler);
    }

    @Override
    protected void onReceiveResult(int resultCode, Bundle resultData) {

        super.onReceiveResult(resultCode, resultData);

        if (resultCode == DownloadService.UPDATE_PROGRESS) {

            int progress = resultData.getInt("progress"); //get the progress
            dialog.setProgress(progress);

            if (progress == 100) {
                dialog.dismiss();
            }
        }
    }
}

2.1 Use Groundy library

Groundy is a library that basically helps you run pieces of code in a background service, and it is based on the ResultReceiver concept shown above. This library is deprecated at the moment. This is how the whole code would look like:

The activity where you are showing the dialog...

public class MainActivity extends Activity {

    private ProgressDialog mProgressDialog;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        findViewById(R.id.btn_download).setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                String url = ((EditText) findViewById(R.id.edit_url)).getText().toString().trim();
                Bundle extras = new Bundler().add(DownloadTask.PARAM_URL, url).build();
                Groundy.create(DownloadExample.this, DownloadTask.class)
                        .receiver(mReceiver)
                        .params(extras)
                        .queue();

                mProgressDialog = new ProgressDialog(MainActivity.this);
                mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                mProgressDialog.setCancelable(false);
                mProgressDialog.show();
            }
        });
    }

    private ResultReceiver mReceiver = new ResultReceiver(new Handler()) {
        @Override
        protected void onReceiveResult(int resultCode, Bundle resultData) {
            super.onReceiveResult(resultCode, resultData);
            switch (resultCode) {
                case Groundy.STATUS_PROGRESS:
                    mProgressDialog.setProgress(resultData.getInt(Groundy.KEY_PROGRESS));
                    break;
                case Groundy.STATUS_FINISHED:
                    Toast.makeText(DownloadExample.this, R.string.file_downloaded, Toast.LENGTH_LONG);
                    mProgressDialog.dismiss();
                    break;
                case Groundy.STATUS_ERROR:
                    Toast.makeText(DownloadExample.this, resultData.getString(Groundy.KEY_ERROR), Toast.LENGTH_LONG).show();
                    mProgressDialog.dismiss();
                    break;
            }
        }
    };
}

A GroundyTask implementation used by Groundy to download the file and show the progress:

public class DownloadTask extends GroundyTask {    
    public static final String PARAM_URL = "com.groundy.sample.param.url";

    @Override
    protected boolean doInBackground() {
        try {
            String url = getParameters().getString(PARAM_URL);
            File dest = new File(getContext().getFilesDir(), new File(url).getName());
            DownloadUtils.downloadFile(getContext(), url, dest, DownloadUtils.getDownloadListenerForTask(this));
            return true;
        } catch (Exception pokemon) {
            return false;
        }
    }
}

And just add this to the manifest:

<service android:name="com.codeslap.groundy.GroundyService"/>

It couldn't be easier I think. Just grab the latest jar from Github and you are ready to go. Keep in mind that Groundy's main purpose is to make calls to external REST apis in a background service and post results to the UI with easily. If you are doing something like that in your app, it could be really useful.

2.2 Use https://github.com/koush/ion

3. Use DownloadManager class (GingerBread and newer only)

GingerBread brought a new feature, DownloadManager, which allows you to download files easily and delegate the hard work of handling threads, streams, etc. to the system.

First, let's see a utility method:

/**
 * @param context used to check the device version and DownloadManager information
 * @return true if the download manager is available
 */
public static boolean isDownloadManagerAvailable(Context context) {

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
        return true;
    }
    return false;
}

Method's name explains it all. Once you are sure DownloadManager is available, you can do something like this:

String url = "url you want to download";
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.setDescription("Some descrition");
request.setTitle("Some title");
// in order for this if to run, you must use the android 3.2 to compile your app
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    request.allowScanningByMediaScanner();
    request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
}
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "name-of-the-file.ext");

// get download service and enqueue file
DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);

Download progress will be showing in the notification bar.

Final thoughts

First and second methods are just the tip of the iceberg. There are lots of things you have to keep in mind if you want your app to be robust. Here is a brief list:

  • You must check whether user has an internet connection available
  • Make sure you have the right permissions (INTERNET and WRITE_EXTERNAL_STORAGE); also ACCESS_NETWORK_STATE if you want to check internet availability.
  • Make sure the directory were you are going to download files exist and has write permissions.
  • If download is too big you may want to implement a way to resume the download if previous attempts failed.
  • Users will be grateful if you allow them to interrupt the download.

Unless you need detailed control of the download process, then consider using DownloadManager (3) because it already handles most of the items listed above.

But also consider that your needs may change. For example, DownloadManager does no response caching. It will blindly download the same big file multiple times. There's no easy way to fix it after the fact. Where if you start with a basic HttpURLConnection (1, 2), then all you need is to add an HttpResponseCache. So the initial effort of learning the basic, standard tools can be a good investment.

This class was deprecated in API level 26. ProgressDialog is a modal dialog, which prevents the user from interacting with the app. Instead of using this class, you should use a progress indicator like ProgressBar, which can be embedded in your app's UI. Alternatively, you can use a notification to inform the user of the task's progress. For more details Link

@Michael Little 2011-02-14 13:23:21

Cristian, I know this has been here for a while but I was wondering if you wouldn't mind showing me how to get the progress bar to show. I used the example you gave and it works great (file downloads) but I never get a progress bar. Thanks a ton. Mike

@marlar 2011-06-24 11:06:19

Isn't there a confusion between ProgressDialog and ProgressBar in the example? When I try it, the compiler complains.

@Felipe Sabino 2011-12-06 18:53:45

I have some problems with https urls after conexion.connect();. While debugging, I verified that there is a flag in the conecion object named connected that is set to false. Do you have any clue how to solve this? Or what extra steps should be made for successful https downloads? tks!

@Felipe Sabino 2011-12-06 19:15:10

I just found that it might be a bug on android <= 2.2 code.google.com/p/android/issues/detail?id=15503

@Gökhan Barış Aker 2012-01-02 12:11:37

I know it might not be important. Still considering the performance stuff, using progressDialog.setMax(lenghtOfFile), and publishProgress(total) wouldn't be more efficient? As there are lots of divisions and multiplications in (int)(total*100/lenghtOfFile). Edit: As i double check long data type is deal breaker here, as progress bar demans int, but connection.getContentLength() returns int, which makes long data type seems useless. Am i confused? Yes :). Seeking your enlightment of wisdom, masters...

@Mark 2012-08-21 06:57:33

Isn't there a problem that if the DownloadManager is not available you still need to code your own download code (even if your minSdkLevel is >= GB)?

@Cristian 2012-08-22 16:16:58

DownloadManager is part of the OS, which means it will always be available in GB+ and cannot be uninstalled.

@vinaykumar 2012-09-15 05:45:56

@Cristian, is it possible to update progressBar of activity layout using DownloadMangaer?, if it is possible could you help me with snippet. Thank you.

@Cristian 2012-09-17 14:48:56

Yes it is possible, just read the DownloadManager documentation. You will need to query that data using a content provider

@NagarjunaReddy 2012-10-04 07:25:03

@Cristian I am using Async Task for my App displaying contacts but faceing errors see my question any Idea replay me please stackoverflow.com/questions/12709799/…

@Steven Magana-Zook 2012-10-26 04:06:29

Way to go! I have never seen a more thorough answer on SO.

@Mark 2012-11-16 05:47:51

If DownloadManager is part of the OS (GB+) then wouldn't it be sufficient to check the Build.VERSION.SDK_INT? Is it for sure included in the Kindle Fire devices?

@nLL 2012-11-16 11:42:52

There is a problem in Cristian's answer. Because code at "1. Use AsyncTask and show the download progress in a dialog" does connection.connect(); then InputStream input = new BufferedInputStream(url.openStream()); code makes 2 connections to the server. I have managed to change this behavior by updating the code as follows InputStream input = new BufferedInputStream(connection.getInputStream());

@Cristian 2012-11-16 17:38:42

Thanks for your help... do not hesitate to editing the answer if you want.

@LOG_TAG 2012-11-24 06:13:34

thanks, really helpful information, Any body knows multithreading download library in android for faster paralleled download for the single file?

@Cristian 2012-11-26 08:01:07

Groundy library allows you to do that.

@Lou Morda 2012-11-28 23:08:27

i wish android documentation was this concise.

@Pang 2013-01-26 10:02:56

Suggested to close() the streams (input and output) in finally instead of try, otherwise if any exception is thrown before close(), you have unclosed streams hanging around.

@Cristian 2013-01-26 19:00:31

You are right... just wanted to keep the example as clear as possible. Thanks a lot.

@Akhil Jain 2013-02-03 10:25:50

can you please tell how to implement the same for image view?/, when clicked on a button, set the bitmap image on imageview

@Cristian 2013-02-03 20:31:41

In that case, you better take a look at the wasp library: github.com/casidiablo/wasp

@HGPB 2013-02-13 11:51:48

How should you do this inside a SyncAdapter?

@Marek Sebera 2013-04-27 08:07:12

Isn't there option, without using WRITE_EXTERNAL_STORAGE permission? ad. stackoverflow.com/q/16210894/492624

@Alfie Hanssen 2013-06-18 17:28:19

Using the DownloadManager approach, what is the best way to report progress (bytes downloaded) and update a progress bar?

@nawara 2013-06-19 12:49:39

@Cristian it is possible to use one of those method to download file from my own PC and save it later on sd card using an url to web server like apache tomcat ..?

@Cristian 2013-06-21 01:57:35

@Alfie I think you can use the DownloadManager's Content Provider: stackoverflow.com/questions/5069919/…

@CoronaPintu 2013-10-07 05:28:48

@Dowanload manager will not work in 2.2 then what is other way?

@Cristian 2013-10-07 05:37:22

There are three ways listed; two of them work with 2.2

@speedynomads 2013-12-10 18:18:54

AsyncTask method worked great for me. Thanks

@midnightstar 2013-12-27 17:46:32

Why is the size of the byte buffer 4096 in the AsyncTask example? This means the buffer can store up to 4096 bytes at a time right?

@Cristian 2013-12-27 23:15:47

@midnightstar take a look at this: stackoverflow.com/questions/16067199/… there are more threads, if you want to expand on that.

@Max The Cat 2014-01-09 05:59:27

I've used your "Download from Service" approach, but mProgressDialog, created in activity, is not getting updated. Progress handler is called with correct paramaters, but progress is not changing. What can be the issue?

@Cristian 2014-01-09 23:51:44

Show the code somewhere... gist would do it.

@Marcel Marino 2014-02-20 16:35:08

#1 is working for me sorta kinda. I switched it to "Style_SPINNER" to avoid having to show the progress, but I can't find anywhere to put onPreExecute() and the other functions in that section. It says it runs on the UI thread, but when I place it there I get nothing but error messages. It works, but the Download progress dialog never goes away on its own, and that's problematic.

@amIT 2014-03-13 18:14:36

havent seen such a through answer on stackoverflow in a while. thumbs up for Intent service with result reciever

@ItsNotAboutTheName 2014-04-07 19:29:22

Don't hardcode /sdcard/ use Environment.getExternalStorageDirectory() instead.

@Cristian 2014-04-07 20:13:40

@Nima you are right. Feel free to edit the answer!

@Saeed.re 2014-06-30 11:08:00

How can I pause/stop the download process in Intent service method ?? check my question plz stackoverflow.com/questions/24480206/…

@Alston 2014-08-25 06:15:37

Which approach should I adopt if I need to download lots of files at the same time? I'm afraid the overhead of multi-threading would be very heavy.

@Alston 2014-09-30 07:52:31

@Cristian If a progressbar is shown within a listview and the user leave the page. In this time, the progressbar would detach the window and the progress information would lost. Any solution to address the issue? THANKS!

@Nitesh Khatri 2014-10-15 17:56:18

@Cristian Thanks for the great piece of code. I am implementing your 2nd approach "Download from Service". Can you please tell me how to implement pause and resume feature in this? Since I am downloading large files, internet connection might break in between or the user may want to pause the download and resume later.

@eoinzy 2014-11-13 11:21:47

I'm not even using this code, but +1 for putting in the effort of making such a good answer!!

@Fabiano 2015-02-25 23:35:06

Take note that when using the 3rd option within a Java library separated from app, you will need to pass the Context object to the function that will use the method getSystemService. Using this statement alone will work only inside an Activity.

@Romain 2015-03-25 09:48:47

You will leak your context if the activity is killed.

@icastell 2015-06-09 17:22:23

For the 3 option take note that some Samsung Galaxy devices like S5 and S6 are returning false for the isDownloadManagerAvailable() call. I'm speaking for my own experience, the best way to know if the DownloadManager is avaiable is simply checking the android version is above or equals to Gingerbread.

@Deb 2015-08-14 06:20:43

For method 1, if you are intitializing the progressbar in a fragment then do this:

@MaSepehr 2015-08-22 12:55:38

how could i send Authorization username and password with connection in method 2?

@zackygaurav 2015-11-22 07:25:12

If you're using AsyncTask, replace Exception with IOException in catch block

@Salmaan 2015-12-08 05:09:30

Solution 1 is not working. First it downloads the data and then updates the progress dialog please see stackoverflow.com/questions/34134013/…

@Kenji 2016-01-30 11:05:11

hi, thanks for guid. Can we use both DownloadManager and Update Ui at same time?

@GreenROBO 2016-02-24 09:39:01

@Cristian Worked on your solution No.2. It's working superb! now Suppose I've started this DownloadService for File A, File B and File C. Now I want to Cancel Downloading file A. I am killing the process. It's killing it. but after that it's also not downloading File B and C. Can you please suggest me proper way. It's really important & Urgent for me.

@Marko 2016-03-21 12:14:50

@Cristian the Groundy link is dead, same goes for some of the links pointhing to GitHub on your SO profile. Just a heads up.

@Arpit Patel 2016-04-07 15:29:18

I am getting minus value in progress (logcat) when i upload in our server. If i take any random file link so it work perfectly

@Muhammad Babar 2016-08-01 07:30:56

Byte[] data = new byte[4096] Can you please explain the function of data array more specifically its size (4096) purpose (what if i use 1024) and best practices?

@Muhammad Babar 2016-08-02 10:32:49

For large files it throws java.io.IOException: unexpected end of stream any idea?

@user1676874 2017-01-11 19:34:49

I know this has been here for a while now but, while executing the DownloadManager option I get an IllegalArgumentException: Can only download HTTP/HTTPS URIs while attempting to request a resource on the local network in the url, does anyone know how to make it work like that?

@Iftikar Urrhman Khan 2017-03-01 18:02:32

i used Asynctask method and its working fine

@appy 2017-04-25 10:35:12

DownloadManager class works great for me. Thanks a lot..!!

@Pratik Saluja 2018-06-08 06:46:58

Great tutorial. I want to learn how to achieve resume, pause and retry in AsyncTask for downloading ?

@Tamim Attafi 2019-03-10 09:28:21

Which of these approaches will keep downloading the file even if the application is killed or cleared from recents?

@DADi590 2019-04-13 23:39:40

Om the first version of the answer, can someone explain me why I get a NullPointerException on "connection.connect();"? I can't understand the problem! Tried on the Android Studio emulator and in my phone and it doesn't work! (KitKat btw)

@Sandeep 2014-09-19 13:41:42

While I was starting to learn android development, I had learnt that ProgressDialog is the way to go. There is the setProgress method of ProgressDialog which can be invoked to update the progress level as the file gets downloaded.

The best I have seen in many apps is that they customize this progress dialog's attributes to give a better look and feel to the progress dialog than the stock version. Good to keeping the user engaged with some animation of like frog, elephant or cute cats/puppies. Any animation with in the progress dialog attracts users and they don't feel like being kept waiting for long.

@Rumit Patel 2018-12-24 09:49:32

@VinceStyling 2014-05-07 15:56:14

I'd recommend you to use my Project Netroid, It's based on Volley. I have added some features to it such as multi-events callback, file download management. This could be of some help.

@Hoang Trinh 2014-06-26 07:43:28

Does it support multiple file download? I'm working on a project that allow user to download scheduled. At a specific time (12 AM for instance), the service will download all the link that user selected before. I mean the service I need has to be able to queue download links, and then download all of them (one by one or parallel, depend on user). Thank you

@VinceStyling 2014-06-26 08:49:21

@piavgh yes, all you wanted was satisfy, you can checkout my sample apk, it included a file download management demo.

@DarkCygnus 2018-05-23 18:53:34

Great library! Works good, although I am having issues downloading content from HTTPS Url's, as although one can set your own SSLSocketFactory adding a HostnameVerifier is not possible and I need such verifier. Raised an issue regarding that.

@Dhruv 2018-06-01 07:49:43

sample apk cannot able to download...

@Rumit Patel 2018-12-24 09:45:20

link for Volley. -> Not-Found

@Renetik 2017-08-28 18:34:10

I am adding another answer for other solution I am using now because Android Query is so big and unmaintained to stay healthy. So i moved to this https://github.com/amitshekhariitbhu/Fast-Android-Networking.

    AndroidNetworking.download(url,dirPath,fileName).build()
      .setDownloadProgressListener(new DownloadProgressListener() {
        public void onProgress(long bytesDownloaded, long totalBytes) {
            bar.setMax((int) totalBytes);
            bar.setProgress((int) bytesDownloaded);
        }
    }).startDownload(new DownloadListener() {
        public void onDownloadComplete() {
            ...
        }

        public void onError(ANError error) {
            ...
        }
    });

@Renetik 2017-09-05 20:43:08

But github.com/koush/ion looks like the way to go anyway....

@The Syrian 2015-05-20 23:29:35

I have modified AsyncTask class to handle creation of progressDialog at the same context .I think following code will be more reusable. (it can be called from any activity just pass context,target File,dialog message)

public static class DownloadTask extends AsyncTask<String, Integer, String> {
    private ProgressDialog mPDialog;
    private Context mContext;
    private PowerManager.WakeLock mWakeLock;
    private File mTargetFile;
    //Constructor parameters :
    // @context (current Activity)
    // @targetFile (File object to write,it will be overwritten if exist)
    // @dialogMessage (message of the ProgresDialog)
    public DownloadTask(Context context,File targetFile,String dialogMessage) {
        this.mContext = context;
        this.mTargetFile = targetFile;
        mPDialog = new ProgressDialog(context);

        mPDialog.setMessage(dialogMessage);
        mPDialog.setIndeterminate(true);
        mPDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        mPDialog.setCancelable(true);
        // reference to instance to use inside listener
        final DownloadTask me = this;
        mPDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                me.cancel(true);
            }
        });
        Log.i("DownloadTask","Constructor done");
    }

    @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();
            }
            Log.i("DownloadTask","Response " + connection.getResponseCode());

            // 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(mTargetFile,false);

            byte data[] = new byte[4096];
            long total = 0;
            int count;
            while ((count = input.read(data)) != -1) {
                // allow canceling with back button
                if (isCancelled()) {
                    Log.i("DownloadTask","Cancelled");
                    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;
    }
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        // take CPU lock to prevent CPU from going off if the user
        // presses the power button during download
        PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                getClass().getName());
        mWakeLock.acquire();

        mPDialog.show();

    }

    @Override
    protected void onProgressUpdate(Integer... progress) {
        super.onProgressUpdate(progress);
        // if we get here, length is known, now set indeterminate to false
        mPDialog.setIndeterminate(false);
        mPDialog.setMax(100);
        mPDialog.setProgress(progress[0]);

    }

    @Override
    protected void onPostExecute(String result) {
        Log.i("DownloadTask", "Work Done! PostExecute");
        mWakeLock.release();
        mPDialog.dismiss();
        if (result != null)
            Toast.makeText(mContext,"Download error: "+result, Toast.LENGTH_LONG).show();
        else
            Toast.makeText(mContext,"File Downloaded", Toast.LENGTH_SHORT).show();
    }
}

@Hitesh Sahu 2016-05-26 03:18:10

Dont forgot to add Wake lock permission <uses-permission android:name="android.permission.WAKE_LOCK" />

@Renetik 2015-05-06 19:27:28

Use Android Query library, very cool indeed.You can change it to use ProgressDialog as you see in other examples, this one will show progress view from your layout and hide it after completion.

File target = new File(new File(Environment.getExternalStorageDirectory(), "ApplicationName"), "tmp.pdf");
new AQuery(this).progress(R.id.progress_view).download(_competition.qualificationScoreCardsPdf(), target, new AjaxCallback<File>() {
    public void callback(String url, File file, AjaxStatus status) {
        if (file != null) {
            // do something with file  
        } 
    }
});

@Renetik 2017-08-28 18:17:29

The thing is, I stopped using it, because its unmaintained so don't suppose this is good answer anymore.

@sheetal 2012-06-12 14:21:58

Yes the code above will work .But if you are updating your progressbar in onProgressUpdate of Asynctask and you press back button or finish your activity AsyncTask looses its track with your UI .And when you go back to your activity, even if download is running in background you will see no update on progressbar. So on OnResume() try to run a thread like runOnUIThread with a timer task that updates ur progressbar with values updating from the AsyncTask running background.

private void updateProgressBar(){
    Runnable runnable = new updateProgress();
    background = new Thread(runnable);
    background.start();
}

public class updateProgress implements Runnable {
    public void run() {
        while(Thread.currentThread()==background)
            //while (!Thread.currentThread().isInterrupted()) {
            try {
                Thread.sleep(1000); 
                Message msg = new Message();
                progress = getProgressPercentage();        
                handler.sendMessage(msg);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } catch (Exception e) {
        }
    }
}

private Handler handler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        progress.setProgress(msg.what);
    }
};

Don't forget to Destroy the thread when ur activity is not visible.

private void destroyRunningThreads() {
    if (background != null) {
        background.interrupt();
        background=null;
    }
}

@user1417127 2012-07-10 06:43:22

This is exactly my problem. Can you tell me how to do a timer task to update progressbar? How to get values updating from the AsyncTask running behind

@sheetal 2012-07-10 13:40:31

okk take a global or static variable to where to update your values from asynctask...or u can insert it in DataBase for safe side..so that closing application wont hamper..And when u restart the activity where u want to update ur UI run the UI thread..see example below

@sheetal 2012-07-10 13:53:11

The UI should have the fresh reference..Like the newly initalized ProgressBar in my case

@Behzad 2013-02-20 21:35:30

@sheetal, But It works fine without your code! Why?! My device is Xperia P with Android 4.0.4. I've defined a static boolean variable that the onPreExecute sets it to true and the onPostExecute sets it to false. It shows that we are downloading or not, so we can check if the variable is equal to true, show the previous progressbar dialog.

@iSun 2013-03-06 15:27:16

@sheetal your code is little obscurant, can you tell me some advice?

@sheetal 2013-03-12 06:34:27

@iSun nothing as such i was facing the same problem..i solved it this way and shared it.It can be done better obviously but opinions are open here and so is mine..Thanks neways

@sheetal 2013-03-12 06:36:41

@Behzad yeah wat u said is correct but i am working with Froyo and gingerbreads where Asynctasks were killed without notification for memory issues so i was to resume file downloads if such happens..So for safe side i had the percentage downloads in DataBase

@vishnuc156 2016-10-03 11:06:51

Permissions

  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission 
   android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Using HttpURLConnection

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

public class DownloadFileUseHttpURLConnection extends Activity {

ProgressBar pb;
Dialog dialog;
int downloadedSize = 0;
int totalSize = 0;
TextView cur_val;
String dwnload_file_path =  
"http://coderzheaven.com/sample_folder/sample_file.png";
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Button b = (Button) findViewById(R.id.b1);
    b.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
             showProgress(dwnload_file_path);

                new Thread(new Runnable() {
                    public void run() {
                         downloadFile();
                    }
                  }).start();
        }
    });
}

void downloadFile(){

    try {
        URL url = new URL(dwnload_file_path);
        HttpURLConnection urlConnection = (HttpURLConnection)   
 url.openConnection();

        urlConnection.setRequestMethod("GET");
        urlConnection.setDoOutput(true);

        //connect
        urlConnection.connect();

        //set the path where we want to save the file           
        File SDCardRoot = Environment.getExternalStorageDirectory(); 
        //create a new file, to save the downloaded file 
        File file = new File(SDCardRoot,"downloaded_file.png");

        FileOutputStream fileOutput = new FileOutputStream(file);

        //Stream used for reading the data from the internet
        InputStream inputStream = urlConnection.getInputStream();

        //this is the total size of the file which we are downloading
        totalSize = urlConnection.getContentLength();

        runOnUiThread(new Runnable() {
            public void run() {
                pb.setMax(totalSize);
            }               
        });

        //create a buffer...
        byte[] buffer = new byte[1024];
        int bufferLength = 0;

        while ( (bufferLength = inputStream.read(buffer)) > 0 ) {
            fileOutput.write(buffer, 0, bufferLength);
            downloadedSize += bufferLength;
            // update the progressbar //
            runOnUiThread(new Runnable() {
                public void run() {
                    pb.setProgress(downloadedSize);
                    float per = ((float)downloadedSize/totalSize) *     
                    100;
                    cur_val.setText("Downloaded " + downloadedSize +  

                    "KB / " + totalSize + "KB (" + (int)per + "%)" );
                }
            });
        }
        //close the output stream when complete //
        fileOutput.close();
        runOnUiThread(new Runnable() {
            public void run() {
                // pb.dismiss(); // if you want close it..
            }
        });         

    } catch (final MalformedURLException e) {
        showError("Error : MalformedURLException " + e);        
        e.printStackTrace();
    } catch (final IOException e) {
        showError("Error : IOException " + e);          
        e.printStackTrace();
    }
    catch (final Exception e) {
        showError("Error : Please check your internet connection " +  
e);
    }       
}

void showError(final String err){
    runOnUiThread(new Runnable() {
        public void run() {
            Toast.makeText(DownloadFileDemo1.this, err,  
      Toast.LENGTH_LONG).show();
        }
    });
}

void showProgress(String file_path){
    dialog = new Dialog(DownloadFileDemo1.this);
    dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
    dialog.setContentView(R.layout.myprogressdialog);
    dialog.setTitle("Download Progress");

    TextView text = (TextView) dialog.findViewById(R.id.tv1);
    text.setText("Downloading file from ... " + file_path);
    cur_val = (TextView) dialog.findViewById(R.id.cur_pg_tv);
    cur_val.setText("Starting download...");
    dialog.show();

     pb = (ProgressBar)dialog.findViewById(R.id.progress_bar);
     pb.setProgress(0);
            pb.setProgressDrawable(
      getResources().getDrawable(R.drawable.green_progress));  
  }
}

@Mnightmare 2011-08-29 14:34:50

Don't forget to add permissions to your manifest file if you're gonna be downloading stuff from the internet!

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.helloandroid"
    android:versionCode="1"
    android:versionName="1.0">

        <uses-sdk android:minSdkVersion="10" />

        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
        <uses-permission android:name="android.permission.INTERNET"></uses-permission>
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
        <uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>

        <application 
            android:icon="@drawable/icon" 
            android:label="@string/app_name" 
            android:debuggable="true">

        </application>

</manifest>

@A Boschman 2018-05-17 14:17:29

I'm pretty sure you don't need READ_PHONE_STATE and you definitely don't need WRITE_EXTERNAL_STORAGE; it's a dangerous permission that can be avoided by using the Storage Access Framework.

@chintan adatiya 2014-08-01 14:55:06

I found this blog post very helpful, Its using loopJ to download file, it has only one Simple function, will be helpful to some new android guys.

@Raju yourPepe 2013-07-02 17:11:08

My personal advice is to use Progress Dialog and build up before execution , or initiate at OnPreExecute() , publish progress often if you use horizontal style of progress bar of the progress dialog. The remaining part is to optimize the algorithm of doInBackground.

@ENSATE 2014-02-10 00:17:04

Do not forget to replace "/sdcard..." by new File("/mnt/sdcard/...") otherwise you will get a FileNotFoundException

@Nirav Mehta 2014-04-10 06:09:50

In part 2 Download from service Progress dialog can not display progress increment. it direct return 100,so if 100 it direct check setprogress 100 and progress over, how to increment progress ??it display only 0 progress but actually download running

@Nirav Mehta 2014-04-10 06:15:06

it display only 0% out of 100 only other work properly

@naXa 2014-04-15 02:02:12

Do not do it! There is Environment.getExternalStorageDirectory().getAbsolutePath() for getting a path to sdcard. Also don't forget to check if the external storage is mounted - Environment.getExternalStorageState().equals(Environment.MED‌​IA_MOUNTED) (Mannaz)

Related Questions

Sponsored Content

8 Answered Questions

[SOLVED] Returning a file to View/Download in ASP.NET MVC

26 Answered Questions

[SOLVED] Download File Using Javascript/jQuery

19 Answered Questions

[SOLVED] How to trigger a file download when clicking an HTML button or JavaScript

43 Answered Questions

6 Answered Questions

[SOLVED] Download a file from NodeJS Server using Express

26 Answered Questions

40 Answered Questions

[SOLVED] Can't start Eclipse - Java was started but returned exit code=13

34 Answered Questions

[SOLVED] Android Studio: Add jar as library?

18 Answered Questions

[SOLVED] Fling gesture detection on grid layout

4 Answered Questions

[SOLVED] Android :showing progress dialog

Sponsored Content