【问题标题】:How do I detect if the user has left my app?如何检测用户是否离开了我的应用程序?
【发布时间】:2011-07-13 17:08:46
【问题描述】:

我正在开发一个 Android 应用程序,我想检测用户何时通过单击“返回”按钮或“主页”按钮退出我的应用程序。

此外,onInit() 之类的事件在我的场景中会很有用,因为我只想首先启动 MyInıt 操作。

在其他应用需要更多内存之前,不会调用onDestroy()

【问题讨论】:

  • 进一步 - onDestroy() 通常根本不被调用。通常系统只是在没有任何回调的情况下终止进程。

标签: android


【解决方案1】:

注意:这仅适用于您的目标 >= API14


您还可以使用 Application.registerActivityLifecycleCallbacks() 并在任何活动暂停时将延迟的Runnable(将在用户离开应用程序时调用)发布到Handler。当活动被创建/开始/恢复时,您从 Handler 中删除 Runnable。因此,当您在应用程序内部导航时,您总是会取消 Runnable,但如果激活了不是来自您的应用程序的另一个活动 - 将调用 Runnable

当用户离开我的应用程序时,我用它来注销用户,这里是回调代码:

public class MyApplication extends Application implements Application.ActivityLifecycleCallbacks {

    private Handler handler;
    private Runnable runLogout = new Runnable() {
        @Override
        public void run() {
            //logoutUser()
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();

        registerActivityLifecycleCallbacks(this);
        handler = new Handler(getMainLooper());
    }

    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        handler.removeCallbacks(runLogout);
    }

    @Override
    public void onActivityStarted(Activity activity) {
        handler.removeCallbacks(runLogout);
    }

    @Override
    public void onActivityResumed(Activity activity) {
        handler.removeCallbacks(runLogout);
    }

    @Override
    public void onActivityPaused(Activity activity) {
        handler.postDelayed(runLogout, 1000);
    }

    @Override
    public void onActivityStopped(Activity activity) {

    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {

    }

    @Override
    public void onActivityDestroyed(Activity activity) {

    }
}

但是,Runnable 不会在 Activity 生命周期的上下文中运行,因此要在 Activity 中使用它,您需要设置和检查一些应用程序范围的标志或广播意图。

【讨论】:

  • 我为这个问题找到的最佳解决方案。
  • 这个解决方案很棒,但是在 ChromeTabs 上引入后,它会像应用程序的一部分一样打开一个 chrome 实例,这个解决方案的行为就像应用程序被最小化一样,因为所有活动都显示为暂停,唯一恢复的活动是chrome 不属于您的应用程序,并且您没有收到 onActivityResumed() 的回调。有什么解决方法吗?
  • 但是当应用程序通过向右滑动关闭时这将不起作用?它不适合我
【解决方案2】:

如果您的活动是堆栈中的最后一个,那么使用 onKeyDown 检测后退按钮将解决 1/2 的问题

home 键有点棘手,没有绝对的方法,但你可以做这样的事情来满足我的简单需求。

onUserLeaveHint 根据文档在用户单击主页按钮时或当某事中断您的应用程序(如来电)时调用,因此您可以使用 onUserInteraction 方法来标记最后一次用户交互时间。

现在,如果这在 onUserLeaveHint 之前足够接近,您可以假设(不保证,但到目前为止对我有效)主页按钮是您的应用程序被推入后台(退出)的原因

不确定您捕捉主页按钮的意图是什么,无论如何,这是一种简单的方法,我在两个事件周围使用了一个 100 毫秒的栅栏,我发现这两个事件一直对我有用。注意:我只在少数手机上进行了测试,就像 Android 中的所有东西一样,你的里程会因操作系统/硬件而异(见鬼,即使是记录在案并应该工作的东西有时也没有)

long userInteractionTime = 0;

@Override
public void onUserInteraction() {
    userInteractionTime = System.currentTimeMillis();
    super.onUserInteraction();
    Log.i("appname","Interaction");
}

@Override
public void onUserLeaveHint() {
    long uiDelta = (System.currentTimeMillis() - userInteractionTime);

    super.onUserLeaveHint();
    Log.i("bThere","Last User Interaction = "+uiLag);
    if (uiDelta < 100)
        Log.i("appname","Home Key Pressed");    
    else
        Log.i("appname","We are leaving, but will probably be back shortly!");  
}

【讨论】:

  • onUserLeaveHint() 在来电将活动推到后台时不会被调用(至少在某些系统上)。事实上,从一个电话中,你可以按 HOME 并进入任何应用程序,onUserLeaveHint() 仍然不会被呼叫。
  • @Richard Le Mesurier 好吧,我不怀疑它在某些系统上的工作方式不同,但如果这是真的,那就是一个缺陷。欢迎来到 Android 碎片化的美妙世界 ;-)
  • @Sreedevi 的回答 (stackoverflow.com/a/7793412/383414) 中提到的文档来自Activity.onUserLeaveHint() (developer.android.com/reference/android/app/…) 的 Android 文档。该方法被设计成当有电话来电时不会被调用。(碎片化......让我们的 Android 开发人员继续工作。)
  • 总是说 Home Key Pressed,即使由于应用程序从通知栏启动而进入后台也是如此。无论如何都无法收到第二条消息。
  • @RichardLeMesurier 出于某种原因,每当我切换活动时都会调用onUserLeaveHint()。我该如何解决这个问题?
【解决方案3】:

onUserLeaveHint 是根据文档调用的,当 用户单击主页按钮或当某事打断您的 应用程序(如来电),以便猜测是您 使用 onUserInteraction 方法标记上一次用户交互 时间。

只是对 Idistic 给出的答案的一个小修正 - 当您的活动被来电中断时,调用 OnUserLeaveHint()。这是 Android 文档中的 sn-p -

在活动即将开始时作为活动生命周期的一部分调用 作为用户选择的结果进入后台。例如,当 用户按下 Home 键,onUserLeaveHint() 将被调用,但是 当来电导致通话中活动 自动带到前台,onUserLeaveHint() 不会 调用被中断的活动。

【讨论】:

  • 正确 - 我们正在尝试通过来电自动柜员机解决此问题。
【解决方案4】:

是的,检查应用程序的生命周期 - 当用户最小化或离开时调用了几个方法 暂停() 停止() 和 onDestroy()

http://developer.android.com/reference/android/app/Activity.html

【讨论】:

  • 这些是每个活动,但我指的是应用程序。
  • 我不认为 android 在每个应用程序的基础上都支持类似的东西 - 但是,请记住,任何应用程序都只是活动的集合。一种选择是为所有具有您想要的行为的个人活动课程。另一种选择可能是每个活动调用的通用类来进行清理。
  • 无法保证onDestroy() 会被调用,因为任务可以在onPause() 之后直接终止,因此永远不会到达onStop()。并且当用户按下主页按钮时,onDestroy() 不会自动调用。更糟糕的是,onStop() 会在您使用 home 键离开 Activity 以及开始另一个 Activity 时调用。
【解决方案5】:

Application.ActivityLifecycleCallbacks 的帮助下,您可以跟踪正在破坏的活动和正在启动的新活动,但是当用户滑动或返回按钮(在最后一个堆栈上)时,postdelayed 将不会调用,Activitystopdestroy如果您想捕捉用户滑动或后退按钮(在最后一个堆栈上),当您在应用程序内部时将始终调用,那么此代码将起作用。

public class Yourapp extends Application implements Application.ActivityLifecycleCallbacks {

    private Activity currentActivity; 
    private Handler closecheckhandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                //do whatever you want
                default:
                    super.handleMessage(msg);
            }
        }
    };
    @Override
    public void onCreate() {
        super.onCreate();

        registerActivityLifecycleCallbacks(this);

    }

    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {

    }

    @Override
    public void onActivityStarted(Activity activity) {

    }

    @Override
    public void onActivityResumed(Activity activity) {
        currentActivity = activity;

    }

    @Override
    public void onActivityPaused(Activity activity) {

    }

    @Override
    public void onActivityStopped(Activity activity) {

    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {

    }

    @Override
    public void onActivityDestroyed(Activity destroActivity) {
      if (currentActivity.equals(destroActivity)) {
            closecheckhandler.sendEmptyMessage(//Custom Code);
        } else {
            //do whatever you want
        }
    }
}

【讨论】:

    【解决方案6】:

    您可能会考虑的另一个选项是检查返回按钮或主页按键。这是通过覆盖 onKeyDown() 、监听返回键/home 键并覆盖默认行为来完成的。

    我发现了一个类似的问题,可能会对您有所帮助。

    Android: Prompt user to save changes when Back button is pressed

    干杯

    【讨论】:

    • 主键永远不会被 onKeyDown (或任何其他方法)捕获
    • 在编写本文时,它可以使用 KeyEvent.KEYCODE_HOME。此处的示例:stackoverflow.com/questions/5547818/… 从那以后情况似乎发生了变化,但那是 4 年前的事了。人们应该考虑在否决之前查看帖子的日期。
    猜你喜欢
    • 2017-11-08
    • 1970-01-01
    • 1970-01-01
    • 2021-09-20
    • 1970-01-01
    • 2013-07-12
    • 2013-02-11
    • 2020-10-03
    • 2019-12-14
    相关资源
    最近更新 更多