5

I want to create a service similar to this one, (reference from Here), to download multiple files asynchronously in Android.

public static class DownloadingService extends IntentService {
public static String PROGRESS_UPDATE_ACTION = DownloadingService.class
        .getName() + ".newDownloadTask";
private ExecutorService mExec;
private CompletionService<NoResultType> mEcs;
private LocalBroadcastManager mBroadcastManager;
private List<DownloadTask> mTasks;

public DownloadingService() {
    super("DownloadingService");
    mExec = Executors.newFixedThreadPool( 3 ); // The reason to use multiple thread is to download files asynchronously. 
    mEcs = new ExecutorCompletionService<NoResultType>(mExec);
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    return super.onStartCommand(intent, flags, startId);
}

@Override
protected void onHandleIntent(Intent intent) {

  while(true)
  {
    if( cursor <= totalDownloadQueue.size() -1) {   //totalDownloadQueue is a static ArrayList which contains numerous DownloadTask
        mEcs.submit(totalDownloadQueue.get(cursor)); 
        cursor++; // The variable cursor is also a static int variable. 
    }
  }// continuously observing the totalDownloadQueue. If any download item is added. Then the thread are dispatched to handle that.
    mExec.shutdown();
}

The user can select download items among listview in different fragments. My strategy is that as the user select the items and press download button, these items are passed into DownloadTask which is responsible for downloading a file. Then the download tasks are added into the totalDownloadQueue.

Here are some questions:

  1. I know the intentservice is triggered by some defined action. But what I want to is to create a background service watching the totalDownloadQueue, if any new downloadtask is availabe, then some thread are called to operate the tasks.

    What's the side effect if I did so for this customized intentservice?

    What alternative class should I use? Please provide sample code along with the explanation, thanks.

  2. As I know, the initialization of the threads is only called by once. If I start the service at the beginning of the application and the threads should be killed as the user terminate the app.(I mean when he swipe out the window.) Do the threads exist after the user exit the application?

  3. If this approach still can't resolve the issue about downloading files asynchronously? What other strategy should I adopt? Please provide some example code or reference so that I can modify on it.

I have spent 7 days dealing with the complex requirement, any help please!

Community
  • 1
  • 1
Alston
  • 2,085
  • 5
  • 30
  • 49

3 Answers3

12

to download multiple files asynchronously in Android.

and also i think you want to download simultaneously.

i think you misused the intentservice. intentservice has a looper and a handler and each call to start causes to create a message for the handler. all messages are queued in the looper queue and are served one at a time.

you should use normal service and do not use intentservice because you want to download simultaneously not one at a time. extend service class and in onCreate method you can create multiple threads and each thread can take a messages from onStartCommand. i do not want to copy and paste the doc example because i think it is better to read all of the doc again. if you read it you can completely understand how to create service that handles multiple task simultaneously although it has created just one thread in the example.

http://developer.android.com/guide/components/services.html

what I want to is to create a background service watching the totalDownloadQueue

i think you do not need that. just when you create downloadtask call service, your message is delivered to service class and in that class you can create blockingqueue to handle your messages by threads.

Do the threads exist after the user exit the application?

yes and maybe no. it depends on the process, if the process exists yes but if the process has been destroyed no. again read lifecycle of process to understand what process is killed or kept by android.

http://developer.android.com/guide/components/processes-and-threads.html

if this approach still can't resolve the issue about downloading files asynchronously? What other strategy should I adopt? Please provide some example code or reference so that I can modify on it.

you can use downloadmanager but it downloads sequentially.

http://developer.android.com/reference/android/app/DownloadManager.html

http://blog.vogella.com/2011/06/14/android-downloadmanager-example/

mmlooloo
  • 18,937
  • 5
  • 45
  • 64
  • Well, I have new multiple threads in the constructor, using the `ExecutorService`. And the doc here also support this kind of design. `https://developer.android.com/training/multiple-threads/create-threadpool.html` – Alston Sep 09 '14 at 02:32
  • yes the docs support but intentservice is created to use one job at a time, the service doc says so. it says to use multiple threading use startservice not intentservice. by the way it is your app do whatever you like. – mmlooloo Sep 09 '14 at 03:16
  • Well, I will check specifically how to implement downloading files simultaneously with `service` in combination of `ExcutorService`. I'll appreciate it If you have such code for me to reference for. – Alston Sep 09 '14 at 05:24
  • A `service` is a background thread, if the user choose more files to download, how can I let the service do the download task? Should I create a queue to cache the download task and it's also `observed` by the service? Thanks!!! – Alston Sep 09 '14 at 09:03
  • `However, because you handle each call to onStartCommand() yourself, you can perform multiple requests simultaneously. That's not what this example does, but if that's what you want, then you can create a new thread for each request and run then right away (instead of waiting for the previous request to finish).` – mmlooloo Sep 09 '14 at 09:46
  • or you can create `blockingqueue` as i mentioned in my answer then in your service create for example 5 threads that each of them can take messages from queue and parse them, this is the idea of volley library. if you want you can read the source code or you can search for other solution that uses one `looper` with multiple threads for handling. – mmlooloo Sep 09 '14 at 09:46
  • Well, I am much interested in the `library volley`. Why should I reinvent a wheel after lots of failure and I can't meet the deadline. Does the library `volley` point to this `http://developer.android.com/training/volley/index.html`? – Alston Sep 09 '14 at 09:52
  • 1
    but you can not download large file with volley so it is not downloadmanager it is for small files – mmlooloo Sep 09 '14 at 09:54
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/60879/discussion-between-stallman-and-mmlooloo). – Alston Sep 09 '14 at 09:54
2

