簡體   English   中英

如果Activity在后台運行,則處理AsyncTask

[英]Handle AsyncTask if the task completes while the Activity is in the background

我使用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
                }
            }

        }
    }
}

使您的AsyncTask類成為靜態內部類。

一個非常有趣的問題...從使用布爾值開始,您可以將Activity暫停時收到的響應保存到SharedPreferences中,如果沒有,則繼續正常處理。 如果活動稍后恢復(或重新創建),請檢查是否存在已保存的響應並進行相應處理。 我在考慮以下方面:

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(), and setSavedResponse() ,但對於4/10而言,效果會稍好一些)

我建議在執行后添加一條try / catch語句-據我所知,在這種情況下會發生某種窗口管理器異常的情況。

但是,我強烈建議您在onPause方法上停止所有異步任務(使用cancel方法),這意味着您不會中斷它們。

http://developer.android.com/reference/android/os/AsyncTask.html#cancel(boolean)

public final布爾取消(boolean mayInterruptIfRunning)

API級別3中已添加嘗試取消執行此任務。 如果任務已經完成,已經被取消或由於某些其他原因而無法取消,則此嘗試將失敗。 如果成功,並且在調用cancel時此任務尚未開始,則該任務永遠不要運行。 如果任務已經開始,則mayInterruptIfRunning參數確定是否應中斷執行該任務的線程以嘗試停止該任務。

調用此方法將導致doInBackground(Object [])返回后,onCancelled(Object)在UI線程上被調用。 調用此方法可確保永遠不會調用onPostExecute(Object)。 調用此方法后,應定期從doInBackground(Object [])檢查isCancelled()返回的值,以盡早完成任務。

參數mayInterruptIfRunning
如果應該中斷執行此任務的線程,則為true;否則為false。 否則,將允許正在進行的任務完成。 如果無法取消任務(通常是因為它已經正常完成),則返回false;否則,返回false。 否則為true,另請參見isCancelled()onCancelled(Object)

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是否為true,如果是,則將用戶帶到另一個屏幕。

   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
            }
        }

    }
}
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM