【问题标题】:Timer does not stop at old activity计时器不会在旧活动处停止
【发布时间】:2016-08-24 04:17:05
【问题描述】:

我在AccountActivity.class 上设置了一个计时器,以确保用户不会按主页按钮,否则将开始倒计时以注销用户或用户锁定他的屏幕。

但是由于onPause 方法,我现在面临一个问题。当我的用户单击调用getaccounttask() 方法的按钮并将我的用户重定向到AccountInformationActivity.class 时,onPause 方法也被激活并且计时器开始倒计时。

是否有任何解决方案可以防止onPause 方法倒计时或取消我的AccountInformationActivity.class 上的计时器?

我试图在我的意图开始之前取消计时器,但仍然不起作用。

我也尝试过使用处理程序,但遇到了同样的问题,我仍在尝试了解 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();
        }
    }
}

【问题讨论】:

    标签: android android-timer


    【解决方案1】:

    嗯,您选择的实现架构可以改进。我稍后会谈到这一点。首先应用此快速修复来修复您的架构。

    很明显,当您使用主屏幕离开Activity 时,您想启动Timer。但用户也可以退出Activity,使用Intent切换到AccountActivity。这个你可以追踪。所以保留一个像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();
            }
        }
    }
    

    现在更好的方法是保留 ServiceSingleton 类。 Singleton 类将是

    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;
    
    }
    

    现在每个活动都会有一个标签(就像它的名字一样),所以每个活动在恢复时都会这样做

    Singleton.getInstance().activityMap.put(tag, this);
    

    什么时候去onPause就行了

    Singleton.getInstance().activityMap.remove(tag, this);
    

    因此,当服务发现 Singleton.getInstance().activityMap 的大小为零时,显然前台没有任何活动,因此它启动了一个计时器。当计时器到期时再次检查计数是否仍然为零,如果为零则执行注销。

    【讨论】:

    • 嗨,我也尝试过处理程序,但我遇到了同样的问题。对于 shouldNavigate 的跟踪部分,我仍然不太确定,因为我还是 Android 和 Java 的新手,如果你能提供一些代码,那将是很棒的,对我理解有很大帮助
    • 请检查编辑,当然根据您的需要进行修复。
    • 天啊..终于成功了!非常感谢!我已经在这个问题上停留了几个星期!再次感谢您所做的一切!
    【解决方案2】:

    我认为您在 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
        }
    

    希望这会有所帮助!

    【讨论】:

    • 嗨,但是(如果我错了,请纠正我)onPause 仅在我将启动计时器的活动(例如我按下主页按钮)作为背景时启动。当我回到活动时 onResume 不是吗?当用户已经在活动中时,为什么要开始倒计时?如果用户不再在我的应用程序中并且用户忘记注销,我正在尝试实现类似超时。
    • onResume() 在屏幕启动或重新启动屏幕时调用。当您按下主页按钮并且应用程序未完全关闭时的示例。再次启动应用后,会触发到 onResume() 反之,onPause() 视为关闭状态,表示关闭屏幕或启动新屏幕时。
    • 是的,但是当用户在应用程序中时,为什么要调用倒计时呢?当用户在屏幕上时?如果是这种情况,那么用户在该特定屏幕上只有 5 分钟的时间,如果用户按下主页按钮,它将永远不会注销用户。因为我正在尝试实现当用户按下主页按钮并忘记从应用程序注销时,超时任务将为用户注销。
    • 也许我不确定你的目标。但你提到“我试图在我的意图开始之前取消计时器但仍然不起作用”你的意思是,你想在开始新屏幕之前停止计时器吗?
    • 是的,因为我的用户要去一个新的活动,但计时器仍然从我的旧活动开始倒计时,这导致我的用户在新活动上处于活动状态时被注销。跨度>
    【解决方案3】:

    onPause()中进行一些修改并添加此权限

    &lt;uses-permission android:name="android.permission.GET_TASKS" /&gt;

        @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;
        }
    

    【讨论】:

    • 你试试这个。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-05
    • 1970-01-01
    • 2014-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多