1

週末に、最初の Android アプリの作成を開始しました。アプリのユーザーにユーザー資格情報を求める必要があるため (これは、さらに Web サービスを使用するために使用されます)、「ログイン システム」をシミュレートしたいと考えています。アプリの開始時に、ユーザーは自分の資格情報を入力するように指示されます。ユーザーが長時間非アクティブになっている場合、入力した資格情報を破棄して、ユーザーを「ログアウト」したいと考えています。コーディング中とその後のテスト中に、自分ができると思っていた方法が機能しないことに気付きました。ドキュメントといくつかのSO-質問を何度も読んだ後、アプリ/アクティビティのライフサイクルとその可能性を完全に理解しているかどうか、ますます自問自答します. そこで、ライフ サイクルと、それがアプリに与える影響を理解するための助けを求めたいと思いました。はい、これはいくつかの質問をまとめたものかもしれません:/

現時点では、私のアプリは次のアクティビティで構成されています。

  • 検索アクティビティ (アプリが開始されると開かれます)
  • 設定アクティビティ (検索ダイアログからアクセスでき、検索ダイアログに戻るリンクがあります)

ユーザーが検索ダイアログに ID を入力した後、検索結果 (NYI) に関するアクティビティを開きたいと考えています。

ユーザー認証の実装を開始するとき、私の考えは次のとおりonResume()でした。アクティビティが呼び出されるたびに、a) ユーザー資格情報が既に保存されているかどうか、b) ユーザーの最後のアクションが X 分前であるかどうかを確認する必要があります。これらのいずれかが失敗した場合、ユーザーが自分の資格情報を入力できる「ログインパネル」を表示したいと思います。資格情報は SharedPreferences に保存されます。そのために、次のことを行いました。

まず、SharedPreferences のチェックと参照を持つ親アクティビティを作成します。

public class AppFragmentActivity extends FragmentActivity  {

  protected SharedPreferences sharedPref;
  protected SharedPreferences.Editor editor;    

  protected String WebServiceUsername;
  protected String WebServicePassword;


  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_appfragmentactivity);

  } 


  @Override
  protected void onResume () {
    super.onResume();


    // Check if user is "logged in".
    // Meaning: Are there given user credentials and are they valid of was the user inactive for too long?

    // We only do this "onResume" because this callback is the only one, which is called everytime an user 
    // starts/restarts/resumes an application
    checkForUserCredentials();


    // Set new "last action" now "now"
    setLastAction(new Date().getTime());
  }

  @Override
  protected void onStart () {
    // Fill content
    super.onStart();

    // Set global sharedPreferences
    sharedPref = this.getSharedPreferences(getString(R.string.FILE_settings_file), Context.MODE_PRIVATE);

  }



  /*
   * Checks if user credentials are valid meaning if they are set and not too old
   */
  private void checkForUserCredentials() {  

    long TimeLastAction = sharedPref.getLong(getString(R.string.SETTINGS_USER_LAST_ACTION), 0);
    long TimeNow = new Date().getTime();

    // Ask for User credentials when last action is too long ago
    if(TimeLastAction < (TimeNow - 1800)) {
      // Inactive for too long
      // Set back credentials 
      setUsernameAndPassword("", "");

    }
    else
    {
      WebServiceUsername = sharedPref.getString(getString(R.string.SETTINGS_USER_USERNAME), "");
      WebServicePassword = sharedPref.getString(getString(R.string.SETTINGS_USER_PASSWORD), "");                
    }

  }

  /*
   * Saves the given last action in the sharedPreferences
   * @param long LastAction - Time of the last action
   */
  private void setLastAction(long LastAction) {
    editor = sharedPref.edit();
    editor.putLong(getString(R.string.SETTINGS_USER_LAST_ACTION), LastAction);
    editor.commit();        
  }

  /*
   * Saves the given username and userpassword sharedPreferences
   * @param String username
   * @param String password
   */
  private void setUsernameAndPassword(String username, String password) {
    editor = sharedPref.edit();
    editor.putString(getString(R.string.SETTINGS_USER_USERNAME), username);
    editor.putString(getString(R.string.SETTINGS_USER_PASSWORD), password);
    editor.commit();    

    WebServiceUsername = username;
    WebServicePassword = password;
  }

  /*
   * Method called when pressing the OK-Button
   */
    public void ClickBtnOK(View view) {
        // Save User-Creentials

      EditText dfsUsername = (EditText) findViewById(R.id.dfsUsername);
      String lvsUsername = dfsUsername.getText().toString();        

      EditText dfsPassword = (EditText) findViewById(R.id.dfsPassword);
      String lvsPassword = dfsPassword.getText().toString();        

      if(lvsUsername.equals("") || lvsPassword.equals("")) {
        TextView txtError = (TextView) findViewById(R.id.txtError);
        txtError.setText(getString(R.string.ERR_Name_or_Password_empty));
      }
      else
      {
        // Save credentials
        setUsernameAndPassword(lvsUsername, lvsPassword);
        setLastAction(new Date().getTime());

        // open Searchactivity
          Intent intent = new Intent(this, SearchActivity.class);
          startActivity(intent);            

      }         

}   

「ログインマスク」はsetContentView(R.layout.activity_appfragmentactivity);.

私が作成した他の 2 つのアクティビティは、この親クラスを拡張しています。これはその1つです:

public class SearchActivity extends AppFragmentActivity {
  SearchFragment searchfragment;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_search);
  }

  @Override
  protected void onResume() {
    super.onResume();

    if(WebServiceUsername.equals("") && WebServicePassword.equals("")) {
      // Username not set. Re"login".
      Intent intent = new Intent(this, AppFragmentActivity.class);
      startActivity(intent);            
    }
  }

  @Override
  protected void onStart() {
    super.onStart();
  }

  // ...
}  

私がライフサイクルを理解している限り、これは次のように機能するはずです: アプリが起動すると (SearchActivityが に設定されています)、アプリは親クラスの にLAUNCHステップインする必要があります。onResume()資格情報がまだ保存されていないことがわかりAppFragmentActivity、ログインのレイアウトが開きます。入力すると、ユーザーは にリダイレクトされ、SearchActivity「OK クレデンシャルがあります。先に進みましょう」と表示されます。しかし、ログインが表示されないため、これは起こりません。だから私はonResume()間違っているかもしれないと思います。おそらく私の完全な考えは悪いですか?ここまではライフサイクルも分かっているつもりだったが、やっぱり分からない?

次に、同様の問題についてSOを調べました。ここで見たのは、私のものと同様の「ログアウト」メカニズムを構築したいユーザーへのコメントで、すべてのアクティビティでこれを実装する必要があるというものでした。onResume()私はそれについて考え、「すべて同じ親からのものであるのに、なぜすべてのアクティビティをオーバーライドする必要があるのですか?子にない場合、親のアクティビティを呼び出す必要があります」と自問しonResume()ました。SO の質問のユーザーは、サービスをバックグラウンド スレッドとして使用して、ログアウトのためにそこにあるタイマーをカウントダウンするようにアドバイスされました。次に、ドキュメントのサービスの記事を読んだ後、完全に混乱しました。

サービスには、開始済みサービスと制限付きサービスの 2 種類があります。開始されたサービスは、アクティビティによって開始された後、停止されないときに地獄がフリーズするまでバックグラウンドで実行されます。したがって、どのアプリからも完全に独立していますが、プログラマーは、不要になったときに停止する必要があります。バインドされたサービスは、1 つまたは複数のアプリ コンポーネントにバインドされ、バインドされたすべてのコンポーネントが終了すると停止します。私はこれが私にとって良い代替手段かもしれないと思っていましたが、さらに考えたとき、どのように自問しましたか: 私の1つがそれを開始し(ログインダイアログとしましょう)、その後閉じられた場合、サービスは停止し、他のアクティビティは常にそこから開始されますそれの感覚になれないもの。したがって、このサービスはコンポーネントではなく、私のアプリにバインドする必要があります。しかし、Android アプリのライフサイクルは何ですか? 情報を「グローバル」に保つにはどうすればよいですか 私のアプリ内。「インテント」を使用してアクティビティ間でデータを切り替えることができることを知っています。

このますます多くの「霧の雲」は、「アクティビティを 1 つだけ使用し、フラグメントを使用してすべてを切り替えようとするか?」

私の質問は次のとおりです(これですべてだと思いますが、もうわかりません):

  • すべての拡張された子のチェックを行う親クラスを作成するという私の考えは大丈夫ですか、それとも私が理解したとおりに機能しますか?
  • onResume()チェックのために親を呼び出すためだけに、子のすべてをオーバーライドする必要がありますか?
  • 「ログイン システム」が機能しない理由を教えてください。
  • Android アプリのライフサイクルとはどのようなもので、どのように操作できますか?
  • 1 つのアクティビティのみを使用し、フラグメントを使用してすべてを切り替えるか、または複数のアクティビティを使用し、そのうちのいくつかでフラグメントを使用する (頻繁に使用される部分を再利用する) のは良い方法ですか?

アドバイスありがとう

4

1 に答える 1

0

私が最終的にやったことは次のとおりです。

親クラスから「ログイン」を削除して、スタンドアロンのアクティビティにしました。このアクティビティは、認証情報が呼び出し元の認証情報と一緒に有効でない場合にfinish()呼び出されます。そのため、ループを作成して未使用のアクティビティを削除することはありません。

于 2013-08-13T18:20:49.967 に答える