如何在片段中实现onBackPressed() ?

是否有一种方法,我们可以实现onBackPressed()在Android片段类似的方式,我们实现在Android活动?

因为片段生命周期没有onBackPressed()。在android3.0的片段中,是否有其他替代方法来超越onBackPressed() ?

636758 次浏览

如果你想要那种功能,你需要在你的活动中覆盖它,然后给你所有的片段添加一个YourBackPressed接口,当你按下后退按钮时,你就会在相关的片段上调用这个接口。

编辑:我想补充我之前的答案。

如果我今天要这样做,我将使用广播,或者如果我希望其他面板同步更新到主/主内容面板,则可能使用有序广播。

支持库中的LocalBroadcastManager可以帮助解决这个问题,你只需要在onBackPressed中发送广播,并在你的片段中订阅。我认为Messaging是一种更加解耦的实现,可伸缩性更好,所以它是我现在的官方实现建议。只需使用Intent的动作作为消息的过滤器。发送你新创建的ACTION_BACK_PRESSED,从你的活动中发送它,并在相关片段中监听它。

根据@ hammer的回答,这里是伪代码,它应该如何工作。 假设你的主活动名为BaseActivity,它有子片段(就像SlidingMenu lib例子一样)。 下面是步骤:

首先,我们需要创建接口和类,实现它的接口具有泛型方法

  1. 创建类接口OnBackPressedListener

    public interface OnBackPressedListener {
    public void doBack();
    }
    
  2. Create class which implements skills of 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);
    }
    }
    
  3. Since now, we will work on our code BaseActivity and its fragments

  4. Create private listener on top of your class BaseActivity

    protected OnBackPressedListener onBackPressedListener;
    
  5. create method to set listener in BaseActivity

    public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
    this.onBackPressedListener = onBackPressedListener;
    }
    
  6. in override onBackPressed implement something like that

    @Override
    public void onBackPressed() {
    if (onBackPressedListener != null)
    onBackPressedListener.doBack();
    else
    super.onBackPressed();
    
  7. in your fragment in onCreateView you should add our listener

    @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;
    }
    

Voila, now when you click back in fragment you should catch your custom on back method.

只需添加addToBackStack当你在你的片段之间过渡,如下所示:

fragmentManager.beginTransaction().replace(R.id.content_frame,fragment).addToBackStack("tag").commit();

如果你写addToBackStack(null),它会自己处理,但如果你给了一个标签,你应该手动处理它。

以下是我对这个问题的解决方案:

活动A:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);


if(requestCode == REQUEST_CODE)
{
if(resultCode == Activity.RESULT_OK)
{
tvTitle.setText(data.getExtras().getString("title", ""));
}
}
}

活动B:

@Override
public void onBackPressed()
{
setResult(Activity.RESULT_OK, getIntent());


super.onBackPressed();
}

活动b保存片段。

在片段:

private void setText(String text)
{
Intent intent = new Intent();
intent.putExtra("title", text);
getActivity().setIntent(intent);
}

通过这种方式,活动A中的意图对象“data”将从片段中获取字符串

不要实现ft.addToBackStack()方法,这样当你按下返回按钮时,你的活动就会结束。

proAddAccount = new ProfileAddAccount();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, proAddAccount);
//fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();

我有同样的问题,我为它创建了一个新的侦听器,并在我的片段中使用。

1 -你的活动应该有一个监听器接口和一个监听器列表

你应该实现添加和删除监听器的方法

你应该重写onBackPressed方法来检查监听器是否使用了背按

public class MainActivity ... {


/**
* Back press listener list. Used for notifying fragments when onBackPressed called
*/
private Stack<BackPressListener> backPressListeners = new Stack<BackPressListener>();




...


/**
* Adding new listener to back press listener stack
* @param backPressListener
*/
public void addBackPressListener(BackPressListener backPressListener) {
backPressListeners.add(backPressListener);
}


/**
* Removing the listener from back press listener stack
* @param backPressListener
*/
public void removeBackPressListener(BackPressListener backPressListener) {
backPressListeners.remove(backPressListener);
}




// Overriding onBackPressed to check that is there any listener using this back press
@Override
public void onBackPressed() {


// checks if is there any back press listeners use this press
for(BackPressListener backPressListener : backPressListeners) {
if(backPressListener.onBackPressed()) return;
}


// if not returns in the loop, calls super onBackPressed
super.onBackPressed();
}


}

4 -你的片段必须实现接口的背压

5 -你需要添加片段作为背按的监听器

如果片段使用这个背压,你应该从onBackPressed返回true

7 -重要-你必须删除片段从列表onDestroy

public class MyFragment extends Fragment implements MainActivity.BackPressListener {




...


@Override
public void onAttach(Activity activity) {
super.onCreate(savedInstanceState);


// adding the fragment to listener list
((MainActivity) activity).addBackPressListener(this);
}


...


@Override
public void onDestroy() {
super.onDestroy();


// removing the fragment from the listener list
((MainActivity) getActivity()).removeBackPressListener(this);
}


...


@Override
public boolean onBackPressed() {


// you should check that if this fragment is the currently used fragment or not
// if this fragment is not used at the moment you should return false
if(!isThisFragmentVisibleAtTheMoment) return false;


if (isThisFragmentUsingBackPress) {
// do what you need to do
return true;
}
return false;
}
}

有一个Stack来代替ArrayList,以便能够从最新的片段开始。在向后台堆栈添加片段时也可能出现问题。所以你需要检查碎片是否可见,而使用背压。否则,其中一个片段将使用事件,并且最新的片段将不会在背按时关闭。

我希望这能解决所有人的问题。

这些都不容易实现,也不会以最佳方式发挥作用。

片段有一个方法调用onDetach来完成这项工作。

@Override
public void onDetach() {
super.onDetach();
PUT YOUR CODE HERE
}

这个就行了。

我只是使用findFragmentById和转换到片段,并调用一个处理onBackpressed的方法。这个示例显示了检查这是否是订单流程的第一步,如果弹出一个对话框片段来确认退出订单。

@Override
public void onBackPressed() {
//check if first fragment in wizard is loaded, if true get abandon confirmation before going back
OrderFragment frag =(OrderFragment)getSupportFragmentManager().findFragmentById(R.id.fragContainer);
if (frag==null || (frag!=null && frag.getOrderStage()<1)){
AlertDialogFragment.show(getSupportFragmentManager(), R.string.dialog_cancel_order,R.string.dialog_cancel_order_msg, R.string.dialog_cancel_order_pos,R.string.dialog_order_quiz_neg, DIALOG_ID_CANCEL);
}else {
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
}
  1. 在你的Activity类中,像下面这样重写onBackPressed:
private BaseFragment _currentFragment;


@Override
public void onBackPressed()
{
super.onBackPressed();
_currentFragment.onBackPressed();
}
  1. 在Fragment类中,添加你想要的代码:
@Override
public void onBackPressed()
{
setUpTitle();
}

我用这种方式解决了在活动中覆盖onBackPressed。所有的FragmentTransaction在提交前都是addToBackStack:

@Override
public void onBackPressed() {


int count = getSupportFragmentManager().getBackStackEntryCount();


if (count == 0) {
super.onBackPressed();
//additional code
} else {
getSupportFragmentManager().popBackStack();
}


}

onBackPressed()导致片段从活动中分离。

根据斯特林·迪亚兹的回答,我认为他是对的。但有些情况是错误的。(例如:旋转屏幕)

所以,我认为我们可以检测isRemoving()是否达到了目标。

你可以写在onDetach()onDestroyView()。它是工作。

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


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

这个对我来说很管用: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;
}
});
}

如果你使用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));
}

java只是一个POJO对象

这是超级干净的,没有接口/实现的麻烦。

这很简单,如果你有一个活动A,你做了3个片段,像B,C和D。现在如果你在片段B或C和onBackPressed,你想要移动到片段D每次。然后你只需要覆盖onBackPressed()方法在主活动A,也当你跳转到任何片段,然后传递一个片段的标签或名称,通过你识别的片段在主活动A。

我举了一个例子,通过这个例子你可以很容易地理解....

if (savedInstanceState == null) {


getSupportFragmentManager().beginTransaction().add(R.id.container, new C_fragment(),"xyz").commit();


}

或者如果你正从片段B移动到片段C,在背按时你想要进入片段D…像下面的

btn.setOnClickListener(new View.OnClickListener() {


@Override
public void onClick(View view) {


getActivity().getSupportFragmentManager().beginTransaction().add(R.id.container, new C_frament(), "xyz").commit();
((ActionBarActivity) getActivity()).getSupportActionBar().setTitle("Fragment C");
}
});

现在你必须重写主活动....中的onBackPressed()方法像下面. .

@Override
public void onBackPressed() {
FragmentManager fragmentManager =getSupportFragmentManager();
if (((C_fragment) getSupportFragmentManager().findFragmentByTag("xyz")) != null && ((C_fragment) getSupportFragmentManager().findFragmentByTag("xyz")).isVisible()) {
Fragment fragment = new D_Fragment();
fragmentManager.beginTransaction().replace(R.id.container, fragment).commit();
getSupportActionBar().setTitle("D fragment ");
} else {
super.onBackPressed();
}
}

如何使用onDestroyView()?

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

我是这样做的,对我很管用

简单的界面

FragmentOnBackClickInterface.java

public interface FragmentOnBackClickInterface {
void onClick();
}

示例实现

# EYZ0

public class MyFragment extends Fragment implements FragmentOnBackClickInterface {


// other stuff


public void onClick() {
// what you want to call onBackPressed?
}

然后在activity中重写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;
}

我使用的另一种方法如下:

  • 奥托事件总线用于在活动和它的片段之间通信
  • 活动中的堆栈,包含自定义的回来操作,包装在调用片段定义的Runnable
  • 当控制Activity中调用onBackPressed时,它弹出最近的自定义回来操作并执行Runnable。如果Stack上没有任何东西,则调用默认的super.onBackPressed()

完整的示例代码包括在这里作为对另一个SO问题的回答。

我知道已经太迟了,但我上周也遇到了同样的问题。没有一个答案能帮到我。然后我开始摆弄代码,这是可行的,因为我已经添加了片段。

在您的活动中,为ViewPager设置OnPageChangeListener,这样您就可以知道用户何时处于第二个活动中。如果他在第二个活动中,创建一个boolean true,如下所示:

    mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
mViewPager.setCurrentItem(0);
mViewPager.addOnPageChangeListener(new OnPageChangeListener() {


@Override
public void onPageSelected(int position) {
// TODO Auto-generated method stub
mSectionsPagerAdapter.instantiateItem(mViewPager, position);
if(position == 1)
inAnalytics = true;
else if(position == 0)
inAnalytics = false;
}


@Override
public void onPageScrolled(int position, float arg1, int arg2) {
// TODO Auto-generated method stub
}


@Override
public void onPageScrollStateChanged(int arg0) {
// TODO Auto-generated method stub


}
});

现在,无论何时按下后退按钮,都检查布尔值,并将当前项目设置为您的第一个片段:

@Override
public void onBackPressed() {
if(inAnalytics)
mViewPager.setCurrentItem(0, true);
else
super.onBackPressed();
}

只需遵循以下步骤:

在添加片段时,

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()
}

就是这样!

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


}

最好的解决方案,

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


}
}
}
}

非常简短而甜蜜的回答:

getActivity().onBackPressed();

我案例的整个场景说明:

我在MainActivity中有FragmentA, 我从FragmentA打开FragmentB (FragmentB是FragmentA的子或嵌套片段)

 Fragment duedateFrag = new FragmentB();
FragmentTransaction ft  = getFragmentManager().beginTransaction();
ft.replace(R.id.container_body, duedateFrag);
ft.addToBackStack(null);
ft.commit();

现在如果你想从FragmentB转到FragmentA,你可以简单地把getActivity().onBackPressed();放在FragmentB中。

你应该添加接口到你的项目如下;

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

希望它能帮助到别人:)

既然这个问题和一些答案已经超过5年了,让我分享一下我的解决方案。这是@oyenigun的回答的后续和现代化

< >强更新: 在本文的底部,我添加了一个使用抽象片段扩展的替代实现,它根本不涉及活动,这对于任何具有更复杂的片段层次结构(涉及需要不同返回行为的嵌套片段)的人来说都很有用

我需要实现这一点,因为我使用的一些片段具有较小的视图,我希望通过返回按钮来消除这些视图,例如弹出的小信息视图,等等,但这对于需要覆盖片段内返回按钮行为的任何人都是有益的。

首先,定义一个接口

public interface Backable {
boolean onBackPressed();
}

这个接口,我称之为Backable(我是一个严格遵守命名约定的人),它只有一个方法onBackPressed(),必须返回一个boolean值。我们需要强制一个布尔值,因为我们需要知道后退按钮是否“吸收”了后退事件。返回true意味着它已经执行了,并且不需要进一步的操作,否则,false表示仍然必须执行默认的后退操作。这个接口应该是它自己的文件(最好是在一个名为interfaces的单独包中)。记住,将类分离到包中是很好的实践。

其次,找到顶部的片段

我创建了一个返回back堆栈中最后一个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()覆盖中,放入您需要的任何逻辑。如果你想让后退按钮弹出后退堆栈(默认行为),返回真正的,你的后退事件已经被吸收。否则,返回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处理它,而需要直接在片段中处理它。但是谁说你不能拥有带有背压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接口自动捕获返回的单击。只需使用标准逻辑从实现的onKey()方法中调用抽象的onBackButtonPressed()方法来识别后退按钮的按下。如果你需要注册按键点击而不是返回按钮,只要确保在你的片段中覆盖onKey()时调用super方法,否则你将在抽象中覆盖行为。

使用简单,只需扩展和实现:

public class FragmentChannels extends BackableFragment {


...


@Override
public void onBackButtonPressed() {
if (doTheThingRequiringBackButtonOverride) {
// do the thing
} else {
getActivity().onBackPressed();
}
}


...
}

由于超类中的onBackButtonPressed()方法是抽象的,因此一旦扩展,就必须实现onBackButtonPressed()。它返回void,因为它只需要在片段类中执行一个操作,而不需要将压力的吸收传递回Activity。如果你用后退按钮做的任何事情都不需要处理,你需要调用活动onBackPressed()方法,否则,后退按钮将被禁用…你不会想要这样的!

< >强警告 如您所见,这将关键侦听器设置为片段的根视图,我们需要集中它。如果在扩展该类的片段(或具有相同内容的其他内部片段或视图)中涉及到编辑文本(或任何其他焦点窃取视图),则需要单独处理。有一篇关于扩展一个EditText的好文章让你在背推上失去注意力

我希望有人觉得这有用。快乐的编码。

在活动生命周期中,当我们使用FragmentActivity或AppCompatActivity时,总是android返回按钮处理FragmentManager事务。要处理backstack,我们不需要处理它的backstack计数或标记任何东西,但我们应该在添加或替换片段时保持专注。请找到以下片段来处理后退按钮的情况,

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

这是我的解决方案:

在# EYZ0

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

< em >片段:< / em >

((MyActivity) getActivity()).setOnBackClickListener(new MyActivity.OnBackClickListener() {
@Override
public boolean onBackClick() {
if (condition) {
return false;
}


// some codes


return true;
}
});

在mainActivity实现回调接口中

protected mainActivity.OnBackPressedListener onBackPressedListener;


public interface OnBackPressedListener {
void doBack();
}


public void setOnBackPressedListener(mainActivity.OnBackPressedListener onBackPressedListener) {
this.onBackPressedListener = onBackPressedListener;
}


@Override
public void onBackPressed() {
if (onBackPressedListener != null) {
onBackPressedListener.doBack();
} else {
super.onBackPressed();
}
}

在片段实现接口OnBackPressedListener,我们写在mainActivity

implements mainActivity.OnBackPressedListener

mainActivity是我的基本活动,在你的片段onCreateView方法中编写以下代码

((mainActivity) getActivity()).setOnBackPressedListener(this);

并实现OnBackPressedListener接口方法doBack

