在周末,我开始构建我的第一个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
,它现在显示“确定的凭据在那里,让我们继续前进”。但这不会发生,因为未显示登录名。所以我认为我的onResume()
可能是错误的。也许我的主意不好?到目前为止,我以为我也了解生命周期,但是显然我不明白吗?然后,我对类似问题进行了四处浏览。我在这里看到的一件事是给一个用户的注释,该用户想要建立一个与我的类似的“注销”机制,他必须在每个活动中都实施此机制。我考虑了一下,问自己:“为什么我的每项活动都来自同一个父母,所以我必须在每项活动中都覆盖
onResume()
?当孩子中没有onResume()
时,父母中的一个应该是称为”。建议SO问题中的用户将服务用作后台线程,以在其中倒数计时器进行注销。然后,我在文档中阅读了服务文章,然后完全迷失了方向:服务有两种类型:启动服务和有界服务。一个启动的服务由一个活动启动,然后在后台运行,直到不停止时地狱冻结。因此,它完全独立于任何应用程序,但是程序员必须/不再需要它时,应停止它。有界服务绑定到一个或多个应用程序组件,并在所有有界组件结束时停止。我认为这对我来说可能是一个不错的选择,但是当我进一步思考时,我问自己:如果我的一个启动了它(例如登录对话框),然后关闭了该服务,而其他活动总是在那里启动不可能的感觉。因此,此服务必须不限于任何组件,而应限于我的应用程序。但是,Android应用程序的生命周期如何?如何在我的应用程序中保持信息“全局”。我知道我可以使用“意图”在活动之间切换数据。
这种越来越多的“雾云”使我问自己:“我应该只使用一个活动,并尝试使用片段来切换所有输入/输出吗?”
所以我的问题是(我想所有的问题,但是我不确定)。
我写父类的想法对所有扩展子代都进行检查是好是坏,并且按我的理解可以正常工作吗?
我是否必须重写子项中的每个
onResume()
以便仅调用父项进行检查?您能给我一个提示,为什么我的“登录系统”不起作用吗?
什么是Android应用程序的生命周期,我如何与之交互?
我应该只使用一个活动,并使用片段来切入/切出所有内容,还是进行多个活动,其中一些活动使用片段(重用经常使用的部件)是一种好方法?
感谢您的建议
最佳答案
最后我要做的是:
我从父类中删除了“登录”内容,成为一个独立的活动。当凭据与调用方的finish()
一起无效时,将调用此活动。因此,我不会建立循环并丢弃未使用的活动。
关于java - Android:登出系统和android生命周期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18189009/