We have a separate tutorial section on this website for HTTP operations. Over there we have already covered all the different network operations like sending a GET/POST request, uploading images, logging request, adding headers etc. We have used two of the most popular Libraries- Volley and Retrofit which provide complete support for all these network operations. But when it comes to downloading large files you cant use Retrofit or Volley, both of these recommend using DownloadManager. And that is what today’s tutorial is all about – DownloadManager Example
The DownloadManager is a system service that handles long-running HTTP downloads. Clients may request that a URI be downloaded to a particular destination file.
Here are some advantages of using DownloadManager
- It performs all the HTTP interaction on background thread by default. You dont need to create any thread.
- It gracefully handles connectivity issues if the network changes or device reboots by automatically retrying download after failure due to any reason.
- It provides features like pause/ resume download thereby improving user experience.
- Has a in built mechanism to inform the user of download progress using notification.
Downloading a File
In this section of DownloadManager Example we will prepare our download request and initiate the File Download
Add Permissions
First step in this DownloadManager Example is to add INTERNET permission to the AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET"/>
Create Activity
We need to create only one Activity in this DownloadManager Example which will have a button to initiate the download of file. Following is the layout file for this activity
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.irshadkumail.downloadexample.MainActivity"> <Button android:layout_width="wrap_content" android:id="@+id/download" android:text="DOWNLOAD" android:layout_centerInParent="true" android:layout_height="wrap_content" /> </RelativeLayout>
Now in our Java file of the Activity we initialize the button and set up a click listener as shown below
public class MainActivity extends AppCompatActivity { private Button button; private long downloadID; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button=findViewById(R.id.download); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { } }); } }
- Note that we have also created a global long variable which will be used to store download identifier id. More about this in next section
Prepare the DownloadManager.Request
Before starting the download we need to create a DownloadManager.Request object with all the details of the download and conditions to start it. DownloadManager.Request has provided us with multiple APIs to set information necessary to begin the download. The only mandatory information to start a download is network URI. Even if you have not specified any destination, Android stores the downloaded file in a shared storage . Below code snippet shows how we prepare our DownloadManager.Request with all the details.
File file=new File(getExternalFilesDir(null),"Dummy"); /* Create a DownloadManager.Request with all the information necessary to start the download */ DownloadManager.Request request=new DownloadManager.Request(Uri.parse("http://speedtest.ftp.otenet.gr/files/test10Mb.db")) .setTitle("Dummy File")// Title of the Download Notification .setDescription("Downloading")// Description of the Download Notification .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)// Visibility of the download Notification .setDestinationUri(Uri.fromFile(file))// Uri of the destination file .setRequiresCharging(false)// Set if charging is required to begin the download .setAllowedOverMetered(true)// Set if download is allowed on Mobile network .setAllowedOverRoaming(true);// Set if download is allowed on roaming network
Following are some important APIs used to set information of the download
- setNotificationVisibility(int)
This API is to control whether a system notification is shown while this download is running or when it is completed.
It can takes any of the following predefined values:
#VISIBILITY_HIDDEN
#VISIBILITY_VISIBLE
#VISIBILITY_VISIBLE_NOTIFY_COMPLETED
If set to VISIBILITY_HIDDEN, this requires the permission android.permission.DOWNLOAD_WITHOUT_NOTIFICATION. - setDescription(String), setTitle(String)
These APIs are used to set the description and title of the download notification (if displayed). - setDestinationInExternalFilesDir(Context ,String,String) , setDestinationUri(Uri), setDestinationInExternalPublicDir(String,String)
These APIs are used to set the destination file path of the downloaded file. You can start a download even without specifying the destination, in which case file is temporarily stored in shared storage. Also if you are storing the file in external storage you need to add STORAGE permissions in the Manifest. - addRequestHeader(String,String)
This API is used to add a request header to the HTTP request used to download the file
Apart from these they are a lot of other APIs like setAllowedOverRoaming(), setRequiresCharging(), setAllowedOverMetered() etc which define the conditions for the download to start. We have not used all the APIs in this DownloadManager Example but you can read more about them here.
Initiate the download
Once the DownloadManager.Request is ready with all the information you can start the download as shown in snippet below
DownloadManager downloadManager= (DownloadManager) getSystemService(DOWNLOAD_SERVICE); downloadID = downloadManager.enqueue(request);// enqueue puts the download request in the queue.
- enqueue(request) returns a unique long ID which acts as an identifier for the download. Note that calling enqueue() doesnt necessarily start the download immediately. It rather schedules the download request in a queue. Once the DownloadManager is free is starts the download.
- Important thing to note is how we initialize global variable downloadID . enqueue() returns an ID for the download, unique across the system. Global variable downloadID is used to store this ID. It is used to reference this download in future.
Listen to Download Complete
So far in this DownloadManager Example we saw to initiate downloading a file in Android. This section covers how to be notified when your download is completed.
One thing to note is that DownloadManager is a separate system service which downloads files requested by client. Here your app is the client and once you call enqueue() from your app it is now the responsibility of DownloadManager to schedule that download and save the file at destination. Therefore it is important that the client is informed when the download is completed. Android DownloadManager sends a ACTION_DOWNLOAD_COMPLETE
broadcast intent when any download is completed. You can listen for this broadcast using a BroadcastReceiver and identify if your download is completed using the unique long ID returned by enqueue().
Not sure what Broadcast is and How does BroadcastReceiver work? Read this simple tutorial
You can be notified when your download is complete by following three steps
- Create a BroadcastReceiver as shown in snippet below.Inside the receiver we just check if the received broadcast is for our download by matching the received download id with our enqueued download.
private BroadcastReceiver onDownloadComplete = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { //Fetching the download id received with the broadcast long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1); //Checking if the received broadcast is for our enqueued download by matching download id if (downloadID == id) { Toast.makeText(MainActivity.this, "Download Completed", Toast.LENGTH_SHORT).show(); } } };
- Once the BroadcastReceiver is created you can register for
ACTION_DOWNLOAD_COMPLETE
in the onCreate method of your activity. ThisACTION_DOWNLOAD_COMPLETE
broadcast is fired everytime any file download is completed by DownloadManager.@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button=findViewById(R.id.download); registerReceiver(onDownloadComplete,new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { beginDownload(); } }); }
- It is also important that you unregister the BroadcastReceiver in onDestroy. This ensures you only listen for this broadcast as long as the activity is active
@Override public void onDestroy() { super.onDestroy(); unregisterReceiver(onDownloadComplete); }
DownloadManager Example: Complete Code
This completes DownloadManager Example. Below is the complete code of your Activity
public class MainActivity extends AppCompatActivity { private Button button; private long downloadID; private BroadcastReceiver onDownloadComplete = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { //Fetching the download id received with the broadcast long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1); //Checking if the received broadcast is for our enqueued download by matching download id if (downloadID == id) { Toast.makeText(MainActivity.this, "Download Completed", Toast.LENGTH_SHORT).show(); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button=findViewById(R.id.download); registerReceiver(onDownloadComplete,new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { beginDownload(); } }); } @Override public void onDestroy() { super.onDestroy(); unregisterReceiver(onDownloadComplete); } private void beginDownload(){ File file=new File(getExternalFilesDir(null),"Dummy"); /* Create a DownloadManager.Request with all the information necessary to start the download */ DownloadManager.Request request=new DownloadManager.Request(Uri.parse("http://speedtest.ftp.otenet.gr/files/test10Mb.db")) .setTitle("Dummy File")// Title of the Download Notification .setDescription("Downloading")// Description of the Download Notification .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)// Visibility of the download Notification .setDestinationUri(Uri.fromFile(file))// Uri of the destination file .setRequiresCharging(false)// Set if charging is required to begin the download .setAllowedOverMetered(true)// Set if download is allowed on Mobile network .setAllowedOverRoaming(true);// Set if download is allowed on roaming network DownloadManager downloadManager= (DownloadManager) getSystemService(DOWNLOAD_SERVICE); downloadID = downloadManager.enqueue(request);// enqueue puts the download request in the queue. } }
We hope you are now clear on how to download files on Android. You can even learn how to upload files on Android by reading this simple tutorial