web-dev-qa-db-ja.com

Android-AsyncTaskを強制的にキャンセルする

私のアクティビティの1つにAsyncTaskを実装しました。

_ performBackgroundTask asyncTask = new performBackgroundTask();
 asyncTask.execute();
_

ここで、「キャンセル」ボタン機能を実装する必要があるため、実行中のタスクの実行を停止する必要があります。実行中のタスク(バックグラウンドタスク)を停止する方法がわかりません。

AsyncTaskを強制的にキャンセルするにはどうすればよいですか?

更新:

同じCancel()メソッドについては見つけましたが、cancel(boolean mayInterruptIfRunning)を呼び出してもバックグラウンドプロセスの実行が必ずしも停止するわけではないことがわかりました。起こりそうなことは、AsyncTaskがonCancelled()を実行し、完了時にonPostExecute()を実行しないということだけです。

62
Paresh Mayani

時々isCancelled()をチェックするだけです:

 protected Object doInBackground(Object... x) {
    while (/* condition */) {
      // work...
      if (isCancelled()) break;
    }
    return null;
 }
90
Jacob Nordfalk

AsyncTaskcancel()を呼び出します。これが実際に何かをキャンセルするかどうかは、あなたがしていることに少し依存します。 Romain Guyを引用するには:

Cancel(true)を呼び出すと、割り込みがバックグラウンドスレッドに送信され、割り込み可能なタスクに役立つ場合があります。それ以外の場合は、doInBackground()メソッドでisCancelled()を定期的に確認するようにしてください。 code.google.com/p/shelvesでこの例を見ることができます。

49
CommonsWare

非同期タスクで何をしているのかに本当に依存します。

多数のファイルを処理するループの場合は、isCanceled()フラグが立てられているかどうかを各ファイルの後にチェックし、そうであればループを中断できます。

非常に長い操作を実行する1行のコマンドの場合、できることはあまりありません。

最善の回避策は、asynctaskのcancelメソッドを使用せず、独自のcancelFlagブール値を使用することです。その後、postExecuteでこのcancelFlagをテストして、結果をどう処理するかを決定できます。

16
Yahel

コメントに記載されているisCancelled() always returns false even i call asynctask.cancel(true);は、アプリを閉じると特に有害ですが、AsyncTaskは動作し続けます。

これを解決するために、提案した_Jacob Nordfalk_コードを次のように変更しました。

_protected Object doInBackground(Object... x) {
    while (/* condition */) {
      // work...
      if (isCancelled() || (FlagCancelled == true)) break;
    }
    return null;
 }
_

メインアクティビティに次を追加しました。

_@Override
protected void onStop() {
    FlagCancelled = true;
    super.onStop();
}
_

私のAsyncTaskはビューの1つのプライベートクラスであるため、現在の実際のフラグ値をAsyncTaskに通知するには、フラグの取得者または設定者が必要でした。

私の複数のテスト(AVD Android 4.2.2、Api 17)は、AsyncTaskが既にdoInBackgroundを実行している場合、isCancelled()はnoで反応することを示しました。キャンセルしようとする方法(つまり、falseのまま)で、たとえばmViewGroup.removeAllViews();中またはOnDestroyMainActivity中に、それぞれがビューのデタッチにつながる

_   @Override 
   protected  void  onDetachedFromWindow() { 
    mAsyncTask.cancel(false); // and the same result with mAsyncTask.cancel(true);
    super.onDetachedFromWindow(); 
   } 
_

導入されたFlagCancelledのおかげでdoInBackground()の強制停止に成功した場合、onPostExecute()が呼び出されますが、onCancelled()onCancelled(Void result)(APIレベル11以降)は呼び出されません。 (理由はわからないが、それらは呼び出されるべきであり、onPostExecute()はそうすべきではない、「cancel()メソッドを呼び出すと、onPostExecute(Object)が呼び出されないことが保証される。」-IdleSun同様の質問に答える )。

