답변:
그냥 발견 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;
}
// ...
}
while(running)
로 while(!isCancelled())
다른 사람이 여기에 코멘트에 말했듯이.
계산을하는 경우 :
isCancelled()
주기적으로 확인 해야합니다.HTTP 요청을하는 경우 :
HttpGet
또는 HttpPost
다른 곳에 (예 : 공개 필드) 인스턴스를 저장합니다 .cancel
, 호출 request.abort()
. 이것은 IOException
당신의 doInBackground
.제 경우에는 다양한 AsyncTasks에서 사용한 커넥터 클래스가있었습니다. 간단하게 abortAllRequests
하기 위해 해당 클래스에 새 메서드를 추가 하고을 호출 한 직후이 메서드를 호출했습니다 cancel
.
HttpGet.abort()
백그라운드 스레드에서 호출해야합니다. 그렇지 않으면 android.os.NetworkOnMainThreadException
.
cancel(true)
중단 하지 않아야 합니까? 문서에서 :If the task has already started, then the mayInterruptIfRunning parameter determines whether the thread executing this task should be interrupted in an attempt to stop the task.
HttpURLConnection.disconnect();
cancel(true)
. 나는 그것을 사용하고 작동합니다.
문제는 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;
}
}
running
플래그 를 만들 필요가 없습니다 . AsyncTask에는 작업이 취소되었을 때 설정되는 내부 플래그가 있습니다. 교체 while (running)
와 함께 while (!isCancelled())
. developer.android.com/reference/android/os/… 따라서이 간단한 경우에는 onCancelled()
재정의 가 필요하지 않습니다 .
간단합니다 AsyncTask
.. AsyncTask
빠르게 (수십 초) 종료되는 짧은 작업을 위해 설계되었으므로 취소 할 필요가 없습니다. "오디오 파일 재생"은 적합하지 않습니다. 일반 오디오 파일 재생을위한 백그라운드 스레드도 필요하지 않습니다.
onPostExecute()
는 작업을 계속해야하는지 여부를 확인하기 위해 테스트 합니다.
이것이 제가 AsyncTask를 작성하는 방법입니다
. 핵심은 add Thread.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;
}
글로벌 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);
}
그것은 나를 위해 작동합니다.
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()
. 그러나 적어도 비동기 작업 종료는 보장됩니다.
Yanchenko의 답변 인 '10 년 4 월 29 일 : AsyncTask를 실행할 때마다 'doInBackground'아래의 코드를 여러 번 실행해야 할 때 'while (running)'접근 방식을 사용하는 것이 깔끔합니다. 'doInBackground'아래의 코드가 AsyncTask 실행 당 한 번만 실행되어야하는 경우 'while (running)'루프의 'doInBackground'아래에있는 모든 코드를 래핑해도 백그라운드 코드 (백그라운드 스레드)가 실행되는 것을 중지하지 않습니다. AsyncTask 자체는 취소됩니다. 왜냐하면 'while (running)'조건은 while 루프 내의 모든 코드가 적어도 한 번 실행 된 후에 만 평가되기 때문입니다. 따라서 (a.) 'doInBackground'아래의 코드를 여러 'while (running)'블록으로 나누거나 (b.) 수많은 'isCancelled'를 수행해야합니다.https://developer.android.com/reference/android/os/AsyncTask.html .
옵션 (a.)의 경우 Yanchenko의 대답을 다음과 같이 수정할 수 있습니다.
public class MyTask extends AsyncTask<Void, Void, Void> {
private volatile boolean running = true;
//...
@Override
protected void onCancelled() {
running = false;
}
@Override
protected Void doInBackground(Void... params) {
// does the hard work
while (running) {
// part 1 of the hard work
}
while (running) {
// part 2 of the hard work
}
// ...
while (running) {
// part x of the hard work
}
return null;
}
// ...
옵션 (b.)의 경우 'doInBackground'의 코드는 다음과 같습니다.
public class MyTask extends AsyncTask<Void, Void, Void> {
//...
@Override
protected Void doInBackground(Void... params) {
// part 1 of the hard work
// ...
if (isCancelled()) {return null;}
// part 2 of the hard work
// ...
if (isCancelled()) {return null;}
// ...
// part x of the hard work
// ...
if (isCancelled()) {return null;}
}
// ...