这已经让我发疯了一段时间了。
是否有任何方法可以可靠地检测是否在 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 起不再有效
Activity.onUserLeaveHint()
完成的。
以下代码对我有用:)
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();
}
这是一个古老的问题,但它可能对某人有所帮助。
@Override
protected void onUserLeaveHint()
{
Log.d("onUserLeaveHint","Home button pressed");
super.onUserLeaveHint();
}
根据文档,onUserLeaveHint() 方法在用户单击主页按钮或某些事情中断您的应用程序(如来电)时被调用。
这对我有用.. :)
无法从 Android 应用程序中检测和/或拦截 HOME 按钮。这是系统内置的,以防止无法退出的恶意应用程序。
当第一个活动打开和关闭或任何活动被主页按钮暂停然后从任务管理器恢复时,我需要在我的应用程序中启动/停止背景音乐。 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()
中检测到该活动正在以其他方式启动另一个活动)时,我没有设法更改启动活动的 onPause()
方法和已启动活动的 onResume()
的调用顺序所以这种情况必须特别处理:
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"/>
修改仅对按下主页按钮作出反应的代码是直截了当的。
覆盖 Activity 中的 onUserLeaveHint()
。当一个新的活动过来或用户按下后,活动将永远不会有任何回调。
onUserLeaveHint();
覆盖此活动类方法。这将检测主页键单击。此方法在活动的 onPause() 回调之前调用。但是当活动被中断时,如通话中活动进入前台,它不会被调用,除了当用户单击主页键时它会调用的中断。
@Override
protected void onUserLeaveHint() {
super.onUserLeaveHint();
Log.d(TAG, "home key clicked");
}
从 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/
尝试为每个屏幕创建一个计数器。如果用户触摸 HOME,则计数器将为零。
public void onStart() {
super.onStart();
counter++;
}
public void onStop() {
super.onStop();
counter--;
if (counter == 0) {
// Do..
}
}
您可以考虑 Andreas Shrade 在他关于 How-To Create a Working Kiosk Mode in Android 的帖子中的解决方案。这有点hacky,但鉴于阻止拦截主页按钮的原因,它必须是;)
由于您只希望在启动应用程序时重新显示根活动,也许您可以通过在清单中更改启动模式等来获得此行为?
例如,您是否尝试过将 android:clearTaskOnLaunch="true" 属性应用于您的启动活动,也许与 android:launchMode="singleInstance" 一起使用?
Tasks and Back Stack 是微调此类行为的绝佳资源。
我遇到了这个问题,因为覆盖 onKeyDown() 方法没有完成任何事情,因为底层的 android 系统没有调用这个方法,我通过覆盖 onBackPressed() 解决了这个问题,并且我在那里设置了一个布尔值 false ,因为我回击了,让我告诉你我在代码中的意思:
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"); }
}
所以这个工作的原因是因为在这个活动之外导航的唯一方法是按下返回或主页,所以如果按下返回,那么我知道原因不在家里,但否则原因是家里,因此我设置了默认布尔值home 的值被按下为真。但是,这仅适用于您的应用程序中的单个活动实例,因为否则您有更多可能导致调用 onPause() 方法。
homePressed
设置为 true,然后切换到另一个应用程序会认为 Home 被按下,而实际上并非如此。
最近我试图检测主页按钮,因为我需要它来做与“onBackPressed()”方法相同的事情。为了做到这一点,我必须像这样覆盖方法“onSupportNavigateUp()”:
override fun onSupportNavigateUp(): Boolean {
onBackPressed()
return true
}
它工作得很好。 =)
https://i.stack.imgur.com/9VWqU.png
您的应用程序的一个选项是使用 android.intent.category.HOME Intent 编写替换主屏幕。相信这种Intent你可以看到home键。
更多细节:
http://developer.android.com/guide/topics/intents/intents-filters.html#imatch
更改主键的行为是个坏主意。这就是为什么 Google 不允许您覆盖 home 键的原因。一般来说,我不会弄乱home键。无论出于何种原因,您需要为用户提供一种退出您的应用程序的方法。
我认为任何解决方法都会产生不必要的副作用。
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()
}
}
}
}
}
这对我有用。您可以覆盖 onUserLeaveHint 方法 https://www.tutorialspoint.com/detect-home-button-press-in-android
@Override
protected void onUserLeaveHint() {
//
super.onUserLeaveHint();
}
onHomeLongPressed
实际上似乎对应于“最近”系统活动的打开。在我的手机上,这是通过按下主页按钮旁边的最近按钮触发的,因此您的代码假设它是家庭长按并不总是正确的。final String SYSTEM_DIALOG_REASON_LONG_PRESS = "assist"