安卓。如何在应用程序关闭后保存用户名和密码?

5
我正在编写一个涉及登录详情(用户名和密码)的应用程序。
我希望当用户关闭应用程序并在以后重新启动时,不必再次输入用户名和密码。

这是我的代码。不幸的是,它似乎无法记住密码和用户名:

protected void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_login);

    mPrefs = getSharedPreferences(PREFS, 0);
    final CheckBox rememberMeCbx = (CheckBox)findViewById(R.id.saveLoginCheckBox);

    boolean rememberMe = mPrefs.getBoolean("rememberMe", false);



    if (android.os.Build.VERSION.SDK_INT > 9)
    {
        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
        StrictMode.setThreadPolicy(policy);
    }
    mXmlRpcClient = new XMLRPCClient(mXmlRpcUri);

    // Set up the login form.
    //mUsername = getIntent().getStringExtra(EXTRA_EMAIL);
    mUsernameView = (EditText) findViewById(R.id.username);
    mUsernameView.setText(mUsername);

    mPasswordView = (EditText) findViewById(R.id.password);
    mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
                @Override
                public boolean onEditorAction(TextView textView, int id,
                        KeyEvent keyEvent) {
                    if (id == R.id.login || id == EditorInfo.IME_NULL) {
                        attemptLogin();
                        return true;
                    }
                    return false;
                }
            });

    mLoginFormView = findViewById(R.id.login_form);
    mLoginStatusView = findViewById(R.id.login_status);
    mLoginStatusMessageView = (TextView) findViewById(R.id.login_status_message);

    findViewById(R.id.sign_in_button).setOnClickListener
    (
            new View.OnClickListener()
            {
                @Override
                public void onClick(View view) 
                {
                    if(rememberMeCbx.isChecked())
                    {
                        attemptLogin(); //function to check if fields are filled correctly
                        saveLoginDetails();
                    }
                    else
                    {
                        attemptLogin();
                        removeLoginDetails();
                    }

                }
            });

    if(rememberMe == true)
    {
        //get previously stored login details
        String login = mPrefs.getString("mUsername", null);
        String upass = mPrefs.getString("mPassword", null);

        if(login != null && upass != null)
        {
            //fill input boxes with stored login and pass
            EditText loginEbx = (EditText)findViewById(R.id.username);
            EditText passEbx = (EditText)findViewById(R.id.password);
            loginEbx.setText(login);
            passEbx.setText(upass);

            //set the check box to 'checked'                
            rememberMeCbx.setChecked(true);
        }
    }
}



/**
 * Represents an asynchronous login/registration task used to authenticate
 * the user.
 */
