如何在Fragments中实现onBackPressed()?

时间:2011-03-27 10:30:14

标签: android android-fragments onbackpressed

我们是否有办法在Android Fragment中实现onBackPressed(),类似于我们在Android Activity中实现的方式?

由于Fragment生命周期没有onBackPressed()。还有其他替代方法来覆盖Android 3.0碎片中的onBackPressed()吗?

54 个答案:

答案 0 :(得分:268)

我以这种方式解决了Activity中的onBackPressed覆盖问题。在提交之前,所有FragmentTransaction都是addToBackStack

@Override
public void onBackPressed() {

    int count = getSupportFragmentManager().getBackStackEntryCount();

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

}

答案 1 :(得分:101)

我认为最好的解决方案是

JAVA SOLUTION

创建简单的界面:

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

KOTLIN SOLUTION

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

答案 2 :(得分:91)

根据@HaMMeRed的回答,这里是伪代码应该如何工作。 假设您的主要活动名为BaseActivity,其中包含子片段(如SlidingMenu lib示例中所示)。 以下是步骤:

首先我们需要创建接口和类来实现其接口以具有泛型方法

  1. 创建类接口OnBackPressedListener

    public interface OnBackPressedListener {
        public void doBack();
    }
    
  2. 创建实现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. 从现在开始,我们将处理代码BaseActivity及其片段

  4. 在班级BaseActivity

    之上创建私人听众
    protected OnBackPressedListener onBackPressedListener;
    
  5. 创建在BaseActivity

    中设置侦听器的方法
    public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
        this.onBackPressedListener = onBackPressedListener;
    }
    
  6. 覆盖onBackPressed中的
  7. 实现类似

    的内容
    @Override
    public void onBackPressed() {
        if (onBackPressedListener != null)
            onBackPressedListener.doBack();
        else
            super.onBackPressed();
    
  8. 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;
    }
    
  9. Voila,现在当你点击片段时,你应该抓住你的自定义背面方法。

答案 3 :(得分:74)

这对我有用: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;
        }
    });
}

答案 4 :(得分:63)

如果您想要这种功能,则需要在活动中覆盖它,然后在所有片段中添加YourBackPressed接口,只要按下后退按钮,就可以调用相关片段。< / p>

编辑:我想追加我之前的回答。

如果我今天要这样做,我会使用广播,或者如果我希望其他面板与主/主要内容面板一致更新,则可以使用有序广播。

支持库中的

LocalBroadcastManager可以为此提供帮助,您只需在onBackPressed中发送广播并订阅您关注的片段。我认为Messaging是一个更加分离的实现,并且可以更好地扩展,所以它现在是我的官方实现建议。只需使用Intent的操作作为邮件的过滤器即可。发送新创建的ACTION_BACK_PRESSED,从您的活动发送,并在相关片段中收听。

答案 5 :(得分:43)

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

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

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

这将是工作。

答案 6 :(得分:22)

只需在您的片段之间转换时添加addToBackStack,如下所示:

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

如果您编写addToBackStack(null),它将自行处理它,但如果您提供标记,则应手动处理。

答案 7 :(得分:19)

因为这个问题和一些答案已经超过五年了,让我分享一下我的解决方案。这是对@oyenigun

的回答的后续和现代化

<强>更新 在本文的底部,我添加了一个使用抽象Fragment扩展的替代实现,该扩展根本不涉及Activity,这对于任何具有更复杂的片段层次结构的人来说都是有用的,这些片段层次结构涉及需要不同反向行为的嵌套片段。

我需要实现这个,因为我使用的一些片段具有较小的视图,我想用后退按钮解除,例如弹出的小信息视图等,但这对于需要覆盖的任何人都有好处片段内的后退按钮的行为。

首先,定义一个接口

public interface Backable {
    boolean onBackPressed();
}

这个界面,我称之为Backable(我是命名约定的坚持者),它有一个方法onBackPressed(),必须返回boolean值。我们需要强制执行一个布尔值,因为我们需要知道按下后退按钮是否已吸收&#34;后面的事件。返回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()并可以返回。否则,将其视为正常的背压并调用超级方法。

