计时器不会停在旧 activity
Timer does not stop at old activity
我在 AccountActivity.class
上设置了一个计时器,以确保用户不按主页按钮,否则将开始倒计时以注销用户或用户锁定屏幕。
但现在由于 onPause
方法,我遇到了一个问题。当我的用户单击调用 getaccounttask()
方法的按钮并将我的用户重定向到 AccountInformationActivity.class
时,onPause
方法也被激活并且计时器开始倒计时。
有什么解决方案可以防止 onPause
方法在我的 AccountInformationActivity.class
上倒计时或取消计时器吗?
我尝试在 intent 开始之前取消计时器,但仍然无效。
我也尝试过使用处理程序,但遇到了同样的问题,我仍在努力掌握 Android 的完整工作原理,因此非常感谢您的帮助或解决方案。
public class AccountActivity extends AppCompatActivity {
private Timer timer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_account);
}
private class getaccounttask extends AsyncTask<String, Void, String>
{
@Override
protected String doInBackground(String... urlaccount)
{
StringBuilder result = new StringBuilder();
try
{
//My Codes
}
catch (Exception e)
{
e.printStackTrace();
}
return result.toString();
}
@Override
protected void onPostExecute(String result)
{
Intent intent = new Intent();
intent.setClass(getApplicationContext(), AccountInformationActivity.class);
startActivity(intent);
}
}
@Override
protected void onPause() {
super.onPause();
timer = new Timer();
Log.i("Main", "Invoking logout timer");
LogOutTimerTask logoutTimeTask = new LogOutTimerTask();
timer.schedule(logoutTimeTask, 300000); //auto logout in 5 minutes
}
@Override
protected void onResume() {
super.onResume();
if (timer != null) {
timer.cancel();
Log.i("Main", "cancel timer");
timer = null;
}
}
private class LogOutTimerTask extends TimerTask {
@Override
public void run() {
//redirect user to login screen
Intent i = new Intent(AccountActivity.this, MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
finish();
}
}
}
我认为您混淆了 Activity 生命周期中的 onPause() 和 onResume()。
对于您的情况,您可以将在 onPause() 中执行的操作切换到 onResume()
@Override
protected void onPause() {
super.onPause();
if (timer != null) {
timer.cancel();
Log.i("Main", "cancel timer");
timer = null;
}
}
@Override
protected void onResume() {
super.onResume();
timer = new Timer();
Log.i("Main", "Invoking logout timer");
LogOutTimerTask logoutTimeTask = new LogOutTimerTask();
timer.schedule(logoutTimeTask, 300000); //auto logout in 5 minutes
}
希望这会有所帮助!
嗯,您选择的实现架构可以改进。我稍后会谈到这一点。首先应用此快速修复来修复您的体系结构。
显然您想在离开 Activity
时使用主屏幕启动 Timer
。但用户也可以通过使用Intent
切换到AccountActivity
来退出Activity
。这个你可以追踪。所以保留一个像 shouldNavigate
这样的布尔标志,最初它应该是 false
。当onResume
时,应设置为false
,但当getcounttask
变为onPostExecute
时,应设置为true
。所以在 onPause
中,如果你要通过 getcounttask
出门,shouldNavigate
将是 true
,如果是 true
,请取消你的定时器,否则,开始你的Timer
.
代码:
public class AccountActivity extends AppCompatActivity {
private Timer timer;
private volatile boolean shouldNavigate = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_account);
}
private class getaccounttask extends AsyncTask<String, Void, String>
{
@Override
protected String doInBackground(String... urlaccount)
{
StringBuilder result = new StringBuilder();
try
{
//My Codes
}
catch (Exception e)
{
e.printStackTrace();
}
return result.toString();
}
@Override
protected void onPostExecute(String result)
{
shouldNavigate = true;
Intent intent = new Intent();
intent.setClass(getApplicationContext(), AccountInformationActivity.class);
startActivity(intent);
}
}
@Override
protected void onPause() {
super.onPause();
if (!shouldNavigate){
timer = new Timer();
Log.i("Main", "Invoking logout timer");
LogOutTimerTask logoutTimeTask = new LogOutTimerTask();
timer.schedule(logoutTimeTask, 300000);
}else{
if (timer != null){
timer.cancel();
timer = null;
}
}
}
@Override
protected void onResume() {
super.onResume();
shouldNavigate = false;
if (timer != null) {
timer.cancel();
Log.i("Main", "cancel timer");
timer = null;
}
}
private class LogOutTimerTask extends TimerTask {
@Override
public void run() {
//redirect user to login screen
shouldNavigate = false;
Intent i = new Intent(AccountActivity.this, MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
finish();
}
}
}
现在更好的方法是保留 Service
和 Singleton
class。
单例 class 将是
public Singleton{
private static Singleton instance = null;
private Singleton(){
activityMap = new HashMap<String, Activity>();
}
public static Singleton getInstance(){
if (instance == null) instance = new Singeton();
return instance;
}
public HashMap<String, Activity> activityMap;
}
现在每个 activity 都会有一个标签(就像它的名字一样),所以每个 activity 的简历都可以
Singleton.getInstance().activityMap.put(tag, this);
然后去 onPause
就可以了
Singleton.getInstance().activityMap.remove(tag, this);
因此,当服务发现 Singleton.getInstance().activityMap
的大小为零时,显然没有 activity 在前台,因此它会启动一个计时器。当计时器到期时再次检查计数是否仍为零,如果为零则执行注销。
在onPause()
中进行一些修改并添加此权限
<uses-permission android:name="android.permission.GET_TASKS" />
@Override
protected void onPause() {
if (isApplicationSentToBackground(this)) {
// Do what you want to do on detecting Home Key being Pressed
timer = new Timer();
Log.i("Main", "Invoking logout timer");
LogOutTimerTask logoutTimeTask = new LogOutTimerTask();
timer.schedule(logoutTimeTask, 300000); //auto logout in 5 minutes
Log.i("Main", "Invoking Home Key pressed");
}
super.onPause();
}
public boolean isApplicationSentToBackground(final Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
if (!topActivity.getPackageName().equals(context.getPackageName())) {
return true;
}
}
return false;
}
我在 AccountActivity.class
上设置了一个计时器,以确保用户不按主页按钮,否则将开始倒计时以注销用户或用户锁定屏幕。
但现在由于 onPause
方法,我遇到了一个问题。当我的用户单击调用 getaccounttask()
方法的按钮并将我的用户重定向到 AccountInformationActivity.class
时,onPause
方法也被激活并且计时器开始倒计时。
有什么解决方案可以防止 onPause
方法在我的 AccountInformationActivity.class
上倒计时或取消计时器吗?
我尝试在 intent 开始之前取消计时器,但仍然无效。
我也尝试过使用处理程序,但遇到了同样的问题,我仍在努力掌握 Android 的完整工作原理,因此非常感谢您的帮助或解决方案。
public class AccountActivity extends AppCompatActivity {
private Timer timer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_account);
}
private class getaccounttask extends AsyncTask<String, Void, String>
{
@Override
protected String doInBackground(String... urlaccount)
{
StringBuilder result = new StringBuilder();
try
{
//My Codes
}
catch (Exception e)
{
e.printStackTrace();
}
return result.toString();
}
@Override
protected void onPostExecute(String result)
{
Intent intent = new Intent();
intent.setClass(getApplicationContext(), AccountInformationActivity.class);
startActivity(intent);
}
}
@Override
protected void onPause() {
super.onPause();
timer = new Timer();
Log.i("Main", "Invoking logout timer");
LogOutTimerTask logoutTimeTask = new LogOutTimerTask();
timer.schedule(logoutTimeTask, 300000); //auto logout in 5 minutes
}
@Override
protected void onResume() {
super.onResume();
if (timer != null) {
timer.cancel();
Log.i("Main", "cancel timer");
timer = null;
}
}
private class LogOutTimerTask extends TimerTask {
@Override
public void run() {
//redirect user to login screen
Intent i = new Intent(AccountActivity.this, MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
finish();
}
}
}
我认为您混淆了 Activity 生命周期中的 onPause() 和 onResume()。
对于您的情况,您可以将在 onPause() 中执行的操作切换到 onResume()
@Override
protected void onPause() {
super.onPause();
if (timer != null) {
timer.cancel();
Log.i("Main", "cancel timer");
timer = null;
}
}
@Override
protected void onResume() {
super.onResume();
timer = new Timer();
Log.i("Main", "Invoking logout timer");
LogOutTimerTask logoutTimeTask = new LogOutTimerTask();
timer.schedule(logoutTimeTask, 300000); //auto logout in 5 minutes
}
希望这会有所帮助!
嗯,您选择的实现架构可以改进。我稍后会谈到这一点。首先应用此快速修复来修复您的体系结构。
显然您想在离开 Activity
时使用主屏幕启动 Timer
。但用户也可以通过使用Intent
切换到AccountActivity
来退出Activity
。这个你可以追踪。所以保留一个像 shouldNavigate
这样的布尔标志,最初它应该是 false
。当onResume
时,应设置为false
,但当getcounttask
变为onPostExecute
时,应设置为true
。所以在 onPause
中,如果你要通过 getcounttask
出门,shouldNavigate
将是 true
,如果是 true
,请取消你的定时器,否则,开始你的Timer
.
代码:
public class AccountActivity extends AppCompatActivity {
private Timer timer;
private volatile boolean shouldNavigate = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_account);
}
private class getaccounttask extends AsyncTask<String, Void, String>
{
@Override
protected String doInBackground(String... urlaccount)
{
StringBuilder result = new StringBuilder();
try
{
//My Codes
}
catch (Exception e)
{
e.printStackTrace();
}
return result.toString();
}
@Override
protected void onPostExecute(String result)
{
shouldNavigate = true;
Intent intent = new Intent();
intent.setClass(getApplicationContext(), AccountInformationActivity.class);
startActivity(intent);
}
}
@Override
protected void onPause() {
super.onPause();
if (!shouldNavigate){
timer = new Timer();
Log.i("Main", "Invoking logout timer");
LogOutTimerTask logoutTimeTask = new LogOutTimerTask();
timer.schedule(logoutTimeTask, 300000);
}else{
if (timer != null){
timer.cancel();
timer = null;
}
}
}
@Override
protected void onResume() {
super.onResume();
shouldNavigate = false;
if (timer != null) {
timer.cancel();
Log.i("Main", "cancel timer");
timer = null;
}
}
private class LogOutTimerTask extends TimerTask {
@Override
public void run() {
//redirect user to login screen
shouldNavigate = false;
Intent i = new Intent(AccountActivity.this, MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
finish();
}
}
}
现在更好的方法是保留 Service
和 Singleton
class。
单例 class 将是
public Singleton{
private static Singleton instance = null;
private Singleton(){
activityMap = new HashMap<String, Activity>();
}
public static Singleton getInstance(){
if (instance == null) instance = new Singeton();
return instance;
}
public HashMap<String, Activity> activityMap;
}
现在每个 activity 都会有一个标签(就像它的名字一样),所以每个 activity 的简历都可以
Singleton.getInstance().activityMap.put(tag, this);
然后去 onPause
就可以了
Singleton.getInstance().activityMap.remove(tag, this);
因此,当服务发现 Singleton.getInstance().activityMap
的大小为零时,显然没有 activity 在前台,因此它会启动一个计时器。当计时器到期时再次检查计数是否仍为零,如果为零则执行注销。
在onPause()
中进行一些修改并添加此权限
<uses-permission android:name="android.permission.GET_TASKS" />
@Override
protected void onPause() {
if (isApplicationSentToBackground(this)) {
// Do what you want to do on detecting Home Key being Pressed
timer = new Timer();
Log.i("Main", "Invoking logout timer");
LogOutTimerTask logoutTimeTask = new LogOutTimerTask();
timer.schedule(logoutTimeTask, 300000); //auto logout in 5 minutes
Log.i("Main", "Invoking Home Key pressed");
}
super.onPause();
}
public boolean isApplicationSentToBackground(final Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
if (!topActivity.getPackageName().equals(context.getPackageName())) {
return true;
}
}
return false;
}