I am writing an application targeting API level 9 or higher. So, i
have decided to go with DownloadManager Class that SDK offers.
My question is 2 part -
1. When i am downloading a single file, how do i display the progress
of the download. I see i can get COLUMN_TOTAL_SIZE_BYTES and
COLUMN_BYTES_DOWNLOADED_SO_FAR from the querying the download manager
instance. But i am not sure if i have to put the query in a thread and
implement a loop so that i can poll regularly to update the progress
bar. I guess, i am not sure, how to query regularly - will it go in
the main thread or be implemented as a runnable - the mechanism i am
not clear.
2. If i have to support multiple file downloads, then do i have to
launch each one of them in it's own thread?
Thanks.
If you are building on 2.3 and above you don't need to, it automatically displays it in the status bar. Do it like this,
Code from commonsware,
private static final int DOWNLOAD_SUCCESSFUL = 100;
private static final int DOWNLOAD_FAILED = 99;
private DownloadManager mgr=null;
on create do this,
`mgr = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
registerReceiver(onComplete,
new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
`
Then on the click event of the file download,
lastDownload =
mgr.enqueue(new DownloadManager.Request(uri)
.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI |
DownloadManager.Request.NETWORK_MOBILE)
.setAllowedOverRoaming(false)
.setTitle("Test File")
.setDescription("Download zipped file.")
.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS,
file_name));
And then a broadcast receiver for when your donwnload compeletes,
BroadcastReceiver onComplete=new BroadcastReceiver() {
public void onReceive(Context ctxt, Intent intent) {
findViewById(R.id.start).setEnabled(true);
File unzipFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),file_name);
//check for new file download
//extract if it's a new download
if (unzipFile.exists()) {
new UnzipFile().execute();
} else {
Toast.makeText(Main.this, "Download not found!", Toast.LENGTH_LONG).show();
}
}
};`
Related
i made app with webView in Android Studio , my app contains all images so i have also implemented download button in my app , but when someone click on download button it just download the image , i want to show pop up when download is Finished , something like this,
Download Completed and below Ok button
this is my code of download
Uri source = Uri.parse(url);
// Make a new request pointing to the .apk url
DownloadManager.Request request = new DownloadManager.Request(source);
// appears the same in Notification bar while downloading
request.setDescription("Description for the DownloadManager Bar");
request.setTitle("PunjabiDharti.jpg");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
}
// save the file in the "Downloads" folder of SDCARD
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "PunjabiDharti.jpg");
// get download service and enqueue file
DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);
how to show pop up ?
First, add Dependencies for MaterialDialog in build.gradle
dependencies {
// ... other dependencies here
implementation 'com.afollestad.material-dialogs:core:0.9.6.0'
}
Create a BroadcastReceiver Handler
BroadcastReceiver downloadListener = new BroadcastReceiver(){
public void onReceive(Context ct, Intent intent){
new MaterialDialog.Builder(this)
.title("Download Completed")
.content("Download Successfully Completed")
.positiveText("OK")
.show();
}
};
And now register Receiver
registerReceiver(downloadListener, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
My app requires to download files in the evening if there is Wi-Fi. Is Service the best way to implement it?
If user closes my app, does that mean I cannot download in any way? That means my user has to keep my app in the background?
You could just use DownloadManager and restrict the allowed network types to Wi-Fi only.
For example:
DownloadManager manager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
Uri uri = Uri.parse("http://something.xyz/somefile.asd");
DownloadManager.Request request = new DownloadManager.Request(uri);
// allowing Wi-Fi only
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
long id = manager.enqueue(request);
To get notified when your download completes, you could define a receiver for the ACTION_DOWNLOAD_COMPLETE broadcast:
private final BroadcastReceiver downloadReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// the ID of the finished download
long downloadedId = intent.getLongExtra(
DownloadManager.EXTRA_DOWNLOAD_ID, -1);
// do whatever you'd like here
}
};
And register/unregister it:
#Override
protected void onResume() {
super.onResume();
registerReceiver(downloadReceiver,
new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
#Override
protected void onPause() {
unregisterReceiver(downloadReceiver);
super.onPause();
}
Don't forget to add the appropriate permissions to your Manifest:
<!-- required -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- optional -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
If you run sticky service , you can download your files in worker threads not main threads even your app is closed.Therefore after finishing you can use broadcast receiver to notify the user or start an activity.
You can use services even when your app is closed. I recommend using IntentService. It is easy to use and it runs in a thread other than your UI thread. You can also make it STICKY so that your service will be restarted even if Android kills it.
In my app, I am using DownloadManager, for downloading PDF's, which notifies the application via a BroadcastReceiver once the download is completed. My problem is the onReceive() method of BroadcastReceiver is getting called twice. The code is as follows:
In my list adapter, a for loop is run for downloading the selected pdf's. The downloading code is written in another class as follows:
public static void downloadCheat(final SherlockFragmentActivity activity, final String cheatName, String pathOnServer){
Request request = new Request(
Uri.parse(ApplicationConstants.CHEAT_DOWNLOAD_SERVER_URL
+ "/" + pathOnServer + cheatName + ".pdf"));
if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) {
request.setShowRunningNotification(true);
}
else {
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
}
final DownloadManager dm = (DownloadManager) activity
.getSystemService(Context.DOWNLOAD_SERVICE);
final long enqueue = dm.enqueue(request);
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
long i = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
System.out.println(i);
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {
Query query = new Query();
query.setFilterById(enqueue);
Cursor c = dm.query(query);
if (c.moveToFirst()) {
int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_STATUS);
if (DownloadManager.STATUS_SUCCESSFUL == c.getInt(columnIndex)) {
}
}
//create custom notification
}
}
};
activity.registerReceiver(receiver, new IntentFilter(
DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
I am trying to add notifications for each pdf download. This works perfectly with download managers own internal notification for HoneyComb and above versions but for GingerBread it does not work and hence I have to push my own custom notification. So I need to determine the exact time when the pdf is downloaded completely. As of now I am able to push my own custom notification but the notifications come twice for every pdf download (As onReceive() is getting twice for each pdf). Can anyone please explain why onReceive() is called twice(for every pdf). Is there any workaround for this? Also could someone please recommend how the broadcast receiver can be un-registered in my case here?The above code is not a part of Activity, so I am not sure how to unregister the receiver.
Thanks for stopping by and reading the post.
You normally register receivers onResume() and unregister in onPause(). Are you doing so?
I think I may have originally misunderstood what you were trying to do. You should be able to call unregisterReceiver from onReceive. Does this do what you want?
You said you are downloading two pdfs. I only see one Download Request in your method. So I assume what you did is to call that method twice. If that is true, you actually registered two receiver to receive the ACTION_DOWNLOAD_COMPLETE event.
You only need to register once in onCreate or onStart or some methods else. For notification purpose, you can use intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1) to get the download id, the id is unique for each download. You can use this id to get the information about the downloaded file and make your file-specific notification.
This looks like the same bug that is described here:
https://code.google.com/p/android/issues/detail?id=18462
Solution: API 11 is needed see answer below!
Easy Question: After downloading a File with the implemented DownloadManager the Notification disappears. How do I force the Notification to stay after Download?
I tried to use VISIBILITY_VISIBLE_NOTIFY_COMPLETED, but i do not know how i can use it
Thank for any kind of help to solve this problem ;)
EDIT: Code
public class BgDL extends Activity {
private DownloadManager mgr = null;
private long id;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
mgr = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
Request request = new Request(Uri.parse(getIntent().getStringExtra("URL")));
id = mgr.enqueue(request
.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "UPDATE")
.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI|DownloadManager.Request.NETWORK_MOBILE)
.setAllowedOverRoaming(false)
.setTitle("APP update")
.setDescription("New version "+getIntent().getDoubleExtra("OV", 0.0))
);
registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
BroadcastReceiver receiver = new BroadcastReceiver () {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(mgr.ACTION_DOWNLOAD_COMPLETE) ){
unregisterReceiver(receiver);
finishActivity(99);
}
}
};
}
Add the correct flag to your request:
Request request = new Request(Uri.parse(getIntent().getStringExtra("URL")));
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
Reference:
http://developer.android.com/reference/android/app/DownloadManager.Request.html#setNotificationVisibility(int)
Control whether a system notification is posted by the download manager while this download is running or when it is completed. If enabled, the download manager posts notifications about downloads through the system NotificationManager. By default, a notification is shown only when the download is in progress.
http://developer.android.com/reference/android/app/DownloadManager.Request.html#VISIBILITY_VISIBLE_NOTIFY_COMPLETED
This download is visible and shows in the notifications while in progress and after completion.
I am developing an application in which i need to download a file(.zip / .txt / .jpg etc) size- 5 to 50 MB.. Application based on Android 2.2.
The user provides the URL and triggers the download but then the downloading process runs in background until complete.
streaming should be used for downloading file.
I want to know how can this be done using HTTP connections.
what classes can be used for this?
Does android 2.2 provides an API for this?
Any kind of help is appreciated....
Android did include an API called DownloadManager for just this purpose...but it was release in 2.3; so while it won't be useful in your application targeting 2.2, it might still be a good resource for you to research the implementation.
A simple implementation I would recommend is something like this:
Use an HttpURLConnection to connect and download the data. This will require the INTERNET permission to be declared in your manifest
Determine where you want the file to be. If you want it on the device's SD card, you will also need the WRITE_EXTERNAL_STORAGE permission.
Wrap this operation in the doInBackground() method of an AsyncTask. This is a long-running operation, so you need to put it into a background thread, which AsyncTask manages for you.
Implement this in a Service so the operation can run protected without the user keeping the an Activity in the foreground.
Use NotificationManager to notify the user when the download is complete, which will post a message to their status bar.
To simplify things further, if you use IntentService, it will handle the threading for you (everything in onHandleIntent gets called on a background thread) and you can queue up multiple downloads for it to handle one at a time by simply sending multiple Intents to it. Here's a skeleton example of what I'm saying:
public class DownloadService extends IntentService {
public static final String EXTRA_URL = "extra_url";
public static final int NOTE_ID = 100;
public DownloadService() {
super("DownloadService");
}
#Override
protected void onHandleIntent(Intent intent) {
if(!intent.hasExtra(EXTRA_URL)) {
//This Intent doesn't have anything for us
return;
}
String url = intent.getStringExtra(EXTRA_URL);
boolean result = false;
try {
URL url = new URL(params[0]);
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
//Input stream from the connection
InputStream in = new BufferedInputStream(connection.getInputStream());
//Output stream to a file in your application's private space
FileOutputStream out = openFileOutput("filename", Activity.MODE_PRIVATE);
//Read and write the stream data here
result = true;
} catch (Exception e) {
e.printStackTrace();
}
//Post a notification once complete
NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
Notification note;
if(result) {
note = new Notification(0, "Download Complete", System.currentTimeMillis());
} else {
note = new Notification(0, "Download Failed", System.currentTimeMillis());
}
manager.notify(NOTE_ID, note);
}
}
Then you can call this service with the URL you want to download anywhere in an Activity like this:
Intent intent = new Intent(this, DownloadService.class);
intent.putExtra(DownloadService.EXTRA_URL,"http://your.url.here");
startService(intent);
Hope that is helpful!
EDIT: I'm fixing this example to remove the unnecessary double-threading for anyone who comes upon this later.