我知道同样的问题是here,已经有人提出问题并且有答案,但我对此答案有疑问。
我的要求是,我想确定用户是否处于非活动状态5分钟,然后用户从应用程序中自动注销并上传登录并注销服务器上的日志。
我已尝试过上述链接中的所有答案,但该答案适用于单项活动,但我想跟踪多项活动。
为此我创建了抽象类
public abstract class SessionTimeOutActivity extends BaseActivity {
public static final long DISCONNECT_TIMEOUT = 1000 * 60; // 5 min = 5 * 60 * 1000 ms
private static Handler disconnectHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
Log.d("SessionTimeOutActivity", "disconnectHandler");
return false;
}
});
private Runnable disconnectCallback = new Runnable() {
@Override
public void run() {
// Perform any required operation on disconnect
Log.d("SessionTimeOutActivity", "disconnectCallback");
Toast.makeText(getApplicationContext(), "Session time out", Toast.LENGTH_LONG).show();
Intent intent = new Intent(getApplicationContext(), LoginActivity.class);
startActivity(intent);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
finish();
}
};
public void resetDisconnectTimer() {
disconnectHandler.removeCallbacks(disconnectCallback);
disconnectHandler.postDelayed(disconnectCallback, DISCONNECT_TIMEOUT);
}
public void stopDisconnectTimer() {
disconnectHandler.removeCallbacks(disconnectCallback);
}
@Override
public void onUserInteraction() {
Log.d("SessionTimeOutActivity", "onUserInteraction");
resetDisconnectTimer();
}
@Override
public void onResume() {
super.onResume();
// resetDisconnectTimer();
}
@Override
public void onStop() {
super.onStop();
// stopDisconnectTimer();
}
}
app中的其他活动
public class MenuActivtyNav extends SessionTimeOutActivity{
.....
}
MenuActivity
public class MenuActivty extends SessionTimeOutActivity{
....
}
问题
1)在锁定屏幕中自动注销不起作用,它不调用disconnectCallback
2)使用app时,它会显示toast消息“Session time out”
答案 0 :(得分:6)
让我们首先了解您的代码没有按照您的意愿行事的原因。
问题1。您应该避免在Android上的活动中长时间运行任务,尤其是当它们不可见时,因为系统可能会终止您的活动或应用程序进程,因此代码将无法运行
问题2。每个活动都会将disconnect
回调发布到您的处理程序,如果用户与第二个活动进行交互,则第一个活动的回调将不会重置并触发。
<强>解。强>
现在让我们考虑解决这个问题的方法。 最好有一个地方来跟踪不活动。它可以是单例,也可以使用应用程序对象。 并分别处理2个案例:第一个是你的用户在应用程序内并且没有使用它而另一个是你的用户不在应用程序时。
对于第一个目标,您可以采用与当前目标类似的方法,但在应用程序中创建共享disconnectCallback
。将处理程序,回调和重置回调逻辑移动到Application类并生成
@Override
public void onUserInteraction()
在应用程序上调用resetCallback
。这将使所有活动使用相同的回调并解决问题2.
对于第二个目标,您可以使用Activity Lifecycle Callbacks。 每次暂停活动时都会保存时间戳。然后,每次恢复活动时,将此时间戳与恢复时间进行比较,如果大于5分钟,则注销用户并路由到登录屏幕。它将解决问题1.您需要保留此时间戳,因为应用程序可能被系统杀死,并且内存中共享的所有内容都将被删除。例如,使用共享首选项。
最后一件事,当应用程序进入后台时,您需要取消回调。你可以在你的活动回调的onActivityPaused(Activity activity)
中,在你将触发第二种情况的逻辑的同一地方。
答案 1 :(得分:1)
即使您可以在使用this answer进行一些努力后管理您的要求。
但我正在考虑一些Timer和Handlers免费解决方案。我已经有了很好的管理计时器解决方案。但我已经成功实现了Timer和Handler免费解决方案。
首先,如果您使用计时器或处理程序,我会告诉您您需要管理的内容。
最后我实施了一个
的解决方案ACTION_SCREEN_ON
/ ACTION_SCREEN_OFF
广播接收器。 <强>解决方案强>
我们不会通过计时器观察用户不活动,而是检查用户活动的最后活动时间。因此,当用户下次交互应用时,我会检查上次交互时间。
以下是BaseActivity.class
,您将从每个活动类而不是LoginActivity
进行扩展。
import android.content.Intent;
import android.content.SharedPreferences;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;
public class BaseActivity extends AppCompatActivity {
public static final long TIMEOUT_IN_MILLI = 1000 * 20;
public static final String PREF_FILE = "App_Pref";
public static final String KEY_SP_LAST_INTERACTION_TIME = "KEY_SP_LAST_INTERACTION_TIME";
@Override
public void onUserInteraction() {
super.onUserInteraction();
if (isValidLogin())
getSharedPreference().edit().putLong(KEY_SP_LAST_INTERACTION_TIME, System.currentTimeMillis()).apply();
else logout();
}
public SharedPreferences getSharedPreference() {
return getSharedPreferences(PREF_FILE, MODE_PRIVATE);
}
public boolean isValidLogin() {
long last_edit_time = getSharedPreference().getLong(KEY_SP_LAST_INTERACTION_TIME, 0);
return last_edit_time == 0 || System.currentTimeMillis() - last_edit_time < TIMEOUT_IN_MILLI;
}
public void logout() {
Intent intent = new Intent(this, LoginActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
Toast.makeText(this, "User logout due to inactivity", Toast.LENGTH_SHORT).show();
getSharedPreference().edit().remove(KEY_SP_LAST_INTERACTION_TIME).apply(); // make shared preference null.
}
}