覆盖返回按钮以像主页按钮一样使用

257

当按下“返回”按钮时,我希望我的应用程序进入停止状态,而不是销毁状态。

在Android文档中指出:

……并非所有活动在按下“返回”键时都会被销毁。当用户在音乐应用程序中开始播放音乐然后按下“返回”键时,应用程序将覆盖正常的返回行为,防止播放器活动被销毁,并继续播放音乐,即使其活动不再可见。

如何在自己的应用程序中复制此功能?

我认为可能有三种可能性...

  1. 捕获“返回”按钮按下事件(如下所示),然后调用与主页按钮调用的任何方法。

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if ((keyCode == KeyEvent.KEYCODE_BACK)) {
        Log.d(this.getClass().getName(), "back button pressed");
    }
    return super.onKeyDown(keyCode, event);
}
  • 捕获后退按钮按下事件,然后模拟按下主页按钮。

  • 捕获后退按钮按下事件,然后启动主屏幕的 Activity ,有效地将我的应用程序的 Activity 置于停止状态。


  • 请参考以下代码解决您的问题:@Override public void onBackPressed() { moveTaskToBack(true); } 这会将当前活动移至后台,而不是销毁它。 - Zar E Ahmer
    10个回答

    343

    通常情况下,您需要创建一个服务(Service)在后台执行某些操作,而您可见的Activity只需控制此Service。(我相信音乐播放器也是以同样的方式工作的,所以文档中的示例有点误导人。)如果是这种情况,则您的Activity可以像往常一样finishService仍将继续运行。

    一个更简单的方法是捕获Back按钮按下事件,并调用moveTaskToBack(true),如下所示:

    // 2.0 and above
    @Override
    public void onBackPressed() {
        moveTaskToBack(true);
    }
    
    // Before 2.0
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            moveTaskToBack(true);
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
    

    我认为首选的选项应该是让Activity正常结束并能够重新创建自己,例如如果需要,从Service中读取当前状态。但是在某些情况下可以使用moveTaskToBack作为一种快速替代方法。

    注意:如Dave所指出,Android 2.0引入了一个新的onBackPressed方法,并提供了这些建议来处理返回按钮。


    1
    moveTaskToBack() 看起来可以按预期工作。使用此方法可能存在哪些缺点?是否存在某些情况,此方法可能无法按预期工作? - bdls
    1
    仔细阅读了它的文档后,我实际上认为它应该可以正常工作。(我最初认为它适用于活动,但实际上它是针对“包含此活动的任务”。)当然,你应该自己测试一下。 :) - Mirko N.
    4
    请阅读http://android-developers.blogspot.com/2009/12/back-and-other-hard-keys-three-stories.html,了解处理后退键的推荐方式。 - hackbod
    1
    @bdls 理论上,如果系统资源不足,后台活动可能会被系统杀死,因此为了安全起见,它应该能够重新创建自己。我查看了 Android 音乐应用程序的源代码,没有看到任何特殊的返回按钮处理。 - Mirko N.
    @bdls Mirko在这里说得很对。你不能依靠Activity类的实例保留状态。当Activity死亡时,你需要保存任何需要的状态,并在重新创建时能够读取它。在你的应用程序中,你可以简单地在Activity启动时向Service请求所需的所有状态。一旦完成了这个步骤,就没有理由重写返回按钮了。 - SamStephens
    显示剩余5条评论

    49

    使用以下代码:

    public void onBackPressed() {    
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_HOME);
        startActivity(intent);
    }
    

    23
    如果您想捕获返回按钮,请看看Android开发者博客上的这篇文章。它介绍了在Android 2.0中实现此功能的更简单方法,以及在运行于1.x和2.0的应用程序中实现此功能的最佳方法。
    然而,如果您的 Activity 被停止,根据设备上的内存可用性,它仍然可能被杀死。如果您想要运行没有 UI 的进程,则应创建一个 Service文档对服务说了以下内容:

    服务没有可视化用户界面,而是在后台无限期地运行。例如,服务可能会在用户处理其他事情时播放背景音乐,或者它可能会通过网络获取数据或计算某些内容,并将结果提供给需要它的活动。

    这些似乎符合您的要求。

    18
    尝试覆盖在 android.app.Activity 类中定义的 void onBackPressed() 方法。

    1
    自 Android 2.0 版本以来,这是正确的覆盖方法。http://developer.android.com/sdk/android-2.0.html - jay

    14

    如果有人需要帮助,我创建了一个活动具有两个布局,可以切换以实现类似page1> page2的结构。 如果他们在第二页并按下返回按钮,则应该返回到第一页,如果他们在第一页按下返回按钮,则仍应像平常一样工作。 这很基本,但它有效。

    @Override
    public void onBackPressed() {
    // check if page 2 is open
        RelativeLayout page2layout = (RelativeLayout)findViewById(R.id.page2layout);
        if(page2layout.getVisibility() == View.VISIBLE){
            togglePageLayout(); // my method to toggle the views
            return;
        }else{
            super.onBackPressed(); // allows standard use of backbutton for page 1
        }
    
    }
    

    希望能对某人有所帮助,祝好。


    10

    工作示例...

    确保不要调用super.onBackPressed();

    @Override
    public void onBackPressed() {
       Log.d("CDA", "onBackPressed Called");
       Intent setIntent = new Intent(Intent.ACTION_MAIN);
       setIntent.addCategory(Intent.CATEGORY_HOME);
       setIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
       startActivity(setIntent);
    }
    
    以这种方式,您的“后退”按钮就像“主页”按钮一样。它不会结束您的活动,而是将其移到后台。
    第二种方法是在onBackPressed中调用moveTaskToBack(true),并确保删除super.onBackPressed

    0
    在Android 2.0之后,可以重写onBackPressed()方法。例如:

    @Override
    public void onBackPressed() {
        moveTaskToBack(true);
    }
    

    0

    更好的是,如何使用OnPause()

    当活动进入后台但尚未(被)销毁时,作为活动生命周期的一部分调用。与onResume()相对应。

    当活动B在活动A前面启动时,将在A上调用此回调。只有在A的onPause()返回后,才会创建B,因此请确保不要在此处执行任何冗长的操作。

    此回调主要用于保存活动正在编辑的任何持久状态,并确保如果没有足够的资源启动新活动而不必首先终止此活动,则不会丢失任何内容。

    这也是做一些停止动画和其他消耗大量CPU的事情的好地方,以便尽可能快地切换到下一个活动,或关闭独占访问的资源,例如相机。


    -1

    我使用了@Mirko N.的答案来制作新的自定义EditText

     public class EditViewCustom extends EditText {
    
        Button cancelBtn;
        RelativeLayout titleReleLayout;
        public EditViewCustom(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        public EditViewCustom(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public EditViewCustom(Context context) {
            super(context);
        }
    
        public void setViews(Button cancelBtn,RelativeLayout titleReleLayout){
            this.cancelBtn = cancelBtn;
            this.titleReleLayout = titleReleLayout;
        }
    
        @Override
        public boolean onKeyPreIme(int keyCode, KeyEvent event) {
            if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
                Log.d("KEYCODE_BACK","KEYCODE_BACK");
                cancelBtn.setVisibility(View.GONE);
                this.setFocusableInTouchMode(false);
                this.setFocusable(false);
                titleReleLayout.setVisibility(View.VISIBLE);
    
                return super.onKeyPreIme(keyCode, event);
              }
    
            return super.onKeyPreIme(keyCode, event);
        }
    
    }
    

    然后从您的活动中设置数据

     searchEditView.setViews(cancelBtn, titleRelativeLayout);
    

    谢谢。


    -1

    我尝试了以上所有解决方案,但都没有对我起作用。以下代码帮助了我,当我尝试以一种使onCreate被调用的方式返回到MainActivity时:

    Intent.FLAG_ACTIVITY_CLEAR_TOP是关键。

      @Override
      public void onBackPressed() {
          Intent intent = new Intent(this, MainActivity.class);
          intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
          startActivity(intent);
      }
    

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接