2011-02-18 39 views
0

私は自分のデータベースからダウンロードするダウンロードのリストをロードするDownloader Serviceを持っています。ASyncタスクが終了した後にアンドロイドサービスを終了する方法完了しましたか?

次に、バックグラウンドスレッドでダウンロードを実行するASyncTaskを作成します。

これはすべて正常に動作しますが、問題は現在、ダウンローダが完了したことをサービスに伝える方法がないことです。私は何らかの形で、ASyncTaskのonPostExecute関数(UIThread上で実行される)からメッセージを送信する必要があります。

サービスはリモートで閉じることができません.ASyncTaskが完了したときにサービスにいくつかの作業があるためです。

サービスからのリスナーを登録してonPostExecuteで呼び出すと考えましたが、タスクが完了する前にサービスを閉じるかスレッドロックの問題が発生すると思います。

私のASyncTaskからダウンローダサービスにメッセージ(ブロードキャストインテントのようなもの)を送信するにはどうすればよいですか?

EDIT
は、ここで私がやっているかについて混乱してあなたのそれらのためのいくつかのコードです。

DownloadService.java(重要ビット):

public class DownloadService extends Service implements OnProgressListener { 

/** The Downloads. */ 
private List<Download> mDownloads = new ArrayList<Download>(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. 
* <strong>Warning, this function shouldn't do any heavy lifting. 
* This will be run in UI thread and should spin off ASyncTasks to do work.</strong> 
* 
* @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<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 
} 
} 

DownloadTask:

/** 
* The Class DownloadTask. 
*/ 
public class DownloadTask extends AsyncTask<Download, Download, Void> { 

/** 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 < 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); 
     } 
    } 
} 

} 
+0

サンプルコードを投稿できますか? ServiceとAsyncTaskがどのように連携して動作しているかは、はっきりとは分かりません。通常はどちらか一方が必要ですが、両方は必要ありません。 –

+0

少し前にコードを投稿しますが、あなたの質問に答えて私のサービスは何がダウンロードされているのかをフォアグラウンドにすることなく管理し、ASyncTaskは実際にはバックグラウンドで重い作業をします(サービスはそれを自動的に行う)。私はサービスからのスレッドでRunnableを分割することができましたが、ASyncTaskはスレッドをより簡単に管理します。 – CodeFusionMobile

+0

AsyncTaskのonPostExecuteはdoInBackgroundの後に実行されるため、相対的な順序が保証されます。しかし、なぜ私はサービス内からAsyncTaskを使用する必要があるのか​​理解できません。もっと説明できますか? –

答えて

6

私は私のデータベースから実行するために、ダウンロードのリストをロードDownloaderのサービスを持っています。 その後、バックグラウンドスレッドでダウンロードを実行するASyncTaskを作成します。

IntentServiceを使用して、なぜあなたのバックグラウンドスレッドが既に存在すると考えてもいいですか?ダウンロードのためにIntentServiceを使用していることを示すHere is a sample project

私は現在、ダウンローダが完了したことをサービスに伝える方法がありません。

stopSelf()onPostExecute()から呼び出します。さらに良いことには、IntentServiceを使用してください。それ以上の作業がなければ自動的にシャットダウンします。

+0

私が言ったように、私は自動的にサービスをシャットダウンしたくありません。サービスは、ダウンロードが完了したときを知り、進行状況を報告し(UIThread上で)、ITSELFをシャットダウンする前に、より多くの作業が行われるようにするためにDECIDEする必要があります。さらに、ASyncTaskを使用すると、ワーカースレッドからのUIThreadの更新が簡単になり、スレッド間で頻繁に通信するためにメッセンジャーを処理する必要はありません。 – CodeFusionMobile

+0

@CodeFusionMobile:「私が言ったように、私は自動的にサービスをシャットダウンしたくありません」 - 私はあなたのことを言っていませんでした。 「サービスは、ダウンロードが完了したときを知り、進行状況を報告し(UIThread上で)、ITSELFを停止する前に、より多くの作業が必要ならばDECIDEする必要があります。これは 'stopSelf()'を呼び出すことによって達成されます。さらに、ASyncTaskを使用すると、ワーカースレッドからUIThreadを簡単に更新でき、スレッド間で頻繁に通信するためにメッセンジャーを処理する必要はありません。 - あなたのサービスは、 "UIThread"で何かをやってはいけません。 – CommonsWare

+0

私はonPostExecuteからstopSelfを呼び出すべきあなたの記事を読んでいます。私の理解は、これはサービスを停止するだけで、サービスを停止する必要があるかどうかを決定することではありません。ドキュメントによると、stopServiceの呼び出しと同じです。また、IntentServiceのもう一つの欠点もあります。意図が完了するまで、他のすべてのコマンドを保持します。つまり、ダウンロードプロセスを一時停止、再開、再起動、またはその他の方法で制御するために、別のメカニズムを導入する必要があります。 – CodeFusionMobile

関連する問題