title: How to end android service after ASyncTask it spun off completes?
body: <p>I have a Downloader Service that loads a list of downloads to run from my database.</p>
  
  <p>It then creates an ASyncTask that will run the downloads in a background Thread.</p>
  
  <p>This all works perfectly well, but the problem is I don't currently have a way to tell the service that the Downloader has completed.  I somehow have to send the service a message from the ASyncTask's <a href="http://developer.android.com/intl/fr/reference/android/os/AsyncTask.html#onPostExecute%28Result%29" rel="nofollow">onPostExecute</a> function (which runs on the UIThread).</p>
  
  <p>I can't simply close the service remotely because the Service has some work to do when the ASyncTask completes.</p>
  
  <p>I've considered registering a listener from the service and calling it in onPostExecute, but I think this would cause problems like closing the service before the Task was complete or some threadlocking issues.</p>
  
  <p>How can I send a message (like a broadcast intent) to my Downloader service from my ASyncTask?</p>
  
  <p><strong>EDIT</strong><br>
  Here's some code for those of you confused about what I am doing.</p>
  
  <p>DownloadService.java (Important bits):</p>
  
  <pre><code>public class DownloadService extends Service implements OnProgressListener {
  
  /** The Downloads. */
  private List&lt;Download&gt; mDownloads = new ArrayList&lt;Download&gt;(10);
  
  private DownloadTask mDownloadTask;
  
  /** The Intent receiver that handles broadcasts. */
  private BroadcastReceiver mIntentReceiver = new BroadcastReceiver()
  {
      @Override
      public void onReceive(Context context, Intent intent) {
          DebugLog.i(TAG, "onRecieve" +intent.toString());
          handleCommand(intent);
      }
  
  };
  
  /* (non-Javadoc)
   * @see android.app.Service#onCreate()
   */
  @Override
  public void onCreate() {
      DebugLog.i(TAG, "onCreate");
      mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
      IntentFilter commandFilter = new IntentFilter();
      commandFilter.addAction(ACTION_PAUSE_DOWNLOADS);
      commandFilter.addAction(ACTION_START_DOWNLOADS);
      registerReceiver(mIntentReceiver, commandFilter);
  }
  
  /* (non-Javadoc)
   * @see android.app.Service#onDestroy()
   */
  @Override
  public void onDestroy(){
      DebugLog.i(TAG, "onDestroy");
      //Make sure all downloads are saved and stopped
      pauseAllDownloads();
      //unregister command receiver
      unregisterReceiver(mIntentReceiver);
      //cancel notifications
      closeNotification();
  }
  
  /* (non-Javadoc)
   * @see android.app.Service#onStartCommand(android.content.Intent, int, int)
   */a
  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
      handleCommand(intent);
      // We want this service to continue running until it is explicitly
      // stopped, so return sticky.
      return START_STICKY;
  }
  /**
   * Handle command sent via intent.
   * &lt;strong&gt;Warning, this function shouldn't do any heavy lifting.  
   * This will be run in UI thread and should spin off ASyncTasks to do work.&lt;/strong&gt;
   *
   * @param intent the intent
   */
  private void handleCommand(Intent intent) {
      if(intent != null){
          String action = intent.getAction();
          Uri data = intent.getData();
          if(action.equals(ACTION_START_DOWNLOADS))
          {
              updateDownloads();//Fetch list of downloads to do from database
              startDownloads();//run downloads
          }else if(action.equals(ACTION_PAUSE_DOWNLOADS)){
              pauseAllDownloads();
          }
      }
  }
  
  /**
   * Start all downloads currently in list (in order).
   */
  private void startDownloads()
  {
      pauseAllDownloads();//make sure we don't have a download task running
      mDownloadTask = new DownloadTask();
      mDownloadTask.setOnProgressListener(this);
      Download[] downloads = new Download[mDownloads.size()];
      for(int i = 0; i&lt;mDownloads.size(); i++)
      {
          Download d = mDownloads.get(i);
          if(d.getStatus() != Download.COMPLETE)
          {
              downloads[i] = mDownloads.get(i);   
          }
      }
      //must be called on UI thread
      mDownloadTask.execute(downloads);
  }
  
  /**
   * Pause downloads.
   */
  private void pauseAllDownloads()
  {
      if(mDownloadTask == null)
      {
          //Done.  Nothing is downloading.
          return;
      }
  
      //Cancel download task first so that it doesn't start downloading next
      if(mDownloadTask.cancel(true))
      {
          //Task has been canceled.  Pause the active download.
          Download activeDownload = mDownloadTask.getActiveDownload();
          if(activeDownload != null)
          {
              activeDownload.pause();
          }
      }else
      {
          if(mDownloadTask.getStatus() == AsyncTask.Status.FINISHED)
          {
              DebugLog.w(TAG, "Download Task Already Finished");
          }else{
              //Task could not be stopped
              DebugLog.w(TAG, "Download Task Could Not Be Stopped");
          }
      }
  }
  
  @Override
  public void onProgress(Download download) {
      //download progress is reported here from DownloadTask
  }
  }
  </code></pre>
  
  <p>DownloadTask:</p>
  
  <pre><code>/**
   * The Class DownloadTask.
   */
  public class DownloadTask extends AsyncTask&lt;Download, Download, Void&gt; {
  
  /** The On progress listener. */
  private OnProgressListener mOnProgressListener;
  
  /**
   * The listener interface for receiving onProgress events.
   * The class that is interested in processing a onProgress
   * event implements this interface and registers it with the component.
   *
   */
  public static interface OnProgressListener
  {
  
      /**
       * On progress update.
       *
       * @param download the download
       */
      public void onProgress(Download download);
  }
  
  private Download mCurrent;
  
  /**
   * Sets the on progress listener.
   *
   * @param listener the new on progress listener
   */
  public void setOnProgressListener(OnProgressListener listener)
  {
      mOnProgressListener = listener;
  }
  
  /**
   * Gets the active download.
   *
   * @return the active download
   */
  public Download getActiveDownload()
  {
      return mCurrent;
  }
  
  /* (non-Javadoc)
   * @see android.os.AsyncTask#doInBackground(Params[])
   */
  @Override
  protected Void doInBackground(Download... params) {
      int count = params.length;
      for (int i = 0; i &lt; count; i++) {
          mCurrent = params[i];
          if(mCurrent == null)
          {
              continue;
          }
          mCurrent.setDownloadProgressListener(new Download.OnDownloadProgressListener() {
  
              @Override
              public void onDownloadProgress(Download download, int bytesDownloaded,
                      int bytesTotal) {
                  publishProgress(download);
              }
          });
          mCurrent.setOnStatusChangedListener(new Download.OnStatusChangedListener() {
  
              @Override
              public void onStatusChanged(Download download, int status) {
                  publishProgress(download);
              }
          });
          mCurrent.download();
          //publishProgress(mCurrent); redundant call
          if(this.isCancelled())
              break;
      }
      return null;
  }
  
  /* (non-Javadoc)
   * @see android.os.AsyncTask#onPostExecute(java.lang.Object)
   */
  public void onPostExecute(Void v)
  {
      //TODO notify completion.
  }
  
  /* (non-Javadoc)
   * @see android.os.AsyncTask#onProgressUpdate(Progress[])
   */
  @Override
  protected void onProgressUpdate(Download... progress) {
      if(mOnProgressListener != null)
      {
          for(Download d:progress)
          {
              mOnProgressListener.onProgress(d);
          }
      }
  }
  
  }
  </code></pre>