我使用异步任务上传图片并获得一些结果。
在上传图片时,我看到一个进度对话框,用onPreExecute()方法编写,如下所示:
protected void onPreExecute() {
uploadingDialog = new ProgressDialog(MyActivity.this);
uploadingDialog.setMessage("uploading");
uploadingDialog.setCancelable(true);
uploadingDialog.show();
}
好的,当我按下后退按钮时,显然对话框因setCancelable(true)而消失。
但(显然)异步任务不会停止。
那我怎么解决这个问题呢?当我按下后退按钮时,我想取消对话和异步任务。有什么想法吗?
编辑:找到解决方案。请看下面的答案。
答案 0 :(得分:100)
来自SDK:
取消任务
可以通过调用cancel(boolean)随时取消任务。 调用此方法将导致后续调用isCancelled() 返回真实。
调用此方法后,onCancelled(Object),而不是 doInBackground(Object [])返回后将调用onPostExecute(Object)。
确保尽快取消任务, 你应该定期检查isCancelled()的返回值 doInBackground(Object []),如果可能的话(例如在循环内)。
所以你的代码适合于对话框监听器:
uploadingDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) {
myTask.cancel(true);
//finish();
}
});
现在,正如我之前在SDK中提到的那样,您必须检查任务是否被取消,因为您必须在onPreExecute()方法中检查 isCancelled()。
例如:
if (isCancelled())
break;
else
{
// do your work here
}
答案 1 :(得分:32)
找到解决方案: 我在上传Digial.show()之前添加了一个动作监听器:
uploadingDialog.setOnCancelListener(new DialogInterface.OnCancelListener(){
public void onCancel(DialogInterface dialog) {
myTask.cancel(true);
//finish();
}
});
当我按下后退按钮时,上面的OnCancelListener取消了对话框和任务。如果要在后退时完成整个活动,也可以添加finish()。请记住将异步任务声明为如下变量:
MyAsyncTask myTask=null;
执行你的异步任务:
myTask = new MyAsyncTask();
myTask.execute();
答案 2 :(得分:10)
我花了一段时间搞清楚这一点,我想要的只是一个如何做到的简单例子,所以我想我会发布我是如何做到的。这是一些更新库的代码,并有一个进度对话框,显示已更新的书籍数量,并在用户取消对话框时取消:
private class UpdateLibrary extends AsyncTask<Void, Integer, Boolean>{
private ProgressDialog dialog = new ProgressDialog(Library.this);
private int total = Library.instance.appState.getAvailableText().length;
private int count = 0;
//Used as handler to cancel task if back button is pressed
private AsyncTask<Void, Integer, Boolean> updateTask = null;
@Override
protected void onPreExecute(){
updateTask = this;
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setOnDismissListener(new OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
updateTask.cancel(true);
}
});
dialog.setMessage("Updating Library...");
dialog.setMax(total);
dialog.show();
}
@Override
protected Boolean doInBackground(Void... arg0) {
for (int i = 0; i < appState.getAvailableText().length;i++){
if(isCancelled()){
break;
}
//Do your updating stuff here
}
}
@Override
protected void onProgressUpdate(Integer... progress){
count += progress[0];
dialog.setProgress(count);
}
@Override
protected void onPostExecute(Boolean finished){
dialog.dismiss();
if (finished)
DialogHelper.showMessage(Str.TEXT_UPDATELIBRARY, Str.TEXT_UPDATECOMPLETED, Library.instance);
else
DialogHelper.showMessage(Str.TEXT_UPDATELIBRARY,Str.TEXT_NOUPDATE , Library.instance);
}
}
答案 3 :(得分:9)
在您的活动中创建一些成员变量,如
YourAsyncTask mTask;
Dialog mDialog;
将这些用于对话和任务;
onPause()中的只需调用
if(mTask!=null) mTask.cancel();
if(mDialog!=null) mDialog.dismiss();
答案 4 :(得分:5)
我想改进代码。当您aSyncTask
onCancelled()
aSyncTask
的回调方法被自动调用时,您可以隐藏progressBarDialog
。
您也可以包含此代码:
public class information extends AsyncTask<String, String, String>
{
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected String doInBackground(String... arg0) {
return null;
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
this.cancel(true);
}
@Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
}
@Override
protected void onCancelled() {
Toast.makeText(getApplicationContext(), "asynctack cancelled.....", Toast.LENGTH_SHORT).show();
dialog.hide(); /*hide the progressbar dialog here...*/
super.onCancelled();
}
}
答案 5 :(得分:3)
我使用AsyncTask的大部分时间我的业务逻辑都是在一个独立的业务类上,而不是在UI上。在那种情况下,我在doInBackground()中没有循环。一个例子是同步过程,它消耗服务并一个接一个地保存数据。
我最终将我的任务交给业务对象,以便它可以处理取消。我的设置是这样的:
public abstract class MyActivity extends Activity {
private Task mTask;
private Business mBusiness;
public void startTask() {
if (mTask != null) {
mTask.cancel(true);
}
mTask = new mTask();
mTask.execute();
}
}
protected class Task extends AsyncTask<Void, Void, Boolean> {
@Override
protected void onCancelled() {
super.onCancelled();
mTask.cancel(true);
// ask if user wants to try again
}
@Override
protected Boolean doInBackground(Void... params) {
return mBusiness.synchronize(this);
}
@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
mTask = null;
if (result) {
// done!
}
else {
// ask if user wants to try again
}
}
}
public class Business {
public boolean synchronize(AsyncTask<?, ?, ?> task) {
boolean response = false;
response = loadStuff(task);
if (response)
response = loadMoreStuff(task);
return response;
}
private boolean loadStuff(AsyncTask<?, ?, ?> task) {
if (task != null && task.isCancelled()) return false;
// load stuff
return true;
}
}
答案 6 :(得分:2)
你可以要求取消,但不能真正终止它。请参阅此answer。
答案 7 :(得分:2)
我有类似的问题 - 基本上我是在用户销毁活动后在异步任务中获得NPE。在研究Stack Overflow上的问题之后,我采用了以下解决方案:
volatile boolean running;
public void onActivityCreated (Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
running=true;
...
}
public void onDestroy() {
super.onDestroy();
running=false;
...
}
然后,我在异步代码中定期检查“是否正在运行”。我有压力测试这个,我现在无法“打破”我的活动。这非常有效,并且比我在SO上看到的一些解决方案更简单。
答案 8 :(得分:1)
如何取消AsyncTask
完整答案在这里-Android AsyncTask Example
AsyncTask提供了更好的取消策略,可以终止当前正在运行的任务。
取消(布尔值mayInterruptIfitRunning)
myTask.cancel(false)-使isCancelled返回true。帮助取消任务。
myTask.cancel(true)–它还使isCancelled()返回true,中断后台线程并释放资源。
这被认为是一种自大的方法,如果在后台线程中执行任何thread.sleep()方法,则cancel(true)会在那时中断后台线程。但是cancel(false)将等待它,并在该方法完成后取消任务。
如果您调用cancel()而doInBackground()尚未开始执行。 onCancelled()将调用。
在调用cancel(…)之后,应该定期检查doInbackground()上isCancelled()返回的值。如下图所示。
protected Object doInBackground(Params… params) {
while (condition)
{
...
if (isCancelled())
break;
}
return null;
}