不参与活动的第二个选项

有时,您根本不希望Activity处理此问题,您需要直接在片段中处理它。但谁说你无法拥有带有反压API的片段?只需将您的片段扩展到一个新类。

创建一个扩展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因为它只需要在片段类中执行一个动作,并且不需要将按下的吸收传递回活动。 确保您调用了活动onBackPressed()方法,如果您使用后退按钮执行的任何操作都不需要处理,否则后退按钮将被禁用。你并不想要那个!

<强>注意事项 正如您所看到的,这会将关键监听器设置为片段的根视图,我们需要关注它。如果片段中涉及的编辑文本(或任何其他焦点窃取视图)扩展了此类(或其他内部片段或具有相同视图的视图),则您需要单独处理它。在extending an EditText上有一篇很好的文章,不再关注背压。

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

答案 8 :(得分:17)

使用Navigation component,您可以like this

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

答案 9 :(得分:13)

解决方案很简单:

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

答案 10 :(得分:11)

新的更好的方法:遵循 Fragment 中的一段代码将帮助您捕获后退事件。

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

答案 11 :(得分:10)

如果您使用的是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

答案 12 :(得分:8)

在片段的onCreate方法内添加以下内容:

.container i:nth-of-type(1) {
  -webkit-transition-delay: 1.1s;
  transition-delay: 1.1s;
}

.container i:nth-of-type(2) {
  -webkit-transition-delay: 0.9s;
  transition-delay: 0.9s;
}

答案 13 :(得分:7)

Google已发布新的API,以处理onBackPressed中的Fragment

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

            }
        })

答案 14 :(得分:7)

我这样做了,它对我有用

简单界面

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

答案 15 :(得分:7)

onBackPressed()导致Fragment与Activity分离。

根据@Sterling Diaz的回答,我认为他是对的。但有些情况会出错。 (例如旋转屏幕)

所以,我认为我们可以检测isRemoving()是否能实现目标。

您可以在onDetach()onDestroyView()处撰写。这是工作。

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

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

答案 16 :(得分:7)

这只是一个可以解决问题的小代码:

 getActivity().onBackPressed();

希望它可以帮助某人:)

答案 17 :(得分:7)

您应该为项目添加界面,如下所示;

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

答案 18 :(得分:6)

如果您使用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对象

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

答案 19 :(得分:6)

如何使用onDestroyView()?

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

答案 20 :(得分:5)

这是我的解决方案:

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

答案 21 :(得分:4)

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

答案 22 :(得分:3)

非常简短的答案:

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。

答案 23 :(得分:3)

请按以下步骤操作:

添加片段时始终

delete

然后在主要活动中,覆盖fragmentTransaction.add(R.id.fragment_container, detail_fragment, "Fragment_tag").addToBackStack(null).commit();

onBackPressed()

要处理应用中的后退按钮,

if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
    getSupportFragmentManager().popBackStack();
} else {
    finish();
}

就是这样!

答案 24 :(得分:3)

在活动生命周期中,当我们使用FragmentActivity或AppCompatActivity时,总是android后退按钮处理FragmentManager事务。

为了处理后台堆叠,我们不需要处理其后台堆叠计数或标记任何东西但是我们应该在添加或替换片段时保持专注。请找到以下代码片段来处理后退按钮的情况,

import android.content.Context;
import android.content.Intent;
import android.support.v4.view.PagerAdapter;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class MainActivity extends AppCompatActivity {

private Viewpager viewpager;
private Intromanager intromanager;
private int[] layouts;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    intromanager = new Intromanager(this);
    if(!intromanager.Check())
    {
        intromanager.setFirst(false);
        Intent i = new Intent(MainActivity.this, Main2Activity.class);
        startActivity(i);
        finish();
    }
    setContentView(R.layout.activity_main);

    layouts = new int[]{R.layout.activity_screen_1,R.layout.activity_screen_2,R.layout.activity_screen_3};
}


