title: Running multiple parallel downloads in Android
body: <p>First, I extended <code>IntentService</code> to build my <code>DonwloadService</code> class. It was OK, but a download queue had been created and 2nd download had to wait for the 1st to finished etc.</p>
  
  <p>So I decided to extend <code>Service</code> class (following the <a href="http://developer.android.com/guide/components/services.html" rel="nofollow">docs</a>). I've just added download function and function for publishing results (listened by receiver in activity):</p>
  
  <pre><code>    public class DownloadService extends Service
  {
      private static final String TAG = DownloadService.class.getSimpleName();
  
      public static final String EXTRA_DOWNLOAD = "EXTRA_DOWNLOAD";
      public static final String EXTRA_POSITION = "EXTRA_POSITION";
      public static final String INTENT_NOTIFICATION = "INTENT_NOTIFICATION";
      public static final String EXTRA_RESULT = "EXTRA_RESULT";
      public static final String EXTRA_PROGRESS = "EXTRA_PROGRESS";
      public static final String EXTRA_PATH = "EXTRA_PATH";
      public static final String EXTRA_INDETERMINABLE = "EXTRA_INDETERMINABLE";
      public static final int RESULT_PROGRESS = 123;
  
      private int mResult = Activity.RESULT_CANCELED;
  
      private Looper mServiceLooper;
      private ServiceHandler mServiceHandler;
  
      private final class ServiceHandler extends Handler
      {
          public ServiceHandler(Looper looper)
          {
              super(looper);
          }
  
          @Override
          public void handleMessage(Message message)
          {
              // Download file
              download(message.getData());
  
              // Stop the service using the startId, so that we don't stop
              // the service in the middle of handling another job
              stopSelf(message.arg1);
          }
      }
  
      @Override
      public void onCreate()
      {
          // Start up the thread running the service.  Note that we create a
          // separate thread because the service normally runs in the process's
          // main thread, which we don't want to block.  We also make it
          // background priority so CPU-intensive work will not disrupt our UI.
          HandlerThread handlerThread = new HandlerThread("DownloadServiceStartArguments",
                  Process.THREAD_PRIORITY_BACKGROUND);
          handlerThread.start();
  
          // Get the HandlerThread's Looper and use it for our Handler
          mServiceLooper = handlerThread.getLooper();
          mServiceHandler = new ServiceHandler(mServiceLooper);
      }
  
      @Override
      public int onStartCommand(Intent intent, int flags, int startId)
      {
          // For each start request, send a message to start a job and deliver the
          // start ID so we know which request we're stopping when we finish the job
          Message message = mServiceHandler.obtainMessage();
          message.setData(intent.getExtras());
          message.arg1 = startId;
          mServiceHandler.sendMessage(message);
  
          return START_REDELIVER_INTENT;
      }
  
      @Nullable
      @Override
      public IBinder onBind(Intent intent)
      {
          // No binding provided
          return null;
      }
  
      @Override
      public void onDestroy()
      {
          Log.d(TAG, "Service done");
      }
  
      /**
       * Handles file download
       *
       * @param bundle
       */
      private void download(Bundle bundle)
      {
          if (bundle != null) {
              return;
          }
  
          Download download = bundle.getParcelable(EXTRA_DOWNLOAD);
          int position = bundle.getInt(EXTRA_POSITION, -1);
  
          File downloadedFile = new File(Environment.getExternalStorageDirectory(), position + ".jpg");
          if (downloadedFile.exists()) {
              downloadedFile.delete();
          }
  
          FileOutputStream fileOutputStream = null;
  
          int filesize = -1;
  
          try {
  
              fileOutputStream = new FileOutputStream(downloadedFile.getPath());
  
              URL url = new URL(download.getUrl());
              HttpURLConnection connection = (HttpURLConnection) url.openConnection();
              connection.connect();
  
              filesize = connection.getContentLength();
  
              InputStream reader = new BufferedInputStream(connection.getInputStream());
  
              byte data[] = new byte[1024];
  
              int next = -1;
              int total = 0;
              while ((next = reader.read(data)) != -1) {
                  mResult = RESULT_PROGRESS;
                  total += next;
                  publishResult(downloadedFile.getAbsolutePath(),
                          (filesize &gt; 0) ? Math.round(total * 100 / filesize) : Math.round(total / 1024),
                          position, filesize &lt;= 0);
  
                  fileOutputStream.write(data, 0, next);
              }
  
              mResult = Activity.RESULT_OK;
  
          } catch (Exception e) {
              e.printStackTrace();
          } finally {
              if (fileOutputStream != null) {
                  try {
                      fileOutputStream.close();
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              }
          }
          publishResult(downloadedFile.getAbsolutePath(), 100, position, filesize &lt;= 0);
  
      }
  
      private void publishResult(String downloadPath, int progress, int positionInList,
                                 boolean indeterminable)
      {
          Intent intent = new Intent(INTENT_NOTIFICATION);
          intent.putExtra(EXTRA_PATH, downloadPath);
          intent.putExtra(EXTRA_PROGRESS, progress);
          intent.putExtra(EXTRA_POSITION, positionInList);
          intent.putExtra(EXTRA_INDETERMINABLE, indeterminable);
          intent.putExtra(EXTRA_RESULT, mResult);
          sendBroadcast(intent);
      }
  }
  </code></pre>
  
  <p>But still there is a download queue, no parallel downloads.</p>