Android - 如何覆盖“返回”按钮,使其不会完成()我的活动?

Android - How To Override the "Back" button so it doesn't Finish() my Activity?

提问人:Donal Rafferty 提问时间:6/29/2010 最后编辑:Donal Rafferty 更新时间:10/30/2020 访问量:409889

问:

我目前有一个活动,当它显示时,通知也会显示在通知栏中。

这样,当用户按 Home 键并且 Activity 被推送到后台时,他们可以通过通知返回 Activity。

当用户按下后退按钮时,会出现问题,我的活动被销毁,但通知仍然存在,因为我希望用户能够按下后退,但仍然能够通过通知访问活动。但是当用户尝试这样做时,我会得到空指针,因为它试图启动一个新活动而不是带回旧活动。

因此,从本质上讲,我希望“后退”按钮的行为与“主页”按钮完全相同,这是我到目前为止尝试过的方法:


        @Override
        public boolean onKeyDown(int keyCode, KeyEvent event)  {
            if (Integer.parseInt(android.os.Build.VERSION.SDK) < 5
                    && keyCode == KeyEvent.KEYCODE_BACK
                    && event.getRepeatCount() == 0) {
                Log.d("CDA", "onKeyDown Called");
                onBackPressed();
            }

            return super.onKeyDown(keyCode, event);
        }

        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); 

            return;
        }   

但是,上面的代码似乎仍然允许我的 Activity 被销毁,当按下后退按钮时,如何阻止我的 Activity 被销毁?

Android-Activity nullPointerException 后退按钮 onkeypress

评论

0赞 aleung 12/19/2010
有一个类似的问题:stackoverflow.com/questions/2459848/......
1赞 Zar E Ahmer 5/20/2014
类似的答案..stackoverflow.com/questions/5914040/......
0赞 SudoPlz 11/19/2015
此外,我认为您必须将代码更改为“if (Integer.parseInt(android.os.Build.VERSION.SDK) > 5<”应该成为., the >
1赞 ToolmakerSteve 9/22/2016
即使你解决了这个问题,你仍然必须处理系统杀死你的应用程序的可能性,对吧?我的意思是,空情况还有可能吗?或者,如果系统出于任何原因终止了您的应用程序,这也会删除您的通知吗?我认为这一定是一个问题,因为即使应用程序不存在,通知的目的是存在。
2赞 Alex Cohn 12/22/2022
更新:2022 年 9 月 onBackPressed() 在 API 级别 33 中已弃用。请改用 or 来处理后退导航。OnBackInvokedCallbackandroidx.activity.OnBackPressedCallback

答:

12赞 kiswa 6/29/2010 #1

我认为您想要的不是覆盖后退按钮(这似乎不是一个好主意 - Android 操作系统定义了该行为,为什么要更改它?),而是使用活动生命周期并将您的设置/数据保存在 onSaveInstanceState(Bundle) 事件中。

@Override
onSaveInstanceState(Bundle frozenState) {
    frozenState.putSerializable("object_key",
        someSerializableClassYouWantToPersist);
    // etc. until you have everything important stored in the bundle
}

然后,使用 onCreate(Bundle) 从该持久化捆绑包中获取所有内容并重新创建状态。

@Override
onCreate(Bundle savedInstanceState) {
    if(savedInstanceState!=null){ //It could be null if starting the app.
        mCustomObject = savedInstanceState.getSerializable("object_key");
    }
    // etc. until you have reloaded everything you stored
}

考虑上面的伪装代码,为你指明正确的方向。阅读活动生命周期应该可以帮助您确定完成所需任务的最佳方式。

评论

0赞 Donal Rafferty 6/30/2010
嗨,Kiswa,这是真的,我不想改变默认行为。我尝试使用 onSavedInstanceState,但它不起作用,但我相信我现在已经发现了我的错误。谢谢
5赞 Matt Briançon 5/9/2011
我至少遇到过一些情况,我想在不实际启动新活动的情况下模拟标准活动堆栈行为。在这些情况下,我认为覆盖默认的 onBackPressed() 行为是合适的。不过,总的来说,我同意:避免覆盖。
4赞 Leif Andersen 8/11/2011
我同意@Matt。我目前正在开发一款使用 NDK 的跨平台游戏。因此,如果一切都是单一活动,那就最简单了。因此,后退按钮的默认行为是转义应用程序,这不是大多数用户所期望的。因此,我不得不覆盖默认行为,使活动的行为不同,就好像用户实际上去了不同的活动一样,并且只在某些情况下退出应用程序。
1赞 Ted 10/5/2011
onSaveInstanceState 和保存数据不是一个完全不同的问题吗?
0赞 ToolmakerSteve 9/22/2016
@Ted - 如果你是说除了 onSaveInstanceState 之外,还需要有保留非 UI 应用程序数据的代码,那么我同意。一旦您放弃前台,您的应用可能会在没有进一步警告的情况下被终止。必须始终保存任何重要的东西。另一方面,我认为无论您使用什么技术来隐藏应用程序但保留它,都会调用应用程序生命周期方法,因此没有必要仅针对这种情况添加保存逻辑。无论如何,你的应用都需要在所有正确的位置使用该代码。
311赞 ekawas 6/30/2010 #2

删除密钥侦听器,或在有 .trueKEY_BACK

您只需要以下命令即可获取后退键(确保不要调用 super in)。onBackPressed()

此外,如果您计划在后台运行服务,请务必查看并确保有持续的通知,否则 Android 会在需要释放内存时终止您的服务。startForeground()

@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);
}
85赞 Teo Inke 4/25/2015 #3

