Android 如果任务在活动处于后台时完成,则处理AsyncTask

Android 如果任务在活动处于后台时完成,则处理AsyncTask,android,android-asynctask,Android,Android Asynctask,我使用AsyncTasks已经有一段时间了,但是最近遇到了一个场景,我不确定如何正确处理。因为我认为这是一种比较常见的情况,所以我决定在这里问这个问题 因此,我尝试使用AsyncTask进行一个简单的调用,让用户登录到应用程序。调用完成后,如果成功,则应将用户带到另一个活动。这个逻辑很简单。当用户在登录呼叫返回之前离开应用程序时,问题就会出现。在这种情况下,我应该在onPostExecute()中执行什么操作 我所看到的一些应用程序所做的是,只要活动仍然存在,它们无论如何都会继续呼叫,并将启动下

我使用AsyncTasks已经有一段时间了,但是最近遇到了一个场景,我不确定如何正确处理。因为我认为这是一种比较常见的情况,所以我决定在这里问这个问题

因此,我尝试使用AsyncTask进行一个简单的调用,让用户登录到应用程序。调用完成后,如果成功,则应将用户带到另一个活动。这个逻辑很简单。当用户在登录呼叫返回之前离开应用程序时,问题就会出现。在这种情况下,我应该在
onPostExecute()
中执行什么操作

我所看到的一些应用程序所做的是,只要活动仍然存在,它们无论如何都会继续呼叫,并将启动下一个活动。然而,这创造了一种奇怪的体验,用户离开应用程序,然后几秒钟后,应用程序突然出现在他们面前。当然,我希望避免这样做

更新 示例代码:

public class ExampleActivity extends Activity {
    private boolean mIsPaused;
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        Button btnSignIn = (Button) findViewById(R.id.btn_sign_in);
        btnSignIn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                new SignInTask(ExampleActivity.this).execute();
            }
        });
        ...
    }

    @Override
    protected void onPause() {
        super.onPause();
        mIsPaused = true;
    }

    @Override
    protected void onResume() {
        super.onResume();
        mIsPaused = false;
    }

    private boolean isPaused() {
        return mIsPaused;
    }

    ...
    private static class SignInTask extends AsyncTask<Void, Void, SomeResult> {

        private final WeakReference<ExampleActivity> mAct;

        public SignInTask(ExampleActivity act) {
            mAct = new WeakReference<ExampleActivity>(act);
        }

        @Override
        protected SomeResult doInBackground(Void... params) {
            return mApi.signIn(creds);
        }

        @Override
        protected void onPostExecute(SomeResult result) {
            if (result.getCode() == OK) {
                ExampleActivity act = mAct.get();
                if (act != null) {
                    if (act.isPaused()) {
                        // do something
                    } else {
                        startActivity(new Intent(act, NextActivity.class));
                    }
                } else {
                    // do something
                }
            }

        }
    }
}
公共类ExampleActivity扩展活动{
私人布尔错误假设;
...
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
...
按钮btnSignIn=(按钮)findViewById(R.id.btn\u sign\u in);
setOnClickListener(新的OnClickListener(){
@凌驾
公共void onClick(视图v){
new SigningTask(ExampleActivity.this.execute();
}
});
...
}
@凌驾
受保护的void onPause(){
super.onPause();
假假=真;
}
@凌驾
受保护的void onResume(){
super.onResume();
误发=假;
}
私有布尔值isPaused(){
返回假信号;
}
...
专用静态类SIGNTASK扩展异步任务{
私人最终WeakReference mAct;
公共信号任务(例如活动法){
mAct=新WeakReference(act);
}
@凌驾
受保护的SomeResult doInBackground(无效…参数){
返回mApi.SIGN(creds);
}
@凌驾
PostExecute上受保护的void(SomeResult结果){
if(result.getCode()==OK){
ExampleActivity act=mAct.get();
if(act!=null){
if(act.isPaused()){
//做点什么
}否则{
startActivity(新意图(act,NextActivity.class));
}
}否则{
//做点什么
}
}
}
}
}

我建议在执行后使用try/catch语句-据我所知,在这种情况下会出现某种窗口管理器异常

但是,我强烈建议停止onPause方法上的任何异步任务(使用cancel方法),这意味着您不会中断它们

公共最终布尔值取消(布尔值可能中断frunning)

在API级别3中添加 试图取消此任务的执行。如果任务已完成、已取消或由于其他原因无法取消,则此尝试将失败。如果成功,并且调用cancel时此任务尚未启动,则此任务不应运行。如果任务已经启动,则MayInterruptFrunning参数确定执行此任务的线程是否应该中断以尝试停止任务

调用此方法将导致在doInBackground(Object[])返回后在UI线程上调用onCancelled(Object)。调用此方法可确保永远不会调用onPostExecute(对象)。调用此方法后,应定期检查IsCancell()从doInBackground(Object[])返回的值,以便尽早完成任务

参数 如果执行此任务的线程应该被中断,则可能中断frunning
true;否则,允许完成正在进行的任务。 退换商品 如果无法取消任务(通常是因为任务已正常完成),则为false;反之亦然 另见 已取消() onCancelled(对象)


将AsyncTask类设置为静态内部类

boolean isRunning; //set it to true in onResume, and false in onStop
boolean isWaiting; // set it to true in onPostExecute, if "isRunning" is false

检查
onResume
是否
isWaiting
为真,如果是,将用户带到另一个屏幕。

非常有趣的问题。。。按照您使用布尔函数开始的步骤,您可以在活动暂停时将其收到的响应保存到SharedReferences,或者在未暂停时继续正常处理。如果活动稍后继续(或重新创建),请检查是否有已保存的响应,并相应地进行处理。我的想法大致如下:

import org.json.JSONObject;

import android.app.Activity;
import android.os.Bundle;

public class TaskActivity extends Activity {

    private static final String KEY_RESPONSE_JSON = "returned_response";

    private boolean paused = false;

    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        // don't setup here, wait for onPostResume() to figure out what to do
    }

    @Override
    public void onPostResume(){
        super.onPostResume();
        paused = false;

        if(isSavedResponseAvailable()) processResponse(getSavedResponse());
        else setup();
    }

    @Override
    public void onPause(){
        paused = true;
        super.onPause();
    }

    private void setup(){ 
        // normal setup
    }

    public void onReceiveResponse(JSONObject response){
        if(paused) setSavedResponse(response);
        else processResponse(response); 
    }

    private void processResponse(JSONObject response){
        // Continue with processing as if they never left

        getSharedPreferences(this.getClass().getName(), 0).edit().clear().commit(); // Clear everything so re-entering won't parse old data
    }   

    private boolean isSavedResponseAvailable(){
        return getSavedResponse() != null;
    }

    private JSONObject getSavedResponse(){
        try{
            return new JSONObject(getSharedPreferences(this.getClass().getName(), 0).getString(KEY_RESPONSE_JSON, ""));
        }
        catch(Exception e){ }
        return null;
    }

    private void setSavedResponse(JSONObject response){
        getSharedPreferences(this.getClass().getName(), 0).edit().putString(KEY_RESPONSE_JSON, response.toString()).commit();
    }
}
显然,这是假设任务的响应是JSON,但是没有理由不扩展它来单独保存数据并从保存的首选项数据重建必要的响应对象

不过,就清洁方法而言。。。我给出了一个3/10的版本,但我想不出更好的版本了(好吧,除了将TaskActivity抽象并强制实现覆盖
setup()、processResponse()、isResponseAvailable()、getSavedResponse()和setSavedResponse()
,但对于4/10这样的版本来说,这只会稍微好一点)

使用cancel()Activty类的backpress()上的AsynchTask类的
公共类ExampleActivity扩展了活动{
私人布尔错误假设;
SIGNTASK SINGETASK OBJ;
...
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
...
按钮btnSignIn=(按钮)findViewById(R.id.btn\u sign\u in);
setOnClickListener(新的OnClickListener(){
@凌驾
公共void onClick(视图v){
singleTaskObj=新的符号任务(Examp
   Use the cancel() of AsynchTask class onBackPress() of Activty class


 public class ExampleActivity extends Activity {
private boolean mIsPaused;
SignInTask singleTaskObj;
...
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ...
    Button btnSignIn = (Button) findViewById(R.id.btn_sign_in);
    btnSignIn.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
           singleTaskObj =  new SignInTask(ExampleActivity.this).execute();
        }
    });
    ...
}

@Override
protected void onPause() {
    super.onPause();
    mIsPaused = true;
}

@Override
protected void onResume() {
    super.onResume();
    mIsPaused = false;
}

protected void onBackPressed()
{
 singleTaskObj.cancel();
}

private boolean isPaused() {
    return mIsPaused;
}

...
private static class SignInTask extends AsyncTask<Void, Void, SomeResult> {

    private final WeakReference<ExampleActivity> mAct;

    public SignInTask(ExampleActivity act) {
        mAct = new WeakReference<ExampleActivity>(act);
    }

    @Override
    protected SomeResult doInBackground(Void... params) {
        return mApi.signIn(creds);
    }

    @Override
    protected void onPostExecute(SomeResult result) {
        if (result.getCode() == OK) {
            ExampleActivity act = mAct.get();
            if (act != null) {
                if (act.isPaused()) {
                    // do something
                } else {
                    startActivity(new Intent(act, NextActivity.class));
                }
            } else {
                // do something
            }
        }

    }
}
}