一方、同じAsyncTaskがキャンセルする前にdoInBackground()を開始していなかった場合、すべてが正常であり、isCancelled()がtrueに変わり、チェックインすることができます

_@Override
    protected void onCancelled() {
        Log.d(TAG, String.format("mAsyncTask - onCancelled: isCancelled = %b, FlagCancelled = %b", this.isCancelled(), FlagCancelled ));
    super.onCancelled();
}
_
5
Elia12345

AsyncTaskは長時間実行される操作には使用すべきではありませんが、応答しないタスク(応答しないHTTP呼び出しなど)でキャッチされる場合があります。その場合、AsyncTaskをキャンセルする必要があります。

これを行うには挑戦が必要です。 1. AsyncTaskで表示される通常の進行ダイアログは、ユーザーが[戻る]ボタンを押したときにAsyncTaskで最初にキャンセルされるものです。 2. AsyncTaskはdoInBackgroundメソッド内にある場合があります

ProgressDialogでdismissDialogListernerを作成することにより、ユーザーは[戻る]ボタンを押して、実際にAsycnTaskを無効にし、ダイアログ自体を閉じることができます。

以下に例を示します。

public void openMainLobbyDoor(String username, String password){
    if(mOpenDoorAsyncTask == null){
        mOpenDoorAsyncTask = (OpenMainDoor) new OpenMainDoor(username, password, Posts.API_URL, 
                mContext, "Please wait while I unlock the front door for you!").execute(null, null, null);
    }
}

private class OpenMainDoor extends AsyncTask<Void, Void, Void>{

    //declare needed variables
    String username, password, url, loadingMessage;
    int userValidated;
    boolean canConfigure;
    Context context;
    ProgressDialog progressDialog;

    public OpenMainDoor(String username, String password, String url, 
                Context context, String loadingMessage){
        userValidated = 0;
        this.username = username;
        this.password = password;
        this.url = url;
        this.context = context;
        this.loadingMessage = loadingMessage;
    }

    /**
     * used to cancel dialog on configuration changes
     * @param canConfigure
     */
    public void canConfigureDialog(boolean canConfigure){
        this.canConfigure = canConfigure;
    }

    @Override
    protected void onPreExecute(){
        progressDialog = new ProgressDialog(this.context);
        progressDialog.setMessage(loadingMessage);
        progressDialog.setIndeterminate(true);
        progressDialog.setCancelable(true);
        progressDialog.setOnCancelListener(new OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                mOpenDoorAsyncTask.cancel(true);
            }
        });
        progressDialog.show();
        this.canConfigure = true;
    }

    @Override
    protected Void doInBackground(Void... params) {
        userValidated = Posts.authenticateNTLMUserLogin(username, password, url, context);
        while(userValidated == 0){
            if(isCancelled()){
                break;
            }
        }
        return null;
    }

    @Override
    protected void onPostExecute(Void unused){
        //determine if this is still attached to window
        if(canConfigure)
            progressDialog.dismiss();

        if(userValidated == 1){
            saveLoginValues(username, password, true);
            Toast.makeText(context, R.string.main_login_pass, Toast.LENGTH_SHORT).show();
        }else{
            saveLoginValues(username, password, false);
            Toast.makeText(context, R.string.main_login_fail, Toast.LENGTH_SHORT).show();
        }
        nullifyAsyncTask();
    }

    @Override
    protected void onCancelled(){
        Toast.makeText(context, "Open door request cancelled!", Toast.LENGTH_SHORT).show();
        nullifyAsyncTask();
    }
}
2
Droid Chris

グローバルAsyncTaskクラス変数

LongOperation LongOperationOdeme = new LongOperation();

AsyncTaskを中断するKEYCODE_BACKアクション

   @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            LongOperationOdeme.cancel(true);
        }
        return super.onKeyDown(keyCode, event);
    }

わたしにはできる。

1
Göksel Güren