2016-08-11 9 views
2

私はAndroid開発には比較的新しいので、onSaveInstanceState()について質問があります。私は現在、アプリケーションのログインアクティビティに取り組んでいます。ユーザーが自分のアカウントにログインできるかどうかを確認するために、サーバーへのコールを実行し、レスポンスコードに基づいてユーザーにアクセスを許可するかどうかを確認します。私の質問の根拠は、私が休憩コールクラスにアクティビティのコンテキストを渡すのを避けようとしているという事実に基づいています。これを行うために、私は、残りの呼び出しが成功したかどうかを表すloginアクティビティと、rest-callクラスに渡すbooleanを更新するrunnableを作成するブール値フィールドを作成します。これはAsyncTaskのアイデアに反していることは知っていますが、これが起こっている間にユーザーに待つようにダイアログボックスを表示するだけでは何も見つかりません。私の質問は以下の通りです。OnSaveInstanceState/RestCalls

1)onCreateメソッドでsavedInstanceState()を使用すると、このブール値フィールドを最初にインスタンス化して、nullのオブジェクトブール値をチェックすることを禁止しますか?私が意味するのは、アクティビティが何らかの理由で(オリエンテーションの変更など)破棄された後で、オーバーライドされたonSaveInstanceStateメソッドに格納されているブール値を使用することです。ただし、初めて作成されたときはブール値への参照がないため、ブール値を作成する必要があります。

2)このRunnableは役立ちますか?コンテキストを渡す必要はありませんでしたが、RestCall(AsyncTask)が完了する前にアクティビティが削除される場合は、コンテキストまたはRunnableを渡すかどうかが重要ですアクティビティ?私がこれについて考えると、存在しないオブジェクトを指し示す結果になるので、それが大きな違いを生み出すとは思えません。私はそれが最適ではないが、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

なぜあなたはアンドロイドから 'AsyncTask'を使っていませんか?必要なものはすべて用意されており、タスクをより詳細に制御する必要がある場合はコールバックを渡すことさえできます。 –

答えて

2

おめでとうございます。あなたはちょうどAndroidの汚れた小さな秘密を発見しました。

AsyncTaskには、固有の設計上の欠陥があります。あなたが言及した問題の正確さのためにバックグラウンドタスクの実行中に起こる構成の変更をうまく処理しません。アクティビティへの参照を保持する必要がありますが、バックグラウンドタスクが完了するまで参照が有効であるという保証はありません。私は活動の破壊やレクリエーションをまたがるようsetRetainInstance(true)に隠された断片を使用してAlex Lockwood's excellent blog postにあなたを参照してください

  1. は、ここでは、この問題を克服するための2つの方法があります。これは、次のソリューションよりも複雑なソリューションですが、このソリューションでは、コールバックを使用して進行状況を報告できるという利点があります。 AsyncTaskpublishProgress()に電話をかけようとしていた場合は、これを使用する必要があります。

  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()オーバーライドで、私はローダのIDにloaderManager.destroyLoader()を呼び出してください:

    は、ここでの例です。

    また、Alex Lockwoodのブログには、ローダーに関する素晴らしい記事もあります。 UIについては

、私は頻繁に行う何かがloaderManager.initLoader()を呼び出すときにUI上の不確定進捗バーを設置しています。私はまたmProgressShownのようなブール値を設定します。このブール値はonSaveInstanceStateに保存されるので、アクティビティ/フラグメントが再び作成されたときにブール値が復元されます。ブール値は直ちにプログレスバーを表示するように指示します。しばらくしてonLoadFinishedが呼び出され、mProgressShownがクリアされ、進行状況バーが非表示になります。

+0

ありがとう!これはまさに私が必要としていたものです! – James