アクティビティから開始されたIntentServiceがあり、アクティビティの「キャンセル」ボタンを使用して、アクティビティからすぐにサービスを停止できるようにしたいと考えています。その「キャンセル」ボタンが押されるとすぐに、サービスがコードの行の実行を停止するようにします。
私はこれに似たいくつかの質問を見つけました(すなわち here 、 here 、 here 、 here )、しかし、良い答えはありません。 Activity.stopService()
とService.stopSelf()
はService.onDestroy()
メソッドをすぐに実行しますが、onHandleIntent()
のコードを最後まで終わらせてからサービスを破棄します。
サービスのスレッドをすぐに終了する保証された方法は明らかにないので、私が見つけることができる唯一の推奨される解決策は( here )onDestroy()
メソッドを使用し、onHandleIntent()
のコードのほぼすべての行を、その変数を参照する独自の「if」句でラップします。それはコードを書くひどい方法です。
IntentServiceでこれを行うより良い方法を知っている人はいますか?
多くの場合、スレッドまたはプロセスをすぐに停止することは汚いことです。ただし、サービスがステートレスであれば問題ありません。
マニフェストで別のプロセスとしてサービスを宣言します。
<service
Android:process=":service"
...
そして、実行を停止したい場合は、そのプロセスを強制終了します。
ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
List<RunningAppProcessInfo> runningAppProcesses = am.getRunningAppProcesses();
Iterator<RunningAppProcessInfo> iter = runningAppProcesses.iterator();
while(iter.hasNext()){
RunningAppProcessInfo next = iter.next();
String pricessName = getPackageName() + ":service";
if(next.processName.equals(pricessName)){
Process.killProcess(next.pid);
break;
}
}
ここにトリックがあります。揮発性の静的変数を利用し、サービスのいくつかの行で継続条件をチェックして、サービス継続をチェックする必要があります。
class MyService extends IntentService {
public static volatile boolean shouldContinue = true;
public MyService() {
super("My Service");
}
@Override
protected void onHandleIntent(Intent intent) {
doStuff();
}
private void doStuff() {
// do something
// check the condition
if (shouldContinue == false) {
stopSelf();
return;
}
// continue doing something
// check the condition
if (shouldContinue == false) {
stopSelf();
return;
}
// put those checks wherever you need
}
}
アクティビティでこれを実行してサービスを停止します。
MyService.shouldContinue = false;
サービス内でBroadcastReceiverを使用して、単純に停止ブール値をtrueに設定しました。例:
private boolean stop=false;
public class StopReceiver extends BroadcastReceiver {
public static final String ACTION_STOP = "stop";
@Override
public void onReceive(Context context, Intent intent) {
stop = true;
}
}
@Override
protected void onHandleIntent(Intent intent) {
IntentFilter filter = new IntentFilter(StopReceiver.ACTION_STOP);
filter.addCategory(Intent.CATEGORY_DEFAULT);
StopReceiver receiver = new StopReceiver();
registerReceiver(receiver, filter);
// Do stuff ....
//In the work you are doing
if(stop==true){
unregisterReceiver(receiver);
stopSelf();
}
}
次に、アクティビティ呼び出しから:
//STOP SERVICE
Intent sIntent = new Intent();
sIntent.setAction(StopReceiver.ACTION_STOP);
sendBroadcast(sIntent);
サービスを停止します。
PD:私の場合、ループ中にサービスを停止するため、ブール値を使用しますが、おそらくonReceiveでunregisterReceiverとstopSelfを呼び出すことができます。
PD2:サービスが正常に動作を終了した場合、またはuntentReceiverエラーが発生する場合は、unregisterReceiverを呼び出すことを忘れないでください。
IntentServiceの場合、onHandleIntent
メソッドが前のリクエストを完了するまで、何らかのインテントアクションを介して他のリクエストを停止または取得しません。
他のアクションでIntentServiceを再度開始しようとすると、onHandleIntent
は前のインテント/タスクが終了したときにのみ呼び出されます。
また、stopService(intent);
またはstopSelf();
は、onHandleIntent()
メソッドがタスクを完了するまで機能しません。
したがって、ここでのより良い解決策は、ここで通常のService
を使用することだと思います。
私はそれが役立つことを願っています!
IntentService
を使用している場合は、onHandleIntent()
コードがその「停止」信号をポーリングする必要がある、説明したようなことをしていると思われます。
バックグラウンドタスクが長時間実行される可能性があり、それを停止できるようにする必要がある場合は、代わりにプレーンService
を使用する方が良いと思います。大まかに言って、サービスを以下に記述してください。
AsyncTask.cancel(true)
を呼び出す「キャンセル」インテントを公開するか、onDestroy()がAsyncTask.cancel(true)
を呼び出すようにします。バックグラウンド作業をキャンセルする能力と引き換えに、サービスは以下の責任を負います:
doInBackground()
は、InterruptedExceptionを適切に処理し、定期的にThread.interrupted()をチェックし、「早期」に戻る必要があります。stopSelf()
が呼び出されることを保証する必要があります(AsyncTask onPostExecute/onCancelledで)。@Override
protected void onHandleIntent(Intent intent) {
String action = intent.getAction();
if (action.equals(Action_CANCEL)) {
stopSelf();
} else if (action.equals(Action_START)) {
//handle
}
}
それがうまくいくことを願っています。
@budiusが既にコメントで言及しているように、そのボタンをクリックするときに、Service
にブール値を設定する必要があります。
// your Activity.Java
public boolean onClick() {
//...
mService.performTasks = false;
mService.stopSelf();
}
そして、Intent
処理で、インテント情報をコミット/送信するという重要なタスクを実行する前に、そのブール値を使用します。
// your Service.Java
public boolean performTasks = true;
protected void onHandleIntent(Intent intent) {
Bundle intentInfo = intent.getBundle();
if (this.performTasks) {
// Then handle the intent...
}
}
それ以外の場合、サービスはIntent
を処理するタスクを実行します。それが、それが使われることを意図された方法です そうでなければあなたがそれを解決する方法を私は全く見ることができないので あなたがコアコードを見るならば。