2016-08-11 46 views
2

我對Android開發比較陌生,我對onSaveInstanceState()有個疑問。我目前正在爲應用程序開發一個登錄Activity。要檢查用戶是否可以登錄到他們的帳戶,我會對服務器執行一次休息呼叫,並根據響應代碼查看是否應該授予用戶訪問權限。我的問題的根源在於,我試圖避免將Activity的Context傳遞給我的rest-call類。爲此,我在我的登錄Activity中創建了一個布爾型字段,表示剩餘調用是否成功,以及一個可更新布爾型的runnable,我將其傳遞給其餘調用類。我知道這與AsyncTask的想法背道而馳,但我無法找到任何替代方法來簡單地建立一個對話框,告訴用戶在發生這種情況時要等待。我的問題如下。如果我在onCreate方法中使用savedInstanceState(),如何在第一次實例化這個布爾型字段barring null檢查一個Object布爾值?我的意思是,在任何原因(例如方向改變等)下銷燬活動後,我將使用存儲在我的覆蓋onSaveInstanceState方法中的布爾值;然而,當它第一次創建時,它沒有引用一個布爾值,所以它必須創建一個。OnSaveInstanceState/RestCalls

2)這個Runnable甚至有幫助嗎?我這樣做是爲了不必傳遞上下文,但是如果在RestCall(AsyncTask)完成之前將刪除Activity,那麼傳遞上下文還是影響Runnable的Runnable字段無關緊要嗎?活動?我越想到這一點,我越相信它不會產生太大的變化,因爲它仍然會導致它指向一個不存在的對象。我試圖避免使用Singleton設計,因爲我收集它並不是最優的,但是由於AsyncTask存在潛在的時間滯後,我開始認爲它可能是不可避免的。

我知道onSaveInstanceState()是一個已經在StackOverflow上提出很多的主題,但是我找不到這些問題的答案。我很抱歉,如果已經有這樣的線程,但任何幫助或指導,將不勝感激!謝謝!

登錄活動的設置:

public class LoginActivity extends Activity implements View.OnClickListener { 

private EditText username_et; 
private EditText password_et; 
private Button login_b; 
private boolean login_success = true; 
private Runnable run; 


/** 
* Instances created when app starts 
*/ 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.view_login); 
// login_success = false; 
    login_success = savedInstanceState.getBoolean("login_success"); 
    username_et = (EditText) findViewById(R.id.username_text); 
    username_et.setOnClickListener(LoginActivity.this); 
    password_et = (EditText) findViewById(R.id.password_text); 
    password_et.setOnClickListener(LoginActivity.this); 
    login_b = (Button) findViewById(R.id.login_button); 
    login_b.setOnClickListener(LoginActivity.this); 
    run = new Runnable() { 
     @Override 
     public void run() { 
      login_success = true; 
     } 
    }; 
} 

@Override 
public void onSaveInstanceState(Bundle savedInstanceState){ 
    super.onSaveInstanceState(savedInstanceState); 
    savedInstanceState.putBoolean("login_success", login_success); 
} 
+0

爲什麼你不使用Android的'AsyncTask'?它擁有你需要的一切,如果你需要更多的控制任務,你甚至可以通過回調。 –

回答

2

祝賀。你剛剛發現Android的骯髒的小祕密。

AsyncTask有一個固有的設計缺陷。它不能很好地處理後臺任務執行期間發生的配置更改,因爲您提到的問題確實存在。它需要保持對活動的引用,但不能保證引用在後臺任務完成時仍然有效。

這裏有兩種方法來解決這個問題:

  1. 我是指你Alex Lockwood's excellent blog post使用隱藏的片段,setRetainInstance(true)跨越破壞活動和娛樂。這是一個比下一個更復雜的解決方案,但是這個解決方案的優點是您仍然可以使用回調來報告進度。如果您打算在AsyncTask中撥打publishProgress(),那麼這是您應該使用的方法。

  2. 使用Loader。裝載機是在後臺對數據庫數據檢索進行設計的,但事實是,它們也可以用於在後臺處理遠程服務器訪問。我爲大部分遠程服務器任務使用了Loader

    下面是一個例子:

    public static class ResetPasswordLoader extends AsyncTaskLoader<Pair<CharSequence, Exception>> { 
    
        private static final String TAG = "ResetPasswordLoader "; 
    
        private String mEmail; 
    
        public ResetPasswordLoader(Context context, String email) { 
         super(context); 
         mEmail = email; 
         // set the content-changed flag 
         onContentChanged(); 
        } 
    
        @Override 
        protected void onStartLoading() { 
    
         // only start the load if the content-changed flag is set 
         // takeContentChanged() returns the value of the flag before it is cleared 
         if (takeContentChanged()) { 
          forceLoad(); 
         } 
        } 
    
        @Override 
        public Pair<CharSequence, Exception> loadInBackground() { 
    
         CharSequence result = null; 
         Exception exc = null; 
         try { 
          result = Service.getInstance().resetPassword(mEmail); 
         } catch (RemoteServiceException e) { 
          exc = e; 
          Log.e(TAG, "loadInBackground(), email = " + mEmail, e); 
         } 
    
         return new Pair<>(result, exc); 
        } 
    } 
    

    而且,在我onLoadFinished()覆蓋我請確保調用loaderManager.destroyLoader()對裝載機的ID。

    再一次,亞歷克斯洛克伍德的博客也有一些關於裝載機的偉大文章。

對於UI,這是我經常做的是在調用時loaderManager.initLoader()提出了一個不確定的進度條在UI。我還設置了一個布爾值,如mProgressShown。這個布爾值被保存在onSaveInstanceState中,所以當再次創建活動/片段時,我恢復了布爾值,它告訴我立即顯示進度條。一段時間後,onLoadFinished將被調用,我清除mProgressShown並隱藏進度條。

+0

謝謝!這正是我需要的! – James