@Override
public void doBack() {
//call base fragment
}

现在使用doBack()方法调用你想要调用的fragment

在我看来,最好的解决办法是:

JAVA解决方案

创建简单的界面:

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

芬兰湾的科特林解决方案

1 -创建接口

interface IOnBackPressed {
fun onBackPressed(): Boolean
}

2 -准备你的活动

class MyActivity : AppCompatActivity() {
override fun onBackPressed() {
val fragment =
this.supportFragmentManager.findFragmentById(R.id.main_container)
(fragment as? IOnBackPressed)?.onBackPressed()?.not()?.let {
super.onBackPressed()
}
}
}

3 -实现在你的目标片段

class MyFragment : Fragment(), IOnBackPressed {
override fun onBackPressed(): Boolean {
return if (myCondition) {
//action not popBackStack
true
} else {
false
}
}
}

< >强片段: 创建一个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'(意味着它已被处理,因此没有进一步的操作)则中止。

在碎片中处理onBackPressed ()的简单方法

<强>步骤1: 在activity中创建一个静态布尔值

public static Fragment_one;

<强>步骤2: 在On Create方法中的MainActivity(持有片段的活动)上,声明

Fragment_one=true;

在MainActivity中覆盖onBackPressed(

@Override
public void onBackPressed() {


if(Fragment_one) {
//Back key pressed on fragment one


}else {
//Back key pressed on fragment two
}
}

在fragment_one上声明onCreateView方法

MainActivity.Fragment_one=true;

在fragment_two上声明onCreateView方法

MainActivity.Fragment_one=false;

这个方法只适用于两个片段。

像这样实现 Fragment_1 -> Fragment_2 -> Fragment_3

    Button btn = (Button) rootView.findViewById(R.id.your_button_id);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {


Fragment_2 nextFrag= new Fragment_2();
getActivity().getSupportFragmentManager().beginTransaction()
.replace(R.id.content_frame, nextFrag,getTag())
.addToBackStack(null)
.commit();


}
});

Fragment_3 -> Fragment_2 -> Fragment_1

Step_1:在Base Activity中创建一个可公开访问的字符串

step2:每当一个新的Fragment被激活时,在Base Activity中改变String的值

Step_3:然后添加onBackPressed()方法,并将字符串值传递给另一个方法,其中fagments可以被替换

在基础活动中

public static String currentFragment=null;


@Override
public void onBackPressed()
{
displayPreviousFragment(currentFragment);
}


public void displayPreviousFragment(String currentFragment)
{
//creating fragment object
Fragment fragment = null;


//initializing the fragment object which is selected
switch (currentFragment)
{
case "Fragment_2"    :   fragment = new Fargment_1();     break;
case "Fragment_3"    :   fragment = new Fragment_2();     break;
}


//replacing the fragment
if (fragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.frame_to_replace_fragment, fragment);
ft.commit();
}
}
在Fragment_2 < p > 在OnCreateView方法

BaseActivity.currentFragment="Fragment_2";
在Fragment_3 < p > 在OnCreateView方法

BaseActivity.currentFragment="Fragment_3";
@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;
}
});
}

这一行代码将从任何片段中进行操作,它将弹出backstack上的当前片段。

getActivity().getSupportFragmentManager().popBackStack();
public interface IonBackPressInFrag {
void backPressed();
}


public class FragmentMainActivity extends AppCompatActivity {
public IonBackPressInFrag backPressInFrag;


@Override
protected void onCreate(Bundle savedInstanceState) {


@Override
public void onBackPressed () {
backPressInFrag.backPressed();
}
}
}


public class FragDetailSearch extends Fragment implements IonBackPressInFrag {
if(getActivity() !=null){
((FragmentMainActivity) getActivity()).backPressInFrag = this;
}


@Override
public void backPressed() {
Toast.makeText(getContext(), "backkkkkk", Toast.LENGTH_LONG).show();
}
}

好了,伙计们,我终于找到一个好办法了。

在你的onCreate()在你的活动中容纳你的片段添加一个backstack更改监听器,如下所示:

    fragmentManager.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