仅使用一行代码即可更轻松地实现它:

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

评论

3赞 Shadoninja 4/6/2017
这应该是公认的答案。这完全符合问题的要求,并且使用了干净的内置功能。
0赞 Farrukh Faizy 5/3/2017
谢谢:)你能详细阐述一下它背后的概念吗?
1赞 Squirrelkiller 7/25/2017
您只需重写 onBackPressed() 事件,使其将活动移到后面。
1赞 IgorGanapolsky 8/25/2017
当您从主屏幕重新启动应用程序时,此解决方案不会恢复活动(如果任务堆栈上有其他活动)。
0赞 user28775 11/27/2023
它说这现在已经折旧了
16赞 androCoder-BD 5/18/2016 #4

只需这样做..

@Override
public void onBackPressed() {
    //super.onBackPressed();
}

注释掉 //super.onBackPressed();会做诀窍

评论

1赞 ToolmakerSteve 9/22/2016
一个有用的观察,但这不会导致后退按钮什么都不做,就好像它被坏了一样吗?这不是一件好事 - 让用户感到困惑和烦人。恕我直言,必须添加另一个答案的逻辑,以充当有问题的主页按钮。公认的答案提到他们故意不调用超级方法。
0赞 androCoder-BD 12/2/2016
是的,你是绝对正确的。它只会覆盖后退按钮,并且在您在那里放置一些逻辑之前不会执行任何操作。可能是双击按钮关闭应用程序的条件,或者您只想禁用正在进行的操作(进度对话框)等,但它完全符合要求。
8赞 Thakur 5/8/2017 #5

试试这个:

@Override
public void onBackPressed() {
    finish();
}
4赞 Ferran Maylinch 7/25/2017 #6

以防万一您想处理后退按钮(位于手机底部)和主页按钮(操作栏左侧的按钮)的行为,我在项目中使用的此自定义活动可能会对您有所帮助。

import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.view.MenuItem;

/**
 * Activity where the home action bar button behaves like back by default
 */
public class BackActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setupHomeButton();
    }

    private void setupHomeButton() {
        final ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.setDisplayHomeAsUpEnabled(true);
            actionBar.setHomeButtonEnabled(true);
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                onMenuHomePressed();
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    protected void onMenuHomePressed() {
        onBackPressed();
    }
}

在活动中使用示例:

public class SomeActivity extends BackActivity {

    // ....

    @Override
    public void onBackPressed()
    {
        // Example of logic
        if ( yourConditionToOverride ) {
            // ... do your logic ...
        } else {
            super.onBackPressed();
        }
    }    
}
2赞 user3156040 1/10/2019 #7
@Override
public void onBackPressed() {
// Put your code here.
}

//I had to go back to the dashboard. Hence,

@Override
public void onBackPressed() {
    Intent intent = new Intent(this,Dashboard.class);
    startActivity(intent);
}
Just write this above or below the onCreate Method(within the class)
1赞 solaza 2/12/2020 #8

在 Kotlin 中:

val callback = requireActivity().onBackPressedDispatcher.addCallback(this) {
    // Handle the back button event
}

有关更多信息,您可以查看此内容

还有一个关于在 Kotlin 中覆盖后退按钮的具体问题

0赞 RK_DUDE02 9/11/2020 #9

看起来我很晚了,但对于那些需要切换到新屏幕并清除后退按钮堆栈的人来说,这是一个非常简单的解决方案。

startActivity(new Intent(this,your-new-screen.class));
finishAffinity();

finishAffinity();方法清除后退按钮堆栈。

-2赞 Tasos Fourlakis 10/29/2020 #10

就这样做

@Override
public void onBackPressed() {
    super.onBackPressed();
}

评论

0赞 YLS 10/30/2020
这将退出或从应用程序进入上一个屏幕,而不是主页