2015-09-14 3 views
1

Во-первых, я продлил IntentService, чтобы построить класс DonwloadService. Все было в порядке, но была создана очередь загрузки, а вторая загрузка должна была дождаться завершения 1-го и т. Д.Запуск нескольких параллельных загрузок в Android

Итак, я решил продлить класс Service (после docs). Я просто добавил функцию загрузки и функции для публикации результатов (прослушанных приемником активности):

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 > 0) ? Math.round(total * 100/filesize) : Math.round(total/1024), 
         position, filesize <= 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 <= 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); 
    } 
} 

Но до сих пор существует очередь загрузки, никаких параллельных загрузок.

+0

попробовать библиотеку HTTP Ion для андроид, его очень проста в освоении и использовании, и все запросы, генерируемые с помощью его создать отдельный поток для каждого запроса сети автоматически, так что вы не придется беспокоиться о загрузке в параллель Ион позаботится об этом – Bhargav

+0

@Bhargav, спасибо за рекомендацию. Я обязательно посмотрю, но во-первых, я бы хотел попробовать это без какой-либо библиотеки. –

ответ

1

Если вы хотите повторно запускать задачу на разных наборах данных, но вам нужно только одно выполнение, выполняемое за один раз, то IntentService соответствует вашим потребностям. Чтобы автоматически запускать задачи по мере того, как ресурсы становятся доступными или разрешать запуск нескольких задач одновременно (или и то и другое), вам необходимо предоставить управляемую коллекцию потоков. Для этого используйте экземпляр ThreadPoolExecutor, который запускает задачу из очереди, когда поток в пуле становится свободным. Чтобы запустить задачу, все, что вам нужно сделать, это добавить ее в очередь.

Ссылка: Creating a Manager for Multiple Threads

+1

Спасибо за ответ. Я хотел бы иметь несколько параллельных задач (загрузок), работающих с возможностью обновления интерфейса. Я посмотрю ThreadPoolExecutor. –

+0

Может быть, глупый вопрос новичка, но мне нужна служба вообще? –

+0

Если вы используете услугу, вам все равно придется создавать потоки в сервисе для каждой загрузки – Shahzeb

Смежные вопросы