如何检测“最近的应用程序”系统按钮点击(Honeycomb +)

时间:2012-09-18 14:16:52

标签: android button user-interface android-3.0-honeycomb android-4.0-ice-cream-sandwich

我想知道这个按钮叫什么方法。

enter image description here

我的游戏总是暂停/恢复正常情况,除非我使用此按钮时,似乎此按钮不会调用ActivityonPause()onResume()方法。 它可以工作,如果我退出游戏,转到另一个窗口(如图片中的那个),然后使用此按钮恢复。但是,如果我只是按下这个按钮,当游戏时,游戏暂停,但线程dosnt恢复就像它每隔一段时间一样,游戏类型只是停留在屏幕上并且有点闪烁。

很难解释,但我希望我有点清楚,如果没有,请问!

8 个答案:

答案 0 :(得分:23)

按下“Recent Apps”按钮时,不会调用任何标准Activity Lifecycle方法。在最近的应用弹出列表后,活动将保持活动状态。通过此列表的半透明左侧部分,您甚至可以观察应用程序动画是否仍在运行,如果您运行的游戏中包含一些无法正确处理此情况的动画。实际上,Google Play中的许多游戏都没有正确处理这种情况,即使是像“愤怒的小鸟”这样的好游戏。

当用户打开“Recent Apps”列表(或从中返回)时,调用唯一的Activity方法是onWindowFocusChanged,其布尔参数为hasFocus。当用户在此列表中按“返回”时,当用户打开使用onWindowFocusChanged()调用的最近应用方法hasFocus的列表等于false时,使用hasFocus调用的相同方法等于true

答案 1 :(得分:5)

检测“最近的应用”和“#39;按下按钮您可以使用辅助功能服务。您需要运行自己的辅助功能服务并接收类型为" TYPE_WINDOW_STATE_CHANGED"的事件。并查看活动的班级名称。

  1. 在Android开发者中阅读Accessibility Service。设置您自己的辅助功能服务,请求用户许可。
  2. 在辅助功能服务覆盖方法onAccessibilityEvent()
  3. 在此方法中,您将收到AccessibilityEvent event个对象,此对象包含有关您设备上刚刚发生的事件的所有必要信息。
  4. 我们对ClassName感兴趣。 ClassName有时可以为null,所以不要忘记!= null check。 最近的应用程序窗口的程序包名称将根据Android的版本而有所不同:

    • Android 4.1:" com.android.internal.policy.impl.RecentApplicationsDialog"
    • Android 4.2 - 4.4:" com.android.systemui.recent.RecentsActivity"
    • Android 5.0 - 7.1:" com.android.systemui.recents.RecentsActivity" (" s"信已被添加)
  5. 不知道旧设备的班级名称,但我不认为有人在2017年维护它们;)

    所以你会有这样的事情:

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        if (event.getEventType() != AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED || event.getClassName() == null) 
            return;
    
        String className = String.valueOf(event.getClassName());
    
        if (className.equals("com.android.internal.policy.impl.RecentApplicationsDialog")
                || className.equals("com.android.systemui.recent.RecentsActivity")
                || className.equals("com.android.systemui.recents.RecentsActivity")){
            //Recent button was pressed. Do something.
        }
    }
    

    我已经在以下真实设备上测试过它:LG,Nexus,索尼和虚拟设备:摩托罗拉,三星。

    如果有人知道这些班级名称的例外情况,请告诉我。

答案 2 :(得分:4)

我有同样的问题,我解决了这个问题如下。

注册按钮点击Home和RecentApp的广播

InnerReceiver mReceiver = new InnerReceiver();
IntentFilter mFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
registerReceiver(mReceiver, mFilter);

现在是BroadcastReceiver代码

class InnerReceiver extends BroadcastReceiver {
    final String SYSTEM_DIALOG_REASON_KEY = "reason";
    final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
    final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";