public class ViewPagerAdapter extends PagerAdapter
{
    private LayoutInflater layoutInflater;

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        layoutInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View v = layoutInflater.inflate(layouts(position),container,false);
        container.addView(v);
        return v;
    }


    @Override
    public int getCount() {
        return layouts.length;
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view==object;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        View v =(View)object;
        container.removeView(v);
    }
}
}

在这里,我不会为我的家庭片段添加堆栈,因为它是我的应用程序的主页。如果将addToBackStack添加到HomeFragment,那么应用程序将等待删除活动中的所有片段,然后我们将获得空白屏幕,以便我保持以下条件,

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

现在,您可以看到之前在活动中添加的片段,app将在到达HomeFragment时退出。您还可以查看以下代码段。

if (!(fragment instanceof HomeFragment)) {
            transaction.addToBackStack(null);
}

答案 25 :(得分:3)

不要实现ft.addToBackStack()方法,这样当您按下后退按钮时,您的活动就会完成。

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

答案 26 :(得分:3)

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

答案 27 :(得分:2)

根据AndroidX release notesandroidx.activity 1.0.0-alpha01被发布并引入了ComponentActivity,它是现有FragmentActivityAppCompatActivity的新基类。此版本为我们带来了一个新功能:

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

答案 28 :(得分:2)

最佳解决方案,

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

            }
        }
    }
}

答案 29 :(得分:2)

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

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

您还可以随时通过以下方式启用/禁用片段的后按按钮:

backpress.isEnabled = true/false

答案 30 :(得分:1)

您可以在活动中注册片段以处理后退操作:

xpath=(//*[text()[contains(.,'Download')]])[6]

用法:

在片段中:

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

答案 31 :(得分:1)

通过片段中的回调,现在通过处理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();

答案 32 :(得分:1)

好吧,我终于找到了一个好的解决方案。

在容纳片段的活动的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中声明 现在,每次更改片段时,当前片段字符串将成为当前片段的名称。然后,在活动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)
    }

}

我可以确认此方法对我有用。

答案 33 :(得分:1)

如果你有一个活动A并且你制作了3个片段,如B,C和D,那就很简单了。如果你在片段B或C中,你想要每次都在片段D上移动onBackPressed。那么你必须覆盖主要活动A中的onBackPressed()方法,当你跳转到任何片段然后传递该片段的 TAG或名称,通过该片段识别主要活动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();
    }
}

答案 34 :(得分:1)

从您的片段中,只需使用

 requireActivity().onBackPressed();

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

答案 35 :(得分:1)

公共类MyActivity扩展了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;
}

}

答案 36 :(得分:1)

我知道为时已晚,但上周我遇到了同样的问题。没有一个答案对我有帮助。然后我正在玩代码,这很有用,因为我已经添加了片段。

在您的活动中,为OnPageChangeListener设置ViewPager,以便您知道用户何时处于第二个活动中。如果他在第二个活动中,请按如下方式生成布尔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();
}

答案 37 :(得分:1)

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

  • Otto event bus在活动及其片段之间进行通信
  • 活动中包含自定义后退操作的堆栈,其中包含调用片段定义的Runnable
  • 在控件Activity中调用onBackPressed时,会弹出最新的自定义后退操作并执行其Runnable。如果堆栈中没有任何内容,则默认super.onBackPressed()称为

包含示例代码的完整方法here作为this other SO question的答案。

答案 38 :(得分:0)

如果您确实想在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();
        }
    }


}```

答案 39 :(得分:0)

这是我处理按下后退按钮上的片段的答案。 当单击我将片段附加到活动的项目时,我有五个项目(A、B、C、D、E)的底部导航附加到活动。 假设点击项目(A)我附加片段(A)然后如果点击项目(B)然后我附加片段(B)等等。

点击项目的流程。 A->B->C->D->E

返回按钮按下的流程。 E->D->C->B->A

 @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

答案 40 :(得分:0)

private boolean isMainFragment = true;

@Override
public void onBackPressed() {

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

当打开花药片段然后添加

isMainFragment = false;

这是我的工作

答案 41 :(得分:0)

在我的解决方案中(科特琳);

我将onBackAlternative函数用作 BaseActivity 上的参数。

BaseActivity

abstract class BaseActivity {

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

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

我有一个在 BaseFragment 上设置 onBackPressAlternative 的功能。

BaseFragment

abstract class BaseFragment {

     override fun onStart() {
        super.onStart()
        ...
        setOnBackPressed(null) // Add this
     }

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

答案 42 :(得分:0)

您必须使用片段侦听器覆盖onBackPressed()。方法如下:

https://stackoverflow.com/a/51228447/7451779

答案 43 :(得分:0)

只需在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);
}

答案 44 :(得分:0)

在Fragments

中处理 onBackPressed()的简便方法

第1步: 在activity中创建一个静态布尔值。

public static Fragment_one;

第2步: 在On Create方法中的MainActivity(包含片段的Activity)上,声明

Fragment_one=true;

第3步:在MainActivity中覆盖onBackPressed()

@Override
public void onBackPressed() {

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

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

第4步:在fragment_one onCreateView 方法声明

MainActivity.Fragment_one=true;

第5步在fragment_two onCreateView 方法声明

MainActivity.Fragment_one=false;

注意:此方法仅适用于两个片段。

答案 45 :(得分:0)

<强>片段: 使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'(意味着它已被处理,则中止)进一步的行动)。

答案 46 :(得分:0)

on mainActivity

protected DrawerHomeActivity.OnBackPressedListener onBackPressedListener;

public interface OnBackPressedListener {
    void doBack();
}

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

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


    }
    else
        super.onBackPressed();



}

on fragment implements base activity / fragment like

implements DrawerHomeActivity.OnBackPressedListener

DraweHomeActivity是我的基本活动写作

((DrawerHomeActivity) getActivity()).setOnBackPressedListener(this);

并创建方法doBack

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

答案 47 :(得分:0)

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

1 - 您的活动应该有一个监听器界面和一个监听器列表

2 - 您应该实现添加和删除侦听器的方法

3 - 您应该覆盖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 - 您需要将片段添加为后退的监听器

6 - 如果片段使用此背面按

,则应从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能够从最新的片段开始。将片段添加到后台堆栈时也可能存在问题。因此,在使用背压时,您需要检查片段是否可见。否则其中一个片段将使用该事件,并且最新片段将不会在后退时关闭。

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

答案 48 :(得分:-1)

   @Override
   public boolean onKeyDown(int keyCode, KeyEvent event)
    {
       if ((keyCode == KeyEvent.KEYCODE_BACK))
  {
           finish();
    }
       return super.onKeyDown(keyCode, event);
    }

只需评论与Key Down相关的任何方法,现在addToBackStack即可使用。 谢谢

答案 49 :(得分:-1)

这行代码将在任何片段中执行操作,它将在backstack上弹出当前片段。

systeminfo

答案 50 :(得分:-1)

像这样实施 Fragment_1 - &gt; Fragment_2 - &gt; 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 - &gt; Fragment_2 - &gt; Fragment_1

Step_1:在基本活动中创建可公开访问的字符串

步骤2:每当激活新片段时,更改基本活动中字符串的值

Step_3:然后添加onBackPressed()方法并将String值传递给另一个可以替换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中 在OnCreateView方法中

BaseActivity.currentFragment="Fragment_2";

在Fragment_3中 在OnCreateView方法中

BaseActivity.currentFragment="Fragment_3";

答案 51 :(得分:-1)

如果您的片段在活动中。(假设您有一个活动,在此活动中您使用FrameLayout,然后您通过使用FrameLayout从您的活动调用片段A或B或C)然后您只需使用

来自你片段的

Data.Set.Monad.Set Int

答案 52 :(得分:-1)

我只是使用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();
        }
    }

答案 53 :(得分:-2)

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

活动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中的Intent对象“data”将从片段

中获取字符串