在android中检测主页按钮按下

Posted

技术标签:

【中文标题】在android中检测主页按钮按下【英文标题】:Detect home button press in android 【发布时间】:2012-02-11 12:12:38 【问题描述】:

这已经让我发疯了一段时间了。

有没有什么方法可以可靠地检测到在 android 应用程序中是否按下了主页按钮?

如果做不到这一点,是否有一种可靠的方法来判断导致活动进入 onPause 的原因?即我们是否可以检测它是由新活动启动还是按返回/主页引起的。

我看到的一个建议是覆盖 onPause() 并调用 isFinishing() 但这会在按下主页按钮时返回 false,就像新活动开始时一样,因此无法区分两者。

非常感谢任何帮助。

** 更新**: 感谢@android-hungry 提供此链接:https://nishandroid.blogspot.com/

重写以下方法:

@Override
public void onAttachedToWindow() 
    super.onAttachedToWindow();
    this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD);           

然后按下主页按钮会触发以下事件:

@Override
public boolean onKeyDown(int keyCode, KeyEvent event)      

    if(keyCode == KeyEvent.KEYCODE_HOME)
    
       //The Code Want to Perform. 
    
);

我不确定这条线是否有任何副作用:

this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD);   

因此,与流行的看法相反,您实际上可以听出 home 键。令人担忧的是,您可以返回 false 并且让 home 键什么都不做。

更新: 正如预期的那样,这有一些副作用 - 启用此模式后,嵌入的视频和谷歌地图似乎不可见。

更新: 据说这个 hack 从 Android 4.0 起不再有效

【问题讨论】:

我的问题不是在 back 和 home 键之间伪装,但我想在这两种情况下都完成应用程序。我使用Activity.onUserLeaveHint(). 唯一的问题是 onUserLeaveHint() 当我从上述活动开始活动时也会触发,我只想知道是否按下了返回或主页。感谢您的建议 确实如此,但不幸的是,据我所知,它是唯一可以接收有关 Home 键使用信息的地方。使收获误报变得更加困难,可以轻松识别出许多误报,但仍然使听起来很简单的任务变得相当复杂。 @DeanWild:你读过这个吗:nisha113a5.blogspot.com TYPE_KEYGUARD 常量已从 Android 5.0 中的 WindowManager.LayoutParams 中删除 【参考方案1】:

以下代码对我有用 :)

HomeWatcher mHomeWatcher = new HomeWatcher(this);
mHomeWatcher.setOnHomePressedListener(new OnHomePressedListener() 
    @Override
    public void onHomePressed() 
        // do something here...
    
    @Override
    public void onHomeLongPressed() 
    
);
mHomeWatcher.startWatch();
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;

public class HomeWatcher 

    static final String TAG = "hg";
    private Context mContext;
    private IntentFilter mFilter;
    private OnHomePressedListener mListener;
    private InnerReceiver mReceiver;

    public HomeWatcher(Context context) 
        mContext = context;
        mFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
    

    public void setOnHomePressedListener(OnHomePressedListener listener) 
        mListener = listener;
        mReceiver = new InnerReceiver();
    

    public void startWatch() 
        if (mReceiver != null) 
            mContext.registerReceiver(mReceiver, mFilter);
        
    

    public void stopWatch() 
        if (mReceiver != null) 
            mContext.unregisterReceiver(mReceiver);
        
    

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

        @Override
        public void onReceive(Context context, Intent intent) 
            String action = intent.getAction();
            if (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) 
                String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
                if (reason != null) 
                    Log.e(TAG, "action:" + action + ",reason:" + reason);
                    if (mListener != null) 
                        if (reason.equals(SYSTEM_DIALOG_REASON_HOME_KEY)) 
                            mListener.onHomePressed();
                         else if (reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) 
                            mListener.onHomeLongPressed();
                        
                    
                
            
        
    

public interface OnHomePressedListener 
    void onHomePressed();
    void onHomeLongPressed();

【讨论】:

