简体   繁体   English

Activity 中 OnBackPressedCallback 的默认行为?

[英]Default Behavior for OnBackPressedCallback in Activity?

I would like to implement the OnBackPressedCallback detailed in Navigation Components in my app.我想在我的应用程序中实现导航组件中详述的OnBackPressedCallback The documentation is very clear on how to add this custom behavior in fragments, and works quite well.该文档非常清楚如何在片段中添加此自定义行为,并且效果很好。 After reading the linked documentation, it states that you should avoid overriding onBackPressed in your activity.阅读链接的文档后,它指出您应该避免在您的活动中覆盖onBackPressed My current onBackPressed method looks something like this:我当前的onBackPressed方法如下所示:

@Override
public void onBackPressed() {

    if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
      drawerLayout.closeDrawer(GravityCompat.START);
    } else if (shouldOverrideBackPressed()) {
      navigationController.popBackStack(R.id.main_fragment, false);
    } else {
      super.onBackPressed();
    }
}

The last line super.onBackPressed();最后一行super.onBackPressed(); is what I'm not clear about.是什么我不清楚。 How do I retain the default behavior for the back button in an activity while implementing the OnBackPressedCallback ?如何在实现OnBackPressedCallback保留活动中后退按钮的默认行为? This is my current implementation:这是我目前的实现:

getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
  @Override
  public void handleOnBackPressed() {
    if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
      drawerLayout.closeDrawer(GravityCompat.START);
    } else if (shouldOverrideBackPressed()) {
      navigationController.popBackStack(R.id.main_fragment, false);
    } else {
      setEnabled(false);
      MainActivity.this.onBackPressed();
    }
  }
});

If I don't include the setEnabled(false);如果我不包括setEnabled(false); line, then I get a Stack Overflow error, which makes sense.行,然后我收到堆栈溢出错误,这是有道理的。 But surely there is a more elegant way to provide default behavior?但是肯定有一种更优雅的方式来提供默认行为吗?

You shouldn't be putting all of that logic in one OnBackPressedCallback .您不应该将所有这些逻辑放在一个OnBackPressedCallback Instead, each case should be its own callback that is only enabled when it is the one that should be handling the back pressed.相反,每个 case 都应该是它自己的回调,只有在它应该处理 backpressed 时才启用它。

You should not be calling onBackPressed() , etc in handleOnBackPressed() .应该调用onBackPressed()等在handleOnBackPressed() An important part of the contract is that when you get a callback to handleOnBackPressed() , you must handle the back pressed button there.契约的一个重要部分是,当您收到handleOnBackPressed()的回调时,您必须处理那里的后退按钮。 That's precisely why you have control over exactly when the callback is enabled or not.这正是您可以准确控制何时启用回调的原因。

This means you should create one OnBackPressedCallback for your override behavior (although you should probably not being doing that with Navigation anyways) and another for the DrawerLayout that uses a DrawerListener for enabling and disabling the callback:这意味着您应该为您的覆盖行为创建一个OnBackPressedCallback (尽管您可能无论如何都不应该使用 Navigation 这样做),并为使用DrawerListener启用和禁用回调的DrawerLayout另一个:

OnBackPressedDispatcher dispatcher = getOnBackPressedDispatcher();

final OnBackPressedCallback overrideCallback = new OnBackPressedCallback(false) {
    @Override
    public void handleOnBackPressed() {
        navigationController.popBackStack(R.id.main_fragment, false);
    }
};
// Whenever your `shouldOverrideBackPressed()` changes, you need to
// call setEnabled(true) or setEnabled(false) so that callback
// is only called exactly when it needs to handle the back button

// Add this one first since they are called in reverse order
dispatcher.addCallback(this, overrideCallback);

// Now set up the DrawerLayout's callback
final DrawerLayout drawerLayout = findViewById(R.id.your_drawer_layout);
final OnBackPressedCallback drawerCallback = new OnBackPressedCallback(
        drawerLayout.isDrawerOpen(GravityCompat.START)) {
    @Override
    public void handleOnBackPressed() {
        // Unconditionally close the drawer when it is open
        drawerLayout.closeDrawer(GravityCompat.START);
    }
};
// Now add a listener so that this callback is only
// enabled when the drawer is open
drawerLayout.addDrawerListener(new DrawerLayout.SimpleDrawerListener() {
    @Override
    public void onDrawerClosed(View drawerView) {
        // Assume you only have one drawer
        drawerCallback.setEnabled(false);
    }

    @Override
    public void onDrawerOpened(View drawerView) {
        // Assume you only have one drawer
        drawerCallback.setEnabled(true);
    }
});
// Add it last so that it gets called before the overrideCallback
dispatcher.addCallback(this, drawerCallback);

Of course, if you're overriding things at the Activity level, there's no downside to keeping your logic in onBackPressed() - as per the documentation , any callbacks registered from Fragments, etc. will correctly be called when you call super.onBackPressed() .当然,如果您在 Activity 级别覆盖内容,那么将逻辑保留在onBackPressed()没有任何缺点 - 根据文档,当您调用super.onBackPressed()时,将从 Fragment 等注册的任何回调正确调用super.onBackPressed()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM