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);.

然后我创建的另外两个活动正在扩展这个父类。这是其中之一:

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 问题中的用户使用服务作为后台线程来倒计时那里的注销。然后我阅读了文档中的服务文章,然后完全迷失了方向:

有两种类型的服务:已启动的和有界的。一个启动的服务一旦由一个活动启动,然后在后台运行,直到它没有停止时地狱冻结。所以它完全独立于任何应用程序,但程序员必须/应该在不再需要它时停止它。有界服务绑定到一个或多个应用程序组件,并在所有有界组件结束时停止。我认为这对我来说可能是一个不错的选择,但是当我进一步思考时,我问自己如何:如果我的一个启动它(比如说登录对话框)然后关闭,则服务停止并且其他活动总是从那里开始那些不可能是它的感觉。所以这个服务必须不是绑定到任何组件,而是绑定到我的应用程序。但安卓应用程序的生命周期是什么?如何保持信息“全球” 在我的应用程序中。我知道我可以使用“意图”在活动之间切换数据。

这越来越多的“雾云”导致我问自己:“我应该只使用一个活动并尝试使用片段来切换所有内容吗?”

所以我的问题是(我认为这就是全部,但我不确定了):

  • 我的想法是编写一个父类来检查所有扩展孩子的好坏,并且它是否像我理解的那样工作?
  • 我是否必须覆盖onResume()孩子中的每一个才能打电话给父母进行检查?
  • 你能告诉我为什么我的“登录系统”不起作用吗?
  • android 应用程序的生命周期是什么,我如何与之交互?
  • 我应该只使用一个活动并使用片段切换所有内容,还是有几个活动并且其中一些使用片段(重用经常使用的部分)是一种好方法?

谢谢指教

4

1 回答 1

0

我最终所做的如下:

我从父类中删除了“登录”的东西到一个独立的活动中。当凭据与调用的凭据一起无效时,finish()将调用此活动。所以我不会建立循环并丢弃未使用的活动。

于 2013-08-13T18:20:49.967 回答