你的onHomeLongPressed其实好像对应开启了“Recents”系统活动。在我的手机上,这是通过按下主页按钮旁边的最近按钮触发的,因此您的代码假设它是主页长按并不总是正确的。 为什么它对我不起作用,除了通过清单注册广播之外,我做了完全相同的事情。 在应用程序类中注册,工作至今.. +1,我想知道有什么收获?我的意思是,我们会丢失什么原始案例.. :^) 有时intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);返回空值。我想知道这是怎么回事?? 长按原因现在叫final String SYSTEM_DIALOG_REASON_LONG_PRESS = "assist" 【参考方案2】:

这是一个老问题,但它可能对某人有所帮助。

@Override
protected void onUserLeaveHint()

    Log.d("onUserLeaveHint","Home button pressed");
    super.onUserLeaveHint();

根据文档,onUserLeaveHint() 方法会在用户单击主页按钮或某事中断您的应用程序(如来电)时调用。

这对我有用.. :)

【讨论】:

不正确!!!这在按下主页按钮时有效,但在使用 Intent 切换 Activity 时也有效! 这将始终在 onStop() 之前执行,即使其他活动位于顶部或用户强行离开活动或单击主页按钮... @NikunjParadva 您可以在其他活动中使用 onBackPressed() 方法来解决此问题。【参考方案3】:

无法从 Android 应用程序中检测和/或拦截 HOME 按钮。这是系统内置的,用于防止无法退出的恶意应用程序。

【讨论】:

检查接受的答案,这是可能的。但尚未在许多设备上进行测试。 是的...我的应用程序崩溃了。 启动器/家庭替代应用怎么样?我正在构建一个,我想在用户点击主页时转到第一个屏幕 对于启动器使用这个:@Override protected void onNewIntent(Intent intent) super.onNewIntent(intent); /*做你想做的*/ @lisovaccaro 启动器和/或家庭替代品仍然不受 google (src diane hackborn) 支持,因此您不能阻止用户单击主页按钮。您仍然可以将视图添加为系统警报对话框,它将覆盖所有内容。但是主页按钮的点击会通过它。【参考方案4】:

当第一个活动打开和关闭或任何活动被主页按钮暂停然后从任务管理器恢复时,我需要在我的应用程序中启动/停止背景音乐。 Activity.onPause()Activity.onResume()中的纯播放停止/恢复中断了一段时间的音乐,所以我不得不编写以下代码:

@Override
public void onResume() 
  super.onResume();

  // start playback here (if not playing already)


@Override
public void onPause() 
  super.onPause();

  ActivityManager manager = (ActivityManager) this.getSystemService(Activity.ACTIVITY_SERVICE);
  List<ActivityManager.RunningTaskInfo> tasks = manager.getRunningTasks(Integer.MAX_VALUE);
  boolean is_finishing = this.isFinishing();
  boolean is_last = false;
  boolean is_topmost = false;
  for (ActivityManager.RunningTaskInfo task : tasks) 
    if (task.topActivity.getPackageName().startsWith("cz.matelier.skolasmyku")) 
      is_last = task.numRunning == 1;
      is_topmost = task.topActivity.equals(this.getComponentName());
      break;
    
  

  if ((is_finishing && is_last) || (!is_finishing && is_topmost && !mIsStarting)) 
    mIsStarting = false;
    // stop playback here
  

仅当应用程序(其所有活动)关闭或按下主页按钮时才会中断播放。不幸的是,当调用Activity.startActivity() 时,我没有设法更改启动活动的onPause() 方法和启动活动的onResume() 的调用顺序(或在onPause() 中检测到该活动正在以其他方式启动另一个活动)所以这种情况要特别处理:

private boolean mIsStarting;

@Override
public void startActivity(Intent intent) 
  mIsStarting = true;
  super.startActivity(intent);

另一个缺点是这需要将GET_TASKS权限添加到AndroidManifest.xml

<uses-permission
  android:name="android.permission.GET_TASKS"/>

修改此代码使其仅在按下主页按钮时做出反应是直截了当的。

【讨论】:

【参考方案5】:

onUserLeaveHint();

覆盖此活动类方法。这将检测主页键点击。 这个方法在activity的onPause()回调之前被调用。但是当一个activity被中断时它不会被调用,就像一个通话中的activity进入前台一样,除了当用户点击home键时它会调用这个中断。

@Override
protected void onUserLeaveHint() 
    super.onUserLeaveHint();
    Log.d(TAG, "home key clicked");

【讨论】:

【参考方案6】:

覆盖活动中的onUserLeaveHint()。当有新的活动过来或用户按下后,活动将永远不会有任何回调。

【讨论】:

在应用内从一个活动转到另一个活动时也会调用它【参考方案7】:

从 API 14 开始,您可以使用函数 onTrimMemory() 并检查标志 TRIM_MEMORY_UI_HIDDEN。这将告诉您您的应用程序将进入后台。

因此,在您的自定义应用程序类中,您可以编写如下内容:

override fun onTrimMemory(level: Int) 
    if (level == TRIM_MEMORY_UI_HIDDEN) 
        // Application going to background, do something
    

为了对此进行深入研究,我邀请您阅读这篇文章: http://www.developerphil.com/no-you-can-not-override-the-home-button-but-you-dont-have-to/

【讨论】:

好文章 - 可能满足大多数人需要的有用替代方案 不错的解决方案。你知道当应用程序从后台返回时如何重置标志吗?例如,如果我创建一个布尔 isInBackground,我希望在我们从后台返回后将其重置为。【参考方案8】:

尝试为每个屏幕创建一个计数器。如果用户触摸 HOME,则计数器将为零。

public void onStart() 
  super.onStart();
  counter++;


public void onStop() 
  super.onStop();
  counter--;    
  if (counter == 0) 
      // Do..
  

【讨论】:

如果你的意思是全局应用程序计数器,当一个活动被移到后栈而另一个被移到顶部时,或者当顶部活动完成并且返回堆栈活动被移动时,它将为零当您想对按下主页按钮做出反应时,顶部是通常的位置。如果您的意思是活动范围的计数器,那么只要活动不可见(不一定由按下主页按钮引起),它就会为零。唯一的解决方案是使用计时器来推迟您的反应以跳过此转换,但必要的延迟可能无法预测或不可取。【参考方案9】:

您可以考虑 Andreas Shrade 在How-To Create a Working Kiosk Mode in Android 上的帖子中提出的解决方案。这有点hacky,但鉴于阻止拦截主页按钮的原因,它必须是;)

【讨论】:

【参考方案10】:

我遇到了这个问题,由于底层的android系统没有调用这个方法,重写onKeyDown()方法没有完成任何事情,我通过重写onBackPressed()解决了这个问题,并且我设置了一个布尔值那里是假的,因为我回击了,让我告诉你我在代码中的意思:

import android.util.Log;
public class HomeButtonActivity extends Activity 
    boolean homePressed = false;
    // override onCreate() here.

    @Override
    public void onBackPressed() 
        homePressed = false; // simply set homePressed to false
    

    @Overide
    public void onResume() 
        super.onResume();
        homePressed = true; // default: other wise onBackPressed will set it to false
    

    @Override
    public void onPause() 
        super.onPause();
        if(homePressed)  Log.i("homePressed", "yay"); 
    

所以这个工作的原因是因为在这个活动之外导航的唯一方法是按下返回或主页,所以如果按下返回,那么我知道原因不在家里,但否则原因是家里,因此我设置homePressed 的默认布尔值为 true。但是,这仅适用于您的应用程序中的单个活动实例,因为否则您有更多可能导致调用 onPause() 方法。

【讨论】:

其实当你去另一个activity时,会调用onpause方法 这就是为什么我明确指出这只有在您的应用程序只包含一个活动时才有效! 如果多个不相关的活动同时运行,而用户只是在它们之间切换呢?现代 Android 设备支持多任务处理。使用此代码,看起来切换回您的应用程序会将homePressed 设置为 true,然后切换到另一个应用程序会认为 Home 被按下,而实际上并非如此。【参考方案11】:

最近我试图检测主页按钮,因为我需要它与方法“onBackPressed()”相同。为此,我必须像这样重写方法“onSupportNavigateUp()”:

override fun onSupportNavigateUp(): Boolean 
    onBackPressed()
    return true

效果很好。 =)

【讨论】:

【参考方案12】:

Android Home Key 由框架层处理,您无法在应用层级别处理。因为主页按钮动作已经在下面的级别中定义了。但是如果您正在开发您的自定义 ROM,那么它可能是可能的。出于安全原因,Google 限制了 HOME BUTTON 覆盖功能。

【讨论】:

【参考方案13】:

您的应用程序的一个选项是使用 android.intent.category.HOME Intent 编写替代主屏幕。我相信这种Intent你可以看到home键。

更多细节:

http://developer.android.com/guide/topics/intents/intents-filters.html#imatch

【讨论】:

有趣的想法,但有点啰嗦,不像我希望的那样优雅【参考方案14】:

由于您只希望在启动应用程序时重新显示根 Activity,也许您可​​以通过在清单中更改启动模式等来实现此行为?

例如,您是否尝试将android:clearTaskOnLaunch="true" 属性应用于您的启动活动,可能与android:launchMode="singleInstance" 一起使用?

Tasks and Back Stack 是微调此类行为的绝佳资源。

【讨论】:

这似乎是最优雅的解决方案,但我发现它非常不可靠。在几个打开/关闭/暂停周期后,应用程序将开始恢复,而不是完全重新启动【参考方案15】:

更改主页键的行为是个坏主意。这就是为什么 Google 不允许您覆盖 home 键的原因。一般来说,我不会弄乱home键。无论出于何种原因,您都需要为用户提供一种退出应用程序的方法。

我认为任何解决方法都会产生不必要的副作用。

【讨论】:

您绝对是正确的,但有些客户不会接受否定的答案,也不明白他们为什么不应该违反准则。 问题是,即使您不想更改主页按钮的行为,您有时也必须对由于主页按钮按下而导致应用程序后退的情况做出不同的反应,而不是对这种情况做出不同的反应无论出于何种原因,您当前的活动都已暂停。同样的问题在于 Application.onDestroy() 不能用于生产构建。此类示例是当用户隐藏应用程序、停止背景音乐等时暂停游戏。【参考方案16】:

Jack 的答案非常适合click 事件,而longClick 正在考虑的是menu 按钮单击。

顺便说一句,如果有人想知道如何通过 kotlin 来做,

class HomeButtonReceiver(private var context: Context,private var listener: OnHomeButtonClickListener) 
    private val mFilter: IntentFilter = IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)
    private var mReceiver: InnerReceiver = InnerReceiver()

    fun startWatch() 
        context.registerReceiver(mReceiver, mFilter)
    

    fun stopWatch() 
        context.unregisterReceiver(mReceiver)
    

    inner class InnerReceiver: BroadcastReceiver() 
        private val systemDialogReasonKey = "reason"
        private val systemDialogReasonHomeKey = "homekey"
        override fun onReceive(context: Context?, intent: Intent?) 
            val action = intent?.action
            if (action == Intent.ACTION_CLOSE_SYSTEM_DIALOGS) 
                val reason = intent.getStringExtra(systemDialogReasonKey)
                if (reason != null && reason == systemDialogReasonHomeKey) 
                    listener.onHomeButtonClick()
                
            
        
     

【讨论】:

【参考方案17】:

这对我有用。 您可以覆盖 onUserLeaveHint 方法 https://www.tutorialspoint.com/detect-home-button-press-in-android

@Override
    protected void onUserLeaveHint() 
        //
        super.onUserLeaveHint();
    

【讨论】:

这仅在您的应用中只有一个活动时才有效。如果您有多个活动,当您切换到另一个活动时,这不起作用,此方法也会触发。不好。 如果您触发画廊意图等,这也不起作用 这也被建议作为 2017 年这个问题的答案

以上是关于在android中检测主页按钮按下的主要内容,如果未能解决你的问题,请参考以下文章

当用户按下主页按钮时停止 Android 服务

Android 11 - 按下主页按钮时触发前台服务 onTaskRemoved

在android的主页按钮中需要帮助

如何以编程方式在android中检测设备电源按钮按下两次

Android - 按下时显示上次查看的活动(主页按钮 - >应用程序快捷方式)

Android - 双击主页按钮作为默认操作