List<Fragment> f = fragmentManager.getFragments();
//List<Fragment> f only returns one value
Fragment frag = f.get(0);
currentFragment = frag.getClass().getSimpleName();
}
});

(也添加我的fragmenManager是在活动O 现在每次你改变fragment,当前的fragment String就会变成当前fragment的名字。然后在onBackPressed()活动中,你可以控制后退按钮的动作,如下所示

    @Override
public void onBackPressed() {


switch (currentFragment) {
case "FragmentOne":
// your code here
return;
case "FragmentTwo":
// your code here
return;
default:
fragmentManager.popBackStack();
// default action for any other fragment (return to previous)
}


}

我可以确认这个方法对我有用。

简单地在onKeyUp()中做:

@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {


if (keyCode == KeyEvent.KEYCODE_BACK) {
// do something
return true;  // return true if back handled, false otherwise
}


return super.onKeyUp(keyCode, event);
}

根据AndroidX发布说明androidx.activity 1.0.0-alpha01被发布,并引入了ComponentActivity,这是现有的FragmentActivityAppCompatActivity的一个新基类。这个版本给我们带来了一个新功能:

您现在可以通过addOnBackPressedCallback注册一个OnBackPressedCallback来接收onBackPressed()回调,而不需要在您的活动中覆盖该方法。

更新:<强> # EYZ0 < / >强应该被使用。

指南如何使用developer.android.com/guide/navigation/navigation-custom-back


你可以在activity中注册fragment来处理背按:

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()
}
}
   @Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if ((keyCode == KeyEvent.KEYCODE_BACK))
{
finish();
}
return super.onKeyDown(keyCode, event);
}
任何下键相关的方法现在addToBackStack将工作。 由于< / p >

在我的解决方案(Kotlin);

我使用onBackAlternative函数作为BaseActivity上的参数。

BaseActivity

abstract class BaseActivity {


var onBackPressAlternative: (() -> Unit)? = null


override fun onBackPressed() {
if (onBackPressAlternative != null) {
onBackPressAlternative!!()
} else {
super.onBackPressed()
}
}
}

我有一个函数集onBackPressAlternativeBaseFragment

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
}
}

如果你使用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()
}
}
}
)

看到# EYZ0

通过处理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();

使用导航组件你可以做到像这样:

Java

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
}
...
}

在片段的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);
}

你可以像这样使用父活动的onBackPressedDispatcher:

val backpress = requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, true) {
// here dispatcher works for any action when back pressed
}

你也可以从fragment中启用/禁用backpress按钮,如下所示:

backpress.isEnabled = true/false

谷歌发布了一个新的API来处理Fragment中的onBackPressed:

activity?.onBackPressedDispatcher?.addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {


}
})

如果你真的想在Fragment中启用onBackPressed(),试试这个。 在浪费了一个小时的时间后,我根据我以前的经验,做出了这个完全符合需求的解决方案

您只需要关注private int STATUS_FRAGMENT=0;的值,它足以满足片段中addToBackStack()的需求。

import android.view.MenuItem;
import android.view.View;


import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;


import com.example.growfast.NavigationItemsFolder.CoreFragments.Cart;
import com.example.growfast.NavigationItemsFolder.CoreFragments.HelpDesk;
import com.example.growfast.NavigationItemsFolder.CoreFragments.Home;
import com.example.growfast.NavigationItemsFolder.CoreFragments.ProfileDetails;
import com.example.growfast.R;
import com.google.android.material.bottomnavigation.BottomNavigationView;


public class BusinessManagement extends AppCompatActivity {


public BottomNavigationView bottomNavigationView;
private int STATUS_FRAGMENT=0;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_base_layout);
setBottomNavigationMenu();


}


private void setBottomNavigationMenu() {
bottomNavigationView = findViewById(R.id.navigation);
bottomNavigationView.setVisibility(View.VISIBLE);


bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {


Fragment fragment = null;


@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {


switch (item.getItemId()) {


case R.id.action_home:
fragment = new Home();
break;


case R.id.action_profile:
fragment = new ProfileDetails();
break;
case R.id.action_cart:
fragment = new Cart();
break;
case R.id.action_favourites_menu:
fragment = new HelpDesk();
break;


}
return loadFromFragment(fragment);


}
});
bottomNavigationView.setSelectedItemId(R.id.action_home);
}