IntenService and AsyncTask provide a single worker thread, therefore simultaneous download of multiple images is not possible. However, i strongly suggest ThreadPoolExecutor for your requirements. It basically creates a pool of threads which are expended/shrink based on the number of tasks you apply or number of files you want to download. THreadPoolExecutor handles practically every aspect of threads management and its quite efficient. You create a single executor with the as in this code sample:

ExecutorService tpExecutor=
        new ThreadPoolExecutor(
                coreSize,      // the basic number of threads, when a task is added to the queue
                               // a new thread is created if nrOfThreads < coreSize  
                maxPoolSize,   // maximum number of threads created
                keepAliveTime,
                TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>()
                ); 

You can submit multiple downloading task by executing runnables:

tpExecutor.execute(new Runnable());
eldjon
  • 2,800
  • 2
  • 20
  • 23
  • I have use `Executors.newFixedThreadPool( 3 );` to run a multiple tasks. But I don't know if using the `IntentService` is correct or not, I need more specific code. Thanks. – Alston Sep 09 '14 at 03:56
  • Do you mean that I can pass the download path URL and relative parameters to the new `Runnable()` instance object, and it starts the download? Btw: I found that when I call `startService()` multiple times, it failed. But the user can't decide what to download in the first place, he may want to download more files after first decision. And this cause errors to the `service` class. – Alston Sep 09 '14 at 07:50
  • If the number of Runnable tasks are larger than the `LinkedBlockingQueue` size what will happen? As I know, the `execute` acts like registering a event to the pool. If there is no idle thread and the it doesn't exceed the limit of the queue size, it will be queued. – Alston Sep 12 '14 at 08:34
  • 1
    if the current size has not reached the maxSize the `ThreadPoolExecutor` will create a new thread, otherwise the task will be queued. – eldjon Sep 12 '14 at 10:59
0

From the sound of it you might benefit from using the onProgressUpdate method from ASyncTask, which can keep you updated on progress. Maybe have a read through the class description -- it sounds like just what you need. It also comes with lots of sample code!

Hope I am of help!

Sipty
  • 1,159
  • 1
  • 10
  • 18