Our app needs to download files with the following requirements:
User can dynamically add or cancel downloads
Files are downloaded one at a time
Sometimes in background we need to schedule several file downloads
It would be nice to display a notification displaying download progress and a cancel button
We had all this implented in a foreground service that would maintain a queue of tasks and having an aidl interface with methods that allowed to enqueue new downloads or cancel active/enqueued.
Since Android 12 we can no longer start foreground service when the app is in background, so we can't reliably download files anymore in this situation (requirement #3)
As far as I can understand, the recommended way of implementing such task is using WorkManager, but I can't find a good way of doing it.
I consider two approaches, but both are far from perfect:
Every downloaded file is a separate Work. It's easy to cancel when needed and we only need to suply a file URL and that's it.
But the downsides are: there's no way to enqueue several downloads at once (requirement #3), we need to wait for previous work to finish and then enqueue the next one.
Using ExistingWorkPolicy.APPEND doesn't help here - our downloads are independent and if one is cancelled or fails, others should stay in the queue.
Another annoying issue with this approach is that if we display a notification from our ListenableWorker via startForeground(), then for each file download it will be shown and hidded instead of just updating its contents for every new downloaded file.
Use a long running ListenableWorker that would download many files. But this requires somehow delivering enqueue and cancel(fileUrl) messages to the running worker instance (what we did previously using our service with the aidl/binder stuff). As far as I can see, the WorkManager API doesn't support anything like that. So the only thing we can do is to use some static vars to deliver those messages, which would work (if our worker works in the same process as the main app - hopefully, I can rely on that). But using statics in such a way is always kind of a code smell, I would avoid it if possible.
Are there any other possibilities to do this using WorkManager? Maybe I'm missing some part of the API?
Related
What would be the best approach for download on Android. You would be using AsyncTask or Service. I see several example being made of two ways, but what would be the best approach?
That's not the right question to ask, and the answer may be both. An AsyncTask is a separate thread of execution. A Service is just a piece of your app that runs in the background and can live past the end of an Activity.
You need to download any files on a non-UI thread, so either a Thread or AsyncTask is necessary whether you use a Service or not. So you'll always use one of those two. The question of whether or not to also use a service is a question of whether you need the file downloaded even if the user goes to another Activity (there's a few other reasons why you may want to use a Service, but this is the main one).
i suggest ,it depends upon the size of file.for small content file ,asynch is great but if is gonna be a longer task then you can go for service because service also comes with restart feature (start_sticky) in case user kill your app or your app got killed by the android os(LMK : low memory killer) in case of memory crises
I already know that using Services/Intent services we download multiple files in background. But this problem have one more complexity to solve.
I have to download multiple videos/images in different activities in parallel like whats app. I have seen in whats app that we can start download and then we can moves on different screens or press home button etc. But when we move back on that screen again the downloading is still continue with and showing the updated progress.
Like above there is 4 activities and user started downloading of ABC.mp4 on activity and A and then moves on to Activity B. Then moves on to C and started downloading of video/image. If user moves back on to the A and I want to show the progress of that ABC.mp4 file that how much downloaded and same case for the other activities.
Please let me know to you Services or any other way to do, so I can update the UI as well with the updated value of the downloading file. Any help is appreciated.
Well here's my piece of advice:
I did the same thing but with Pdf files a while a ago. First you need to choose a good Http client library to perform the downloads and forget about all the issues related to the downloads that you'll have if you perform this operations by yourself. I recommend you use the Ion librabry has a lot of useful features like cancel the downloads, attach callbacks to have an eye in the download progress, known if the download succeded, failed, etc.
Second, you obviously need a Service running in background, always, you can do this by making your own service, and It's very important that the Service process name in the android manifest is like android:name="com.company.app.services.MyService" and not like android:name=":MyRemoteService" doing so you'll make sure that the service will be running in background all the time (keep in mind that the OS can and will kill the service if It's neccesary, but the service will be restarted when the resources will made available again).
Third, to keep all the views, custom views, activities, fragments, etc. that display those files updated, you need trigger BroadcastReceivers from your Service. Keep in mind that doing so you can't use the LocalBroadcastReceiver, because your Service has its own process indipendent from your application.
Keep in mind that:
1) Theres no need to explicitly use an Activity, you can register your broadcasts anywhere where you see It fit. A RecyclerAdapter (most likely), a Fragment, or an Activity.
2) The communication App/Service is done through Intents so all data that you send to and from the Service must be Serializable.
3) You can use several different types of broadcast each one for differents situations (error, fail, success, progress, etc.) or you can use only one an send a enum that describe this kind of status through the Bundle of the Intent when you fire the broadcasts from your service
Hope this helps you, If you have any doubt, let me know.
I have a list of items, when user clicks on one item,my app starts download a file from internet.
I use AsyncTask for download a file.
Now I want download muitiple files(use Queue the extra file will be added to the Queue and will be downloaded later).How can I manage multiple AsyncTasks?
Note:I use API 8. I don't want to use Download Manager class in API 9
If you are worried about too many AsyncTasks causing issues, you dont need to.
Android automatically handles this from v1.6.
Read this answer for more info.
Additionally, if you do want to more control on execution and scheduling of task, use the Executor class
Problem
Throughout my app I need to download files. In some cases I only need one-way communication, basically communicating with the Activity that a download has finished. In other cases, I need to be able to communicate to the background process to cancel the download, then relay back to the Activity once that task has been complete (two-way communication).
Stipulations
In all cases, a download is only associated with one Activity, so a Service seems unnecessary since I don't need to keep a download running in the background while the user does other things. The user is always blocked while the download is occurring. The download process should be Activity-independent (not specialized for one Activity...reuseable). It would be ideal to have one solution that meets all requirements.
Use cases
The two cases I have right now are as follows:
A user is shown a ProgressDialog while a file is being downloaded. Once the file completes downloading, the user proceeds to the next Activity. Progress does not need to be shown.
A user is shown a ProgressBar while a large file is being downloaded. There is a Cancel button to abort downloading the file. Pressing the Cancel button should signal to the background process to abort downloading the file, then inform the Activity once that action has been performed. Progress needs to be shown while downloading the file.
What I've tried
My original implementation was a separate class, ran in a thread, that passed in a Context that would broadcast progress. This allowed communication from the background process to the Activity, but not vise-versa.
I attempted a Service, but from various articles I read, determined my needs did not justify a Service, as the user needed to be blocked while the download was occurring. I had never implemented a Service before, so I also ran into communication problems (probably poor implementation).
What would be ideal
A two-way BroadcastReceiver. Is that possible? I like being able to register for a BroadcastReceiver if I want to get feedback from the background process, or not if I don't care. I already have a method in a class that takes in an InputStream and a File and makes the transfer, so that method is being reused everywhere that needs to download a file right now.
What you want to do is use an AsyncTask. Read these here on Stackoverflow:
Download a file with Android, and showing the progress in a ProgressDialog
and
Cancelling file download with httpclient and asynctask
Besides AsyncTask, you can also use Loaders.
They do pretty much what you need to do and I think they are available since android 1.6 with android compatibility package [related post]. I think this is your best option :)
I am trying to implement a RESTful API in which I have to upload files that are relatively large for a mobile platform. The upload could take anywhere from 30 seconds to 5 minutes.
I would like my application to be completely usable while the upload takes place. I've been doing some research and I've come across a few methods from which I can't decide which is the correct solution to my problem.
These are the two things I have come across.
Using an IntentService -- handles the worker thread so I don't have to.
Using my own type of Service-- still need to implement an AsyncTask to handle the large process.
Implement an AsyncTask in a singleton file that would allow me to do all the work there but without using the service class.
My question is which method is the best -- if one isn't listed but is a more apt solution to my problem then I would appreciate suggestions.
After researching all these methods I am still also confused on one thing. Lets say I upload a 2MB files, but I want to know when it is done. For example, lets say I have a service that uploads an image and returns and imageID -- I need to be able to know when that service returns an imageID -- process that and then move on to the next upload until the rest are finished.
As always, thanks in advance.
EDIT: I forgot to specify that while uploading I want the app to be usable-- that means that I can switch activities and still have the same service run.
I used IntentService. It extends service so it basically has all the functions of the normal service, expect that it handles the threading for me so I don't have to worry about that. Its working very well at the moment.