private boolean loadFromFragment(Fragment fragment) {
if (fragment != null) {
getSupportFragmentManager().beginTransaction().replace(R.id.my_container, fragment)
.commit();
STATUS_FRAGMENT=1;
return true;
}
return false;
}


@Override
public void onBackPressed() {
if (STATUS_FRAGMENT==1) {
bottomNavigationView.setSelectedItemId(R.id.action_home);
STATUS_FRAGMENT=0;
bottomNavigationView.setVisibility(View.VISIBLE);
}
else{
super.onBackPressed();
}
}




}```

新的更好的方法:下面Fragment中的一段代码将帮助您捕获反按事件。

JAVA

@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);


OnBackPressedCallback callback = new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
Toast.makeText(mContext, "back pressed", Toast.LENGTH_SHORT).show();
            

// And when you want to go back based on your condition
if (yourCondition) {
this.setEnabled(false);
requireActivity().onBackPressed();
}
}
};


requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
}

芬兰湾的科特林

activity?.onBackPressedDispatcher?.addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {


}
})

这是我的回答,处理碎片按下的后退按钮。 我有底部导航与五个项目(A, B, C, D,E)附加到活动时,点击一个项目,我附加的片段到活动。 让我们假设点击项目(A),我附加片段(A),然后如果点击项目(B),我附加片段(B),以此类推

点击项目的流程。# EYZ0

返回按钮按下的流程。# EYZ0

 @Override
public void onBackPressed() {
int count = getSupportFragmentManager().getBackStackEntryCount();
if (count == 0) {
super.onBackPressed();
} else {
int index = ((getSupportFragmentManager().getBackStackEntryCount()) -1);
getSupportFragmentManager().popBackStack();
FragmentManager.BackStackEntry backEntry = getSupportFragmentManager().getBackStackEntryAt(index);
int stackId = backEntry.getId();
bottomNavigationView.getMenu().getItem(stackId).setChecked(true);
}
}

Here the demo is

 requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
//your code
}

从你的片段,就用

 requireActivity().onBackPressed();

为处理单击添加 binding.actionABack.setOnClickListener(v -> requireActivity().onBackPressed());

private boolean isMainFragment = true;


@Override
public void onBackPressed() {


if (isMainFragment){
finish();
}else {
getSupportFragmentManager().popBackStack();
isMainFragment = true;
}
}

当打开花药片段时,只需添加

isMainFragment = false;

这是我的工作

如果你需要在Fragment中实现,你应该使用接口

另一方面,如果你需要在活动中实现,如eg。执行简单的finish()活动,执行以下操作:

YourActivity.kt

override fun onBackPressed() {
Log.d(this.javaClass.simpleName, "onBackPressed() called")


if (supportFragmentManager.fragments.any { it is YourFragment }) {
finish()
return
}
}

在kotlin中,这要简单得多。

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
//
}
})
}

我如何在这个逻辑中调用activity?.onBackPressed

所以我创建了一个可能对你有用的扩展:

fun Fragment.onBackClick(callback: (onBackPressedCallback: OnBackPressedCallback) -> Unit) {
// This callback will only be called when MyFragment is at least Started.


activity?.onBackPressedDispatcher?.addCallback(viewLifecycleOwner) {
callback.invoke(this)
}
}

现在是激动人心的部分,当你的逻辑完成时调用onBackPressed:

片段中的示例使用:

onBackClick {
if (shouldBackFromFrag){
//do your logic when pressed back
}else{
it.isEnabled = false //the key to disable the dispatcher
activity?.onBackPressed()
}
}

if片段和使用NavController简单调用

findNavController().popBackStack()

在kotlin的情况下使用这个onAttach回调

        override fun onAttach(context: Context) {
super.onAttach(context)
val callback: OnBackPressedCallback = object :
OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
// your onbackpressed code




}
}
requireActivity().onBackPressedDispatcher.addCallback(this, callback)
}