を使用して、バックグラウンドスレッドでリモートオーディオファイルフェッチおよびオーディオファイル再生操作を実行していますAsyncTask
。Cancellable
フェッチ操作が実行されている間、進行状況バーが表示されます。
AsyncTask
ユーザーが操作をキャンセル(決定)したときに実行をキャンセル/中止したい。そのような場合を処理する理想的な方法は何ですか?
を使用して、バックグラウンドスレッドでリモートオーディオファイルフェッチおよびオーディオファイル再生操作を実行していますAsyncTask
。Cancellable
フェッチ操作が実行されている間、進行状況バーが表示されます。
AsyncTask
ユーザーが操作をキャンセル(決定)したときに実行をキャンセル/中止したい。そのような場合を処理する理想的な方法は何ですか?
私がどこでも使用してきた が実際には何もしないことをAlertDialogs
発見しました。boolean cancel(...);
偉大な。
そう...
public class MyTask extends AsyncTask<Void, Void, Void> {
private volatile boolean running = true;
private final ProgressDialog progressDialog;
public MyTask(Context ctx) {
progressDialog = gimmeOne(ctx);
progressDialog.setCancelable(true);
progressDialog.setOnCancelListener(new OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
// actually could set running = false; right here, but I'll
// stick to contract.
cancel(true);
}
});
}
@Override
protected void onPreExecute() {
progressDialog.show();
}
@Override
protected void onCancelled() {
running = false;
}
@Override
protected Void doInBackground(Void... params) {
while (running) {
// does the hard work
}
return null;
}
// ...
}
あなたが計算をしているなら:
isCancelled()
定期的にチェックする必要があります。HTTP リクエストを実行している場合:
HttpGet
orのインスタンスをHttpPost
どこかに保存します (例: public フィールド)。cancel
、 を呼び出しますrequest.abort()
。これにより、IOException
が内部にスローされますdoInBackground
。私の場合、さまざまな AsyncTasks で使用するコネクタ クラスがありました。簡単にするために、abortAllRequests
そのクラスに新しいメソッドを追加し、 を呼び出した直後にこのメソッドを呼び出しcancel
ました。
問題は、 AsyncTask.cancel() 呼び出しがタスクの onCancel 関数のみを呼び出すことです。ここで、キャンセル リクエストを処理します。
これは、更新メソッドをトリガーするために使用する小さなタスクです
private class UpdateTask extends AsyncTask<Void, Void, Void> {
private boolean running = true;
@Override
protected void onCancelled() {
running = false;
}
@Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
onUpdate();
}
@Override
protected Void doInBackground(Void... params) {
while(running) {
publishProgress();
}
return null;
}
}
シンプル:を使用しないでくださいAsyncTask
。AsyncTask
すぐに終了する(数十秒)短い操作用に設計されているため、キャンセルする必要はありません。「オーディオファイルの再生」は対象外です。通常のオーディオファイルの再生には、バックグラウンドスレッドも必要ありません。
これが私がAsyncTaskを書く方法です
。重要なポイントはaddThread.sleep(1)です。
@Override protected Integer doInBackground(String... params) {
Log.d(TAG, PRE + "url:" + params[0]);
Log.d(TAG, PRE + "file name:" + params[1]);
downloadPath = params[1];
int returnCode = SUCCESS;
FileOutputStream fos = null;
try {
URL url = new URL(params[0]);
File file = new File(params[1]);
fos = new FileOutputStream(file);
long startTime = System.currentTimeMillis();
URLConnection ucon = url.openConnection();
InputStream is = ucon.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
byte[] data = new byte[10240];
int nFinishSize = 0;
while( bis.read(data, 0, 10240) != -1){
fos.write(data, 0, 10240);
nFinishSize += 10240;
**Thread.sleep( 1 ); // this make cancel method work**
this.publishProgress(nFinishSize);
}
data = null;
Log.d(TAG, "download ready in"
+ ((System.currentTimeMillis() - startTime) / 1000)
+ " sec");
} catch (IOException e) {
Log.d(TAG, PRE + "Error: " + e);
returnCode = FAIL;
} catch (Exception e){
e.printStackTrace();
} finally{
try {
if(fos != null)
fos.close();
} catch (IOException e) {
Log.d(TAG, PRE + "Error: " + e);
e.printStackTrace();
}
}
return returnCode;
}
これを行う唯一の方法は、isCancelled() メソッドの値を確認し、true が返されたときに再生を停止することです。
cancel(true)
ソケットやファイルストリームを閉じたり、ローカルデータベースにデータを書き込んだりするなど、リソースを解放する必要がある可能性があるため、非同期タスクを不必要に強制的に中断するのは好きではありません。非同期タスクは、一部の時間の終了を拒否します。たとえば、メイン アクティビティが閉じられているときに、アクティビティのonPause()
メソッド内から非同期タスクに終了を要求することがあります。したがって、単に呼び出すだけの問題ではありませんrunning = false
。混合ソリューションを使用する必要があります。両方が を呼び出してから、非同期タスクが完了するまで数ミリ秒待ってから、 または のいずれかrunning = false
を呼び出します。cancel(false)
cancel(true)
if (backgroundTask != null) {
backgroundTask.requestTermination();
try {
Thread.sleep((int)(0.5 * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
if (backgroundTask.getStatus() != AsyncTask.Status.FINISHED) {
backgroundTask.cancel(false);
}
backgroundTask = null;
}
副次的な結果として、doInBackground()
終了後にonCancelled()
メソッドが呼び出されることもあれば、 onPostExecute()
. しかし、少なくとも非同期タスクの終了は保証されています。
グローバル 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);
}
わたしにはできる。