有没有一种方法可以onBackPressed()
像在Android Activity中实现的方式一样在Android Fragment中实现?
由于Fragment的生命周期没有onBackPressed()
。onBackPressed()
在Android 3.0片段中是否还有其他替代方法可以替代?
有没有一种方法可以onBackPressed()
像在Android Activity中实现的方式一样在Android Fragment中实现?
由于Fragment的生命周期没有onBackPressed()
。onBackPressed()
在Android 3.0片段中是否还有其他替代方法可以替代?
Answers:
我以这种方式解决onBackPressed
了Activity中的覆盖问题。所有FragmentTransaction
都是addToBackStack
之前提交:
@Override
public void onBackPressed() {
int count = getSupportFragmentManager().getBackStackEntryCount();
if (count == 0) {
super.onBackPressed();
//additional code
} else {
getSupportFragmentManager().popBackStack();
}
}
我认为最好的解决方案是:
创建简单的界面:
public interface IOnBackPressed {
/**
* If you return true the back press will not be taken into account, otherwise the activity will act naturally
* @return true if your processing has priority if not false
*/
boolean onBackPressed();
}
在你的活动中
public class MyActivity extends Activity {
@Override public void onBackPressed() {
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.main_container);
if (!(fragment instanceof IOnBackPressed) || !((IOnBackPressed) fragment).onBackPressed()) {
super.onBackPressed();
}
} ...
}
最后在您的片段中:
public class MyFragment extends Fragment implements IOnBackPressed{
@Override
public boolean onBackPressed() {
if (myCondition) {
//action not popBackStack
return true;
} else {
return false;
}
}
}
interface IOnBackPressed {
fun onBackPressed(): Boolean
}
class MyActivity : AppCompatActivity() {
override fun onBackPressed() {
val fragment =
this.supportFragmentManager.findFragmentById(R.id.main_container)
(fragment as? IOnBackPressed)?.onBackPressed()?.not()?.let {
super.onBackPressed()
}
}
}
class MyFragment : Fragment(), IOnBackPressed {
override fun onBackPressed(): Boolean {
return if (myCondition) {
//action not popBackStack
true
} else {
false
}
}
}
R.id.main_container
啊 那是FragmentPager的ID吗?
.?
)和强制使用非null(!!
)可能会导致NPE- 强制转换并不总是安全的。我宁愿写if ((fragment as? IOnBackPressed)?.onBackPressed()?.not() == true) { ... }
些文字还是写些kotliney(fragment as? IOnBackPressed)?.onBackPressed()?.not()?.let { ... }
.onBackPressed()?.takeIf { !it }?.let{...}
吗?.not()
只是返回相反的值。
val fragment = this.supportFragmentManager.findFragmentById(R.id.flContainer) as? NavHostFragment val currentFragment = fragment?.childFragmentManager?.fragments?.get(0) as? IOnBackPressed currentFragment?.onBackPressed()?.takeIf { !it }?.let{ super.onBackPressed() }
这适用于使用Kotlin和NavigationController的人
根据@HaMMeRed的回答,这里是伪代码,它应该如何工作。可以说您的主活动被调用了BaseActivity
,它具有子片段(例如在SlidingMenu lib示例中)。步骤如下:
首先,我们需要创建接口和实现其接口的类以具有通用方法
创建类界面 OnBackPressedListener
public interface OnBackPressedListener {
public void doBack();
}
创建实施技能的课程 OnBackPressedListener
public class BaseBackPressedListener implements OnBackPressedListener {
private final FragmentActivity activity;
public BaseBackPressedListener(FragmentActivity activity) {
this.activity = activity;
}
@Override
public void doBack() {
activity.getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
从现在开始,我们将处理我们的代码BaseActivity
及其片段
在课程顶部创建私人侦听器 BaseActivity
protected OnBackPressedListener onBackPressedListener;
创建方法以设置侦听器 BaseActivity
public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
this.onBackPressedListener = onBackPressedListener;
}
在重写中onBackPressed
实现类似的东西
@Override
public void onBackPressed() {
if (onBackPressedListener != null)
onBackPressedListener.doBack();
else
super.onBackPressed();
在您的片段中,onCreateView
您应该添加我们的监听器
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
activity = getActivity();
((BaseActivity)activity).setOnBackPressedListener(new BaseBackPressedListener(activity));
View view = ... ;
//stuff with view
return view;
}
瞧,现在当您在片段中单击返回时,您应该捕获自定义的返回方法。
onBackPressed()
当按下后退按钮时,显示的是哪个片段?
((BaseActivity)activity).setOnBackPressedListener(new OnBackpressedListener(){ public void doBack() { //...your stuff here }});
这对我有用:https://stackoverflow.com/a/27145007/3934111
@Override
public void onResume() {
super.onResume();
if(getView() == null){
return;
}
getView().setFocusableInTouchMode(true);
getView().requestFocus();
getView().setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK){
// handle back button's click listener
return true;
}
return false;
}
});
}
如果您想要这种功能,则需要在活动中覆盖它,然后将YourBackPressed
接口添加到所有片段中,每当按下后退按钮时,便会在相关片段上调用该接口。
编辑:我想补充我以前的答案。
如果今天要这样做,那么如果我希望其他面板一起更新到主/主要内容面板,则可以使用广播,也可以使用有序广播。
LocalBroadcastManager
支持库中的可以帮助您解决此问题,您只需发送广播onBackPressed
并订阅您关心的片段即可。我认为“消息传递”是一个更加分离的实现,并且可以更好地扩展,因此这将是我现在的正式实现建议。只需将Intent
的操作用作您邮件的过滤器即可。发送您新创建的内容ACTION_BACK_PRESSED
,从您的活动中发送它,并在相关片段中进行监听。
LocalBroadcastManager
不能进行有序广播
这些都不容易实现,也不会以最佳方式发挥作用。
片段有一个可以调用onDetach的方法来完成这项工作。
@Override
public void onDetach() {
super.onDetach();
PUT YOUR CODE HERE
}
这将完成工作。
isRemoving()
按照stackoverflow.com/a/27103891/2914140中的描述进行添加。
如果您使用的是androidx.appcompat:appcompat:1.1.0
或更高版本,则可以将OnBackPressedCallback
片段添加到片段,如下所示
requireActivity()
.onBackPressedDispatcher
.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
Log.d(TAG, "Fragment back pressed invoked")
// Do custom work here
// if you want onBackPressed() to be called as normal afterwards
if (isEnabled) {
isEnabled = false
requireActivity().onBackPressed()
}
}
}
)
参见https://developer.android.com/guide/navigation/navigation-custom-back
androidx-core-ktx
,则可以使用requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) { /* code to be executed when back is pressed */ }
LifecycleOwner
应在此示例中添加参数。如果没有它,handleBackPressed()
则按下后退按钮将调用之后启动的任何片段。
只需addToBackStack
在片段之间进行过渡时添加即可,如下所示:
fragmentManager.beginTransaction().replace(R.id.content_frame,fragment).addToBackStack("tag").commit();
如果您编写addToBackStack(null)
,它将自行处理,但是如果您提供标记,则应手动处理。
由于这个问题和一些答案已经超过五年了,所以让我分享我的解决方案。这是@oyenigun的回答的后续跟进和现代化
更新: 在本文的底部,我添加了一个使用抽象Fragment扩展的替代实现,该扩展根本不涉及Activity,这对于具有更复杂的片段层次结构且涉及嵌套片段且需要不同返回行为的任何人都是有用的。
我需要实现此功能,因为我使用的某些片段具有较小的视图,我希望通过“后退”按钮将其关闭,例如弹出的小信息视图等,但这对任何需要覆盖行为的人都非常有用。片段内的返回按钮。
首先,定义一个接口
public interface Backable {
boolean onBackPressed();
}
我称这个接口Backable
(我是命名约定的顽强支持者),只有一个onBackPressed()
必须返回boolean
值的方法。我们需要强制使用布尔值,因为我们需要知道后退按钮的按下是否“吸收”了后退事件。返回true
表示已执行操作,不需要采取进一步的操作,否则,false
表示仍必须执行默认的返回操作。此接口应该是它自己的文件(最好在名为的单独程序包中interfaces
)。请记住,将您的类分为多个包是一种好习惯。
二,找到最上面的片段
我创建了一个方法,该方法返回Fragment
后退堆栈中的最后一个对象。我使用标签...如果您使用ID,请进行必要的更改。我在处理导航状态等的实用程序类中有此静态方法,但是,当然要把它放在最适合您的位置。为了教育,我将我的课程放在NavUtils
。
public static Fragment getCurrentFragment(Activity activity) {
FragmentManager fragmentManager = activity.getFragmentManager();
if (fragmentManager.getBackStackEntryCount() > 0) {
String lastFragmentName = fragmentManager.getBackStackEntryAt(
fragmentManager.getBackStackEntryCount() - 1).getName();
return fragmentManager.findFragmentByTag(lastFragmentName);
}
return null;
}
确保后退堆栈计数大于0,否则ArrayOutOfBoundsException
可能会在运行时引发。如果不大于0,则返回null。稍后我们将检查空值...
三,零碎实施
Backable
在需要覆盖后退按钮行为的任何片段中实现接口。添加实现方法。
public class SomeFragment extends Fragment implements
FragmentManager.OnBackStackChangedListener, Backable {
...
@Override
public boolean onBackPressed() {
// Logic here...
if (backButtonShouldNotGoBack) {
whateverMethodYouNeed();
return true;
}
return false;
}
}
在onBackPressed()
替代中,放入您需要的任何逻辑。如果您希望后退按钮不弹出后退堆栈(默认行为),请返回true,表明您的后退事件已被吸收。否则,返回false。
最后,在您的活动中...
重写该onBackPressed()
方法并向其中添加以下逻辑:
@Override
public void onBackPressed() {
// Get the current fragment using the method from the second step above...
Fragment currentFragment = NavUtils.getCurrentFragment(this);
// Determine whether or not this fragment implements Backable
// Do a null check just to be safe
if (currentFragment != null && currentFragment instanceof Backable) {
if (((Backable) currentFragment).onBackPressed()) {
// If the onBackPressed override in your fragment
// did absorb the back event (returned true), return
return;
} else {
// Otherwise, call the super method for the default behavior
super.onBackPressed();
}
}
// Any other logic needed...
// call super method to be sure the back button does its thing...
super.onBackPressed();
}
我们在后栈中获取当前片段,然后进行空检查并确定它是否实现了我们的Backable
接口。如果是这样,请确定事件是否被吸收。如果是这样,我们就结束了onBackPressed()
并且可以返回。否则,将其视为正常的后按,然后调用super方法。
不参与活动的第二种选择
有时,您根本不希望Activity处理该事件,而需要直接在片段中处理它。但是谁说您不能通过 Back Press API使用Fragments?只需将您的片段扩展到一个新的类。
创建一个扩展Fragment并实现View.OnKeyListner
接口的抽象类。
import android.app.Fragment;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
public abstract class BackableFragment extends Fragment implements View.OnKeyListener {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
view.setFocusableInTouchMode(true);
view.requestFocus();
view.setOnKeyListener(this);
}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
onBackButtonPressed();
return true;
}
}
return false;
}
public abstract void onBackButtonPressed();
}
如您所见,任何扩展的片段都BackableFragment
将使用该View.OnKeyListener
界面自动捕获反向点击。只需使用标准逻辑onBackButtonPressed()
从已实现onKey()
方法中调用抽象方法即可识别按下后退按钮。如果您需要注册除“后退”按钮以外的其他按键单击,请确保super
在覆盖onKey()
片段时确保调用该方法,否则将覆盖抽象中的行为。
使用简单,只需扩展和实现:
public class FragmentChannels extends BackableFragment {
...
@Override
public void onBackButtonPressed() {
if (doTheThingRequiringBackButtonOverride) {
// do the thing
} else {
getActivity().onBackPressed();
}
}
...
}
由于onBackButtonPressed()
超类中的方法是抽象的,因此扩展后必须实现onBackButtonPressed()
。它void
之所以返回,是因为它只需要在fragment类中执行一个动作,而无需将新闻的吸收传递回Activity。如果不需要使用后退按钮执行任何操作,请确保确实调用了Activity onBackPressed()
方法,否则,将禁用后退按钮...而您不希望这样做!
注意事项 如您所见,这会将关键侦听器设置为片段的根视图,我们需要对其进行重点关注。如果在扩展此类的片段中包含涉及的编辑文本(或其他任何窃取焦点的视图)(或其他内部片段或具有相同内容的视图),则需要单独处理。有一篇很好的文章介绍了如何扩展EditText从而使注意力不再集中在背面印刷上。
我希望有人觉得这有用。快乐的编码。
super.onBackPressed();
两次电话?
currentFragment
。如果该片段不为null,并且该片段实现该Backable
接口,则不执行任何操作。如果片段不为null且未实现Backable
,则调用super方法。如果片段为空,则跳至上一个超级调用。
currentFragment
不为null且为Backable的实例且被分离(我们按下back
按钮并关闭片段)的情况下,第一次出现super.onBackPressed();
是,然后是第二个。
解决方案很简单:
1)如果您具有所有片段都扩展的基本片段类,则将此代码添加到其类中,否则创建此类基本片段类
/*
* called when on back pressed to the current fragment that is returned
*/
public void onBackPressed()
{
// add code in super class when override
}
2)在您的Activity类中,如下重写onBackPressed:
private BaseFragment _currentFragment;
@Override
public void onBackPressed()
{
super.onBackPressed();
_currentFragment.onBackPressed();
}
3)在您的Fragment类中,添加所需的代码:
@Override
public void onBackPressed()
{
setUpTitle();
}
onBackPressed()
使片段与活动分离。
根据@Sterling Diaz的回答,我认为他是对的。但是有些情况是错误的。(例如,旋转屏幕)
因此,我认为我们可以检测出是否isRemoving()
实现目标。
您可以在onDetach()
或编写它onDestroyView()
。是工作。
@Override
public void onDetach() {
super.onDetach();
if(isRemoving()){
// onBackPressed()
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
if(isRemoving()){
// onBackPressed()
}
}
好吧,我是这样做的,它对我有用
简单的界面
FragmentOnBackClickInterface.java
public interface FragmentOnBackClickInterface {
void onClick();
}
示例实施
MyFragment.java
public class MyFragment extends Fragment implements FragmentOnBackClickInterface {
// other stuff
public void onClick() {
// what you want to call onBackPressed?
}
然后在活动中覆盖onBackPressed
@Override
public void onBackPressed() {
int count = getSupportFragmentManager().getBackStackEntryCount();
List<Fragment> frags = getSupportFragmentManager().getFragments();
Fragment lastFrag = getLastNotNull(frags);
//nothing else in back stack || nothing in back stack is instance of our interface
if (count == 0 || !(lastFrag instanceof FragmentOnBackClickInterface)) {
super.onBackPressed();
} else {
((FragmentOnBackClickInterface) lastFrag).onClick();
}
}
private Fragment getLastNotNull(List<Fragment> list){
for (int i= list.size()-1;i>=0;i--){
Fragment frag = list.get(i);
if (frag != null){
return frag;
}
}
return null;
}
您应该将界面添加到项目中,如下所示;
public interface OnBackPressed {
void onBackPressed();
}
然后,您应该在片段上实现此接口;
public class SampleFragment extends Fragment implements OnBackPressed {
@Override
public void onBackPressed() {
//on Back Pressed
}
}
您可以在活动onBackPressed事件下触发此onBackPressed事件,如下所示;
public class MainActivity extends AppCompatActivity {
@Override
public void onBackPressed() {
Fragment currentFragment = getSupportFragmentManager().getFragments().get(getSupportFragmentManager().getBackStackEntryCount() - 1);
if (currentFragment instanceof OnBackPressed) {
((OnBackPressed) currentFragment).onBackPressed();
}
super.onBackPressed();
}
}
getActivity().onBackPressed();
它,因为它将调用异常:“ java.lang.StackOverflowError:堆栈大小为8MB”。
这只是一个小代码,可以解决问题:
getActivity().onBackPressed();
希望它可以帮助某人:)
如果您使用EventBus,则可能是更简单的解决方案:
在您的片段中:
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
EventBus.getDefault().register(this);
}
@Override
public void onDetach() {
super.onDetach();
EventBus.getDefault().unregister(this);
}
// This method will be called when a MessageEvent is posted
public void onEvent(BackPressedMessage type){
getSupportFragmentManager().popBackStack();
}
在您的Activity类中,您可以定义:
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
// This method will be called when a MessageEvent is posted
public void onEvent(BackPressedMessage type){
super.onBackPressed();
}
@Override
public void onBackPressed() {
EventBus.getDefault().post(new BackPressedMessage(true));
}
BackPressedMessage.java只是一个POJO对象
这是超级干净的,并且没有接口/实现麻烦。
这是我的解决方案:
在MyActivity.java中:
public interface OnBackClickListener {
boolean onBackClick();
}
private OnBackClickListener onBackClickListener;
public void setOnBackClickListener(OnBackClickListener onBackClickListener) {
this.onBackClickListener = onBackClickListener;
}
@Override
public void onBackPressed() {
if (onBackClickListener != null && onBackClickListener.onBackClick()) {
return;
}
super.onBackPressed();
}
并在片段中:
((MyActivity) getActivity()).setOnBackClickListener(new MyActivity.OnBackClickListener() {
@Override
public boolean onBackClick() {
if (condition) {
return false;
}
// some codes
return true;
}
});
爪哇
public class MyFragment extends Fragment {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// This callback will only be called when MyFragment is at least Started.
OnBackPressedCallback callback = new OnBackPressedCallback(true /* enabled by default */) {
@Override
public void handleOnBackPressed() {
// Handle the back button event
}
});
requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
// The callback can be enabled or disabled here or in handleOnBackPressed()
}
...
}
科特林
class MyFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// This callback will only be called when MyFragment is at least Started.
val callback = requireActivity().onBackPressedDispatcher.addCallback(this) {
// Handle the back button event
}
// The callback can be enabled or disabled here or in the lambda
}
...
}
@Override
public void onResume() {
super.onResume();
getView().setFocusableInTouchMode(true);
getView().requestFocus();
getView().setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
// handle back button
replaceFragmentToBackStack(getActivity(), WelcomeFragment.newInstance(bundle), tags);
return true;
}
return false;
}
});
}
public class MyActivity extends Activity {
protected OnBackPressedListener onBackPressedListener;
public interface OnBackPressedListener {
void doBack();
}
public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
this.onBackPressedListener = onBackPressedListener;
}
@Override
public void onBackPressed() {
if (onBackPressedListener != null)
onBackPressedListener.doBack();
else
super.onBackPressed();
}
@Override
protected void onDestroy() {
onBackPressedListener = null;
super.onDestroy();
}
}
在您的片段中添加以下内容,不要忘记实现mainactivity的界面。
public class MyFragment extends Framgent implements MyActivity.OnBackPressedListener {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
((MyActivity) getActivity()).setOnBackPressedListener(this);
}
@Override
public void doBack() {
//BackPressed in activity will call this;
}
}
在我的解决方案中(科特琳);
我使用onBackAlternative功能作为一个参数BaseActivity。
基础活动
abstract class BaseActivity {
var onBackPressAlternative: (() -> Unit)? = null
override fun onBackPressed() {
if (onBackPressAlternative != null) {
onBackPressAlternative!!()
} else {
super.onBackPressed()
}
}
}
我有一组功能onBackPressAlternative上BaseFragment。
基本片段
abstract class BaseFragment {
override fun onStart() {
super.onStart()
...
setOnBackPressed(null) // Add this
}
//Method must be declared as open, for overriding in child class
open fun setOnBackPressed(onBackAlternative: (() -> Unit)?) {
(activity as BaseActivity<*, *>).onBackPressAlternative = onBackAlternative
}
}
然后,我的onBackPressAlternative准备在片段上使用。
子片段
override fun setOnBackPressed(onBackAlternative: (() -> Unit)?) {
(activity as BaseActivity<*, *>).onBackPressAlternative = {
// TODO Your own custom onback function
}
}
不要实现ft.addToBackStack()方法,这样当您按下“后退”按钮时,您的活动将完成。
proAddAccount = new ProfileAddAccount();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, proAddAccount);
//fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
只需按照以下步骤操作:
总是在添加片段时
fragmentTransaction.add(R.id.fragment_container, detail_fragment, "Fragment_tag").addToBackStack(null).commit();
然后在主活动中,覆盖 onBackPressed()
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
} else {
finish();
}
要处理您应用中的后退按钮,
Fragment f = getActivity().getSupportFragmentManager().findFragmentByTag("Fragment_tag");
if (f instanceof FragmentName) {
if (f != null)
getActivity().getSupportFragmentManager().beginTransaction().remove(f).commit()
}
而已!
在活动生命周期中,当我们使用FragmentActivity或AppCompatActivity时,总是android后退按钮处理FragmentManager事务。
要处理后退栈,我们不需要处理其后退栈计数或标记任何内容,但在添加或替换片段时,我们应保持专注。请找到以下片段来处理后退按钮情况,
public void replaceFragment(Fragment fragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (!(fragment instanceof HomeFragment)) {
transaction.addToBackStack(null);
}
transaction.replace(R.id.activity_menu_fragment_container, fragment).commit();
}
在这里,我不会为我的主页片段添加回堆栈,因为它是我的应用程序的主页。如果将addToBackStack添加到HomeFragment,则应用程序将主动删除所有帧,然后我们将得到空白屏幕,因此我保持以下条件,
if (!(fragment instanceof HomeFragment)) {
transaction.addToBackStack(null);
}
现在,您可以看到先前在活动上添加的片段,并且应用程序将在到达HomeFragment时退出。您还可以查看以下片段。
@Override
public void onBackPressed() {
if (mDrawerLayout.isDrawerOpen(Gravity.LEFT)) {
closeDrawer();
} else {
super.onBackPressed();
}
}
片段:创建 一个BaseFragment放置方法:
public boolean onBackPressed();
活动:
@Override
public void onBackPressed() {
List<Fragment> fragments = getSupportFragmentManager().getFragments();
if (fragments != null) {
for (Fragment fragment : fragments) {
if (!fragment.isVisible()) continue;
if (fragment instanceof BaseFragment && ((BaseFragment) fragment).onBackPressed()) {
return;
}
}
}
super.onBackPressed();
}
您的活动将遍历附着的可见片段,并在每个片段上调用onBackPressed(),如果其中一个返回“ true”,则中止操作(这意味着该片段已被处理,因此无进一步操作)。
根据AndroidX发行说明,androidx.activity 1.0.0-alpha01
已发布并引入ComponentActivity
了现有FragmentActivity
和的新基类AppCompatActivity
。此版本为我们带来了一个新功能:
现在,您可以注册一个OnBackPressedCallback
Via addOnBackPressedCallback
来接收onBackPressed()
回调,而无需在您的活动中覆盖该方法。
您可以在活动中注册片段以处理反向新闻:
interface BackPressRegistrar {
fun registerHandler(handler: BackPressHandler)
fun unregisterHandler(handler: BackPressHandler)
}
interface BackPressHandler {
fun onBackPressed(): Boolean
}
用法:
private val backPressHandler = object : BackPressHandler {
override fun onBackPressed(): Boolean {
showClosingWarning()
return false
}
}
override fun onResume() {
super.onResume()
(activity as? BackPressRegistrar)?.registerHandler(backPressHandler)
}
override fun onStop() {
(activity as? BackPressRegistrar)?.unregisterHandler(backPressHandler)
super.onStop()
}
class MainActivity : AppCompatActivity(), BackPressRegistrar {
private var registeredHandler: BackPressHandler? = null
override fun registerHandler(handler: BackPressHandler) { registeredHandler = handler }
override fun unregisterHandler(handler: BackPressHandler) { registeredHandler = null }
override fun onBackPressed() {
if (registeredHandler?.onBackPressed() != false) super.onBackPressed()
}
}
现在,通过片段内的回调,通过处理onBackPressed提供自定义的反向导航更加容易。
class MyFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val onBackPressedCallback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (true == conditionForCustomAction) {
myCustomActionHere()
} else NavHostFragment.findNavController(this@MyFragment).navigateUp();
}
}
requireActivity().onBackPressedDispatcher.addCallback(
this, onBackPressedCallback
)
...
}
如果要基于某些条件执行默认的后退操作,则可以使用:
NavHostFragment.findNavController(this@MyFragment).navigateUp();
在片段的onCreate方法内添加以下内容:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
OnBackPressedCallback callback = new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
//Handle the back pressed
}
};
requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
}
最好的解决方案
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;
public class BaseActivity extends AppCompatActivity {
@Override
public void onBackPressed() {
FragmentManager fm = getSupportFragmentManager();
for (Fragment frag : fm.getFragments()) {
if (frag == null) {
super.onBackPressed();
finish();
return;
}
if (frag.isVisible()) {
FragmentManager childFm = frag.getChildFragmentManager();
if (childFm.getFragments() == null) {
super.onBackPressed();
finish();
return;
}
if (childFm.getBackStackEntryCount() > 0) {
childFm.popBackStack();
return;
}
else {
fm.popBackStack();
if (fm.getFragments().size() <= 1) {
finish();
}
return;
}
}
}
}
}