【发布时间】:2011-01-13 14:44:19
【问题描述】:
你能告诉我我的活动如何检测到用户按下 HOME 键吗?
谢谢。
【问题讨论】:
标签: android
你能告诉我我的活动如何检测到用户按下 HOME 键吗?
谢谢。
【问题讨论】:
标签: android
android.text.method.KeyListener.onKeyDown([view],[text],KEYCODE_HOME,[event])
我不确定其他参数如何适应,甚至如何实现上述参数,但信息都在 keylistner documentation。
但他们在another page 也提到主页键总是回家,你不能改变它。因此,如果您打算使用某种“您确定要退出”对话框,那是行不通的。
【讨论】:
您无法捕获 HOME 事件并以任何方式拦截它。当用户按下主屏幕键时,他们将始终被带到他们设备的主屏幕。
如果您需要知道您的 Activity 何时被发送到后台,例如用户按下主页或返回键,我会实现 onStop() 方法。
【讨论】:
您可以编写一个广播监听器并将过滤器设置为
<category android:name="android.intent.category.HOME" />
从广播接收器开始你的活动/通知活动。
【讨论】:
您可以通过 Activity.onUserLeaveHint() 检测到按下 HOME 按钮。该方法在两种情况下被调用;当用户按下 HOME 并启动新活动时。确保以某种方式区分两者。
【讨论】:
onUserLeaveHint() 在你按下任务键时也会被调用
没有正式的方式来通知“HOME”键按下。但是有一个非常简单的解决方法可以让您的应用区分“HOME”按键和任何其他会导致 Activity 停止的操作。
对于需要在“HOME”按键上执行某些操作的每个类,让它们从包含以下内容的活动扩展:
/**************************************** On Home **********************************/
private boolean leaveCalled = false;
@Override
public void startActivity(Intent intent) {
leaveCalled= true;
super.startActivity(intent);
}
@Override
public void onBackPressed() {
leaveCalled = true;
super.onBackPressed();
}
@Override
protected void onStop() {
super.onStop();
// Home button pressed
if(!leaveCalled) {
// Do whatever you like.
}
leaveCalled = false;
}
编辑
您还需要从包含它的父类扩展您的 Fragments。这是因为 Fragment 会提供额外的路径,以预期的方式而不是“HOME”方式在应用中的 Activity 之间切换。
@Override
public void startActivity(Intent intent) {
getActivity().startActivity(intent);
}
编辑 2
我越来越接近于认为这不是处理此问题的最简单方法...您还需要将 onConfigurationChange="orientation" 添加到使用此方法的所有活动中。然后你可以添加这个:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
leaveCalled = true;
finish();
startActivity(getIntent());
}
编辑 3
呃
@Override
public void finish() {
leaveCalled = true;
super.finish();
}
【讨论】:
onStop() 是leaveCalled = false的情况太多了,比如电话、Activity从服务中启动等等……
可以做到(至少到 2.3)。在 android 版本 2.3.5 无根 HTC WildFire-S 上测试。代码 sn-p 捕获/禁用所有控制键:
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD);
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(keyCode == KeyEvent.KEYCODE_HOME || keyCode == KeyEvent.KEYCODE_POWER || keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU || keyCode == KeyEvent.KEYCODE_SEARCH )
{
Toast.makeText(getApplicationContext(),"You pressed a control button with keyCode : " + keyCode, Toast.LENGTH_SHORT).show();
return false;
}
else
{
Toast.makeText(getApplicationContext(),"You pressed" + keyCode, Toast.LENGTH_SHORT).show();
}
return true;
}
public boolean onKeyUp(int keyCode, KeyEvent event) {
if(keyCode == KeyEvent.KEYCODE_HOME || keyCode == KeyEvent.KEYCODE_POWER || keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU || keyCode == KeyEvent.KEYCODE_SEARCH )
{
return false;
}
else
{
// Do nothing
}
return true;
}
【讨论】:
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(keyCode == KeyEvent.KEYCODE_HOME)
{
//The Code Want to Perform.
}
});
【讨论】:
更新 [2015 年 8 月]:根据 JM Lord 的评论,对于 Lollipop 及更高版本的设备,此答案可能无法正常工作。见Alternative to getRunningTasks in Android L
虽然,这是一个老问题,但大多数答案在 API 级别 17 及更高级别对我不起作用。我正在回答最终对我有用的东西。我尝试了很多方法,但没有一个像今天一样有效。我在
上尝试了答案Call method when home button pressed on android,
Detect home button press in android 和
Overriding the Home button - how do I get rid of the choice?。要点是 Home 就像一个紧急逃生按钮。所以你不能覆盖它,但可以通过某些方式检测到它。
我尝试过的一些(包括上面的答案)并且不起作用是:
以多种方式使用 keyCode==KeyEvent.KEYCODE_HOME
综上所述。现在,如果您阅读
KeyEvent.KEYCODE_HOME,上面写着This key is handled by the
framework and is never delivered to applications。所以它不再
现在有效。
我尝试使用 onUserLeaveHint()。文档说:
在活动即将开始时作为活动生命周期的一部分调用 作为用户选择的结果进入后台。例如, 当用户按下 Home 键时,onUserLeaveHint() 将 通话,但当来电导致通话中活动 被自动带到前台。
问题在于,当您启动 Activity 时,该方法也会被调用
在您调用onUserleaveLint() 的活动中,
就像我的情况一样。有关更多信息,请参阅Android onBackPressed/onUserLeaveHint 问题。所以它不确定
只有按主页按钮才能调用它。
呼叫onStop()。当一个活动在现有活动之上并完全覆盖它时,也可以调用它。所以这也行不通。
以下方法终于为我工作了:
看到How to check current running applications in Android?,你可以说如果你的任务是长按主页按钮时显示的最近任务,那么它被发送到后台。
因此,在您尝试检测按下主页按钮的活动的onPause() 中,您可以检查应用程序是否已发送到后台。
@Override
public void onPause() {
if (isApplicationSentToBackground(this)){
// Do what you want to do on detecting Home Key being Pressed
}
super.onPause();
}
检查你的应用程序是否是最近发送到后台的功能:
public boolean isApplicationSentToBackground(final Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = am.getRunningTasks(1);
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
if (!topActivity.getPackageName().equals(context.getPackageName())) {
return true;
}
}
return false;
}
感谢@idish 指出不要忘记在清单中包含以下权限:
<uses-permission android:name="android.permission.GET_TASKS" />
我不确定这是否有任何缺点,但它对我很有效。希望有一天它可以帮助某人。
P.S:如果您在使用 FLAG_ACTIVITY_NO_HISTORY 标志启动的 Activity 中使用此方法,那么这将没有用,因为它会检查最近的历史记录以确定是否单击了 Home 按钮。
【讨论】:
在你的 Activity 中使用 onUserLeaveHint() 方法
@Override
protected void onUserLeaveHint()
{
super.onUserLeaveHint();
}
http://developer.android.com/reference/android/app/Activity.html#onUserLeaveHint()
【讨论】:
public boolean isApplicationSentToBackground(final Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = am.getRunningTasks(1);
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
if (!topActivity.getPackageName().equals(context.getPackageName())) {
return true;
}
}
return false;
}
public void onPause() {
super.onPause();
if(isApplicationSentToBackground(this))
{
Log.i("Home", "Home Pressed..!");
}
}
【讨论】:
我根据@Springfeed 的建议找到了这个解决方案。这个问题很笼统,请注意这个特定的解决方案将:
这段代码在我的基础Activity 类中(所有活动都继承)
public boolean startingActivity = false;
@Override
protected void onUserLeaveHint()
{
if(startingActivity)
{
// Reset boolean for next time
startingActivity = false;
}
else
{
// User is exiting to another application, do what you want here
Log.i(TAG, "Exiting");
...
}
}
@Override
public void startActivity(Intent intent)
{
startingActivity = true;
super.startActivity(intent);
}
@Override
public void startActivityForResult(Intent intent, int requestCode)
{
startingActivity = true;
super.startActivityForResult(intent, requestCode);
}
由于某些方法也可能使用应用程序上下文来启动意图,我定义了一个由我的 Application 类持有的 ContextWrapper 来切换布尔值(请注意,我可以通过该基类对我自己的应用程序的最顶层活动进行静态访问)。
public class MyContext extends ContextWrapper
{
public MyContext(Context base)
{
super(base);
}
@Override
public void startActivity(Intent intent)
{
BaseActivity activity = BaseActivity.getActivity();
if(activity != null)
{
activity.startingActivity = true;
}
super.startActivity(intent);
}
}
如有必要,您可能还想覆盖 startActivities(...)。
希望这会有所帮助:)
【讨论】: