I know (i think so) how to download a file from a given URL. Used HTTP client to download the file and wrapped it in a runnable. I am assuming in order to be able to download multiple files in parallel, I can simply create more instances of the runnable, and add them to an ExecutorService.
I have already created framework to work with the SQLite DB. Used an ASync task to getwritabledatase, and then add some properties related to the file downloaded to the DB.
What I am unable to wrap my head around is how to make sure I can allow a user to download multiple files, and on completing the donwload, add the DB entry, all in an async manner so that user is free to navigate to another activity (dont have to handle a requirement when he logs out)/
Can I initiate an Async task after the httpclient returns with the file, inside my runnable/run()? or is that a bad practice since the runnable is already sipping off 1 thread and then another in form of async task? Any other suggestion?
Unfortunately I cannot use external libraries provided by someone on git/etc.
Can I initiate an Async task after the httpclient returns with the file, inside my runnable/run()? or is that a bad practice since the runnable is already sipping off 1 thread and then another in form of async task? Any other suggestion?
Downloading a file and writing an entry to the database are two independent operations. You should not do both within the same AsyncTask or Runnable. It will work though, but this is a bad architecture, I think.
Usually you have something like a download manager which is a class that has a mentioned executor. You call this download manager from your controller, for example activity or fragment, and once you receive a callback you can initiate a background task that will write data to the database. It can be anything: AsyncQueryHandler, Runnable, AsyncTask etc. Choose a solution that works better for your use case.
(dont have to handle a requirement when he logs out)/
This is not a problem at all as long as you use a UI-independent component such as Service. You don't need to have a UI to download a file and write it to the database.
Related
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?
So I have an app that will make multipe HTTP Post/Gets
E.G. Login, getThisData, getThatData, sendThis, sendThat
Is it better to have a seperate AsyncTask to handle each one
Or one async task and process them differently with a switch in onPostExecute and doInBackground
Cheers
Short answer is yes you should create a new AsncTask for each call.
And if you interested, the long answer is;
According to the Android's Asynctask documentation,
The goal of the AsyncTask is to take care of thread management for you and you should not worry about the threading mechanisms.
The Android Platform handles the pool of threads to manage the asynchronous operations. AsyncTasks are like consumables. The task can be executed only once (an exception will be thrown if a second execution is attempted.)
Happy asynchronous coding! :-)
It depends on whether the tasks are independent on each other or whether they are interrelated. If independent you can handle this through the same async. For ex if you need some data from your login response and pass that value to getthis task you better use separate async.
Make login a separate async, getthis ,get lthat sendthis sendthat can be in one async.
You'll probably want to separate them, especially if their functionality in the pre/post executes differs. Try to organize your code into logical blocks. For example, if you have an Async Task to Login, and an Async task to, for example, download lots of document data via JSON, they will want separate Async tasks.
However, lets say you have two separate API calls that return similar or partially the same data - if one returned the details of a file (name, size) and the other returned the same data but was a revision of a file - you could switch these in the same ASYNC because the post execute is going to perform the same (or partially the same) code to extract data from the JSON.
If you want to create one instance of AsyncTask, and execute() it several times, no:
Execute AsyncTask several times
If you are asking about designing: whether you should write one class to get different kind of data? It really depends on your circumstances:
If these HTTP call supposed to be sequential, you can put them in one AsyncTask class.
If they have lot in common, just point to different URIs, you can write a call(String uri) method, and invoke that method in your AsyncTask. This case, I think one AsyncTask is also enough.
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
How do I download multiple files in a queue one by one! I'm using this as a sample code, since.
I would be passing the URLs to download in Strings from my local DB dynamically.
Please let me know how to do that. I want the download to start as soon as the application launches. Kindly help me out!
Android Dev Type: Newbie
Purpose of Download Queue: To download multiple files from the server after in-app billing gets successful!
P.S.: I already referenced this question. But I'm not sure if that would solve my issue!
A good way of queuing up requests to be handled asynchronously, one at a time, is with an IntentService. If you have an IntentService which reads URLs from the supplied Intent, then all you have to do is create an Intent for each file you want to download, and send each Intent to the service,
Here is a good tutorial.
EDIT: I see you've already referred to a similar question, where the answer recommends IntentService. So, maybe you should use an IntentService. :)
From API 11 up, a good approach is to use a FixedThreadPool with async tasks. Do once:
ExecutorService threadPoolExecutor = Executors.newFixedThreadPool(3);
Where 3 is the number of downloads you want to run at the same time. It will queueu the task if there are already 3 downloads running, and automatically handle the task later.
Launch your async tasks with:
yourAsynTask.executeOnExecutor(threadPoolExecutor, params);
Params is probably the url you wish to connect to. You can read it out in the onPostExecute of your asynctask, and connect to the server using a HttpURLConnection.
Make sure you call down this on shutdown:
threadPoolExecutor.shutdown()
What's the best way to implement a download queue in Android?
Use an IntentService. It supplies the queue and the background thread for you, so all you have to do is put your download logic in onHandleIntent(). See here for a sample project demonstrating this.
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 :)