    @Override
    public void onReceive(Context context, Intent intent) {

        if (intent.getAction().equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
            String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
            if (reason != null) {
                if (mListener != null) {
                    if (reason.equals(SYSTEM_DIALOG_REASON_HOME_KEY)) {
                        // Home Button click
                    } else if (reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
                        // RecentApp or Overview Button click
                    }
                }
            }
        }
    }
}

但是别忘了unregisterReceiver BroadcastReceiver

答案 3 :(得分:3)

我遇到了类似的问题,所以,我需要知道用户何时按下最近的应用程序按钮(旧版Android中的菜单键按钮)。经过几个小时的研究后,当按下主页按钮或菜单按钮时,我没有发现要捕获的事件。我发现当用户按下主页按钮时,需要花费更长的时间来调用onStop(),所以我找到一个技巧来区分这些与响应时间相关的拖拽按钮和覆盖两种方法:

@覆盖

public void onUserLeaveHint() {
    // do stuff
    super.onUserLeaveHint();
    userLeaveTime = System.currentTimeMillis() ;
    isNotPower = true;
}

@覆盖

public void onStop() {
    super.onStop();
    if (isNotPower) {
        defStop = System.currentTimeMillis() - userLeaveTime;
        if (defStop > 200 ) {
            //home button
        }
        if (defStop < 200) {
            //recent apps button
        }
    }
    isNotPower = false;
}
  • 用于检查未按下电源按钮的isNotPower参数 - 当按下onStop()方法的电源按钮被调用时,而不是onUserLeaveHint()。

答案 4 :(得分:2)

我找到的最佳方式是持续广播行动称为&#34; ACTION_CLOSE_SYSTEM_DIALOGS&#34;。来自Google文档:

广播操作:当用户操作请求时广播 解雇临时系统对话框。临时系统的一些例子 对话框是通知窗口阴影和最近任务对话框

工作代码:

IntentFilter intentFilterACSD = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);

    BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
                    //do what you want here
            }
        }
    };
    this.registerReceiver(broadcastReceiver, intentFilterACSD);

答案 5 :(得分:0)

这只是这个特定游戏的问题吗?或者你玩的每一场比赛都是这样吗?

onPause()onResume()旁边,还有另一个名为onStop()的周期。也许这里有一些基本的事情要做。通过按下“开窗”按钮,游戏可能不会进入onStop - 状态,而按下“主页”按钮则会。

答案 6 :(得分:0)

试试这个:

public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);

    Log.d("Focus debug", "Focus changed !");

    if (!hasFocus) {
        Log.d("Focus debug", "Lost focus !");

    }
}

答案 7 :(得分:0)

我写了一个应用程序,明确地展示了最近应用程序 / 最近键相对于活动和片段的行为。

(任何断言正常生命周期事件均未通过此键触发的说法显然都是错误的。)

onCreate()中,主 Activity 初始化一个数组,用于记录所有已知的 Activity 生命周期事件,并在第二个FrameLayout中将主Fragment与其自身一起触发

onAttach()中,主要的 Fragment 初始化一个单独的数组,用于记录所有已知的 Fragment 生命周期事件。

出于记录目的, Activity Fragment 都将onWindowFocusChanged()视为另一个生命周期事件。

记录的事件带有时间戳,因此在渲染时可以给出用户“暂停”指示(并且onWindowFocusChanged()时,渲染发生在hasFocus==true内部)。

这是启动测试应用程序时用户看到的内容:

enter image description here

几秒钟后,用户按下 recent-apps ,等待几秒钟,然后再次按下以查看真相:

enter image description here

注意:如果不是通过使用“最近使用的应用程序”按钮,而是通过(a)按下数位板关闭/打开按钮(b)按下“开始第二个活动”按钮(c)等重复进行实验,则得出相同的结果。 / p>

答复OP:
显然,没有任何代码可以检测到对最新应用程序键的实际按下!

但这没关系,因为应用程序仍然需要正确处理关联的生命周期事件。