public class UserLoginTask extends AsyncTask<Void, Void, Boolean> {
    @Override
    protected Boolean doInBackground(Void... params) {
        try {
            mSessionID = (String)mXmlRpcClient.call(mLoginFuncName, mUsername, mPassword);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    @Override
    protected void onPostExecute(final Boolean success) {
        mAuthTask = null;
        showProgress(false);

        if (success) {
            finish();
            Intent intent = new Intent(LoginActivity.this, MainWindow.class);
            intent.putExtra("SessionID", mSessionID);
            intent.putExtra("XmlRpcUrl", mXmlRpcUrl);
            intent.putExtra("LoginFuncName", mLoginFuncName);
            intent.putExtra("LogoutFuncName", mLogoutFuncName);
            intent.putExtra("GetDevicesFuncName", mGetDevicesFuncName);
            intent.putExtra("SendPositionFuncName", mSendPositionFuncName);
            intent.putExtra("GetSavedTripFunc", mGetSavedTripFunc);             
            startActivity(intent);
        } else {
            mPasswordView
                    .setError(getString(R.string.error_incorrect_password));
            mPasswordView.requestFocus();
        }
    }


}

private void saveLoginDetails()
{
    //fill input boxes with stored login and pass
    EditText loginEbx = (EditText)findViewById(R.id.username);
    EditText passEbx = (EditText)findViewById(R.id.password);
    String login = loginEbx.getText().toString();
    String upass = passEbx.getText().toString();

    Editor e = mPrefs.edit();
    e.putBoolean("rememberMe", true);
    e.putString("login", login);
    e.putString("password", upass);
    e.commit();
}

private void removeLoginDetails()
{
    Editor e = mPrefs.edit();
    e.putBoolean("rememberMe", false);
    e.remove("login");
    e.remove("password");
    e.commit();
}

请问,我代码有什么问题?我该如何改进它,以便在应用程序关闭并再次打开后保存和检索用户名和密码?


在活动onPause()中保存Preference中的数据,并在活动onResume()中加载该数据。 - M D
那么你的意思是我应该把我的saveLoginDetails()方法放在onPause()中,而将“if(rememberMe == true)”检查放在onResume()中吗? - user3182266
你应该从checkBox的onCheckedChangeListener中获取remember me的值,并且为了保存和获取登录信息,你应该使用SharedPreferences。请参考这个教程来学习如何从preferences中保存/检索数据:http://www.android-ios-tutorials.com/54/android-shared-preferences-tutorial/。 - Houcine
3个回答

15

尝试这种方式:首先定义Preferences

private static final String PREFS_NAME = "preferences";
private static final String PREF_UNAME = "Username";
private static final String PREF_PASSWORD = "Password";

private final String DefaultUnameValue = "";
private String UnameValue;

private final String DefaultPasswordValue = "";
private String PasswordValue;

onPause()

@Override
public void onPause() {
    super.onPause();
    savePreferences();

}

并且onResume()

@Override
public void onResume() {
    super.onResume();
    loadPreferences();
     }

在这里使用savePreferences()

private void savePreferences() {
    SharedPreferences settings = getSharedPreferences(PREFS_NAME,
            Context.MODE_PRIVATE);
    SharedPreferences.Editor editor = settings.edit();

    // Edit and commit
    UnameValue = edt_username.getText();
    PasswordValue = edt_password.getText();
    System.out.println("onPause save name: " + UnameValue);
    System.out.println("onPause save password: " + PasswordValue);
    editor.putString(PREF_UNAME, UnameValue);
    editor.putString(PREF_PASSWORD, PasswordValue);
    editor.commit();
}

并且这里有loadPreferences()

private void loadPreferences() {

    SharedPreferences settings = getSharedPreferences(PREFS_NAME,
            Context.MODE_PRIVATE);

    // Get value
    UnameValue = settings.getString(PREF_UNAME, DefaultUnameValue);
    PasswordValue = settings.getString(PREF_PASSWORD, DefaultPasswordValue);
    edt_username.setText(UnameValue);
    edt_password.setText(PasswordValue);
    System.out.println("onResume load name: " + UnameValue);
    System.out.println("onResume load password: " + PasswordValue);
}

这看起来很有前途,但我有一个复选框,所以我想在复选框被选中时保存细节,而不是在未选中时保存。 - user3182266
@user3182266 分享的偏好设置是通行的方法。 - Raghunandan
@user3182266,那么您需要存储支票簿状态并加载它以进行检查。就是这样。 - M D
3
建议在存储密码等数据时使用MODE_PRIVATE。同时,在使用返回字符串的getString()方法后,无需再使用.toString()方法 :) - localhost
3
如果您在共享首选项文件中保存信息,但您的手机已被root,那么这些文件将会被访问。如果您没有服务器并且可以采用访问令牌方法,在将其放入共享首选项之前,请至少使用加密方法来存储访问令牌以识别用户。请查看https://androidluckyguys.wordpress.com/2017/09/12/android-data-security-aes-and-rsa-encryption-and-decryption/,并研究该主题。账户管理器也并非100%安全。 - T.Dimitrov
显示剩余4条评论

1
我不建议使用你的逻辑!我建议你使用AccountManager API来验证和存储用户凭据,或编写自己的帐户管理器。始终使用AccountManager,它仅存储您的身份验证令牌。

帐户管理器的数据也可以通过root访问!

对于你的逻辑,至少尝试以安全的方式使用SharedPreferences,否则通过root访问我们可以从移动设备中获取SharedPreferences数据!

1
你如何去实现这个功能? - Paradox
使用scottyab:secure-preferences或搜索如何使用自定义Google账户管理器逻辑,有许多示例可用! - LOG_TAG
1
LOG_TAG 账户管理器的数据也可以通过 root 访问,这是不安全的。您需要使用加密。 - T.Dimitrov
1
@T.Dimitrov非常正确!现在有基于Room的共享首选项,支持加密和缓存,性能更好! - LOG_TAG

0

目前为止,我认为你的代码是正确的,但你不知道在哪里实现它。

因此,在您的登录成功并且您想要在应用程序中打开另一个Activity的某个点上,您必须调用一个Intent

因此,当您在成功登录时触发Intent时,您可以像这样调用您的saveLoginDetails()方法。

if(*successful login condition*){
    Intent intent=new Intent(CurrentActivity.this,NextActivity.class);
    saveLoginDetails();
    startActivity(intent);
}

每当用户注销时,您可以实现removeLoginDetails()方法。

希望能有所帮助...干杯...:)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接