ChatGPT解决这个技术问题 Extra ChatGPT

如何让 Fragment 自行移除,即它相当于 finish()?

我正在使用兼容性库将应用程序转换为使用片段。现在,目前我有许多活动(ABCD),它们相互链接,D 有一个“确定”按钮,当按下该按钮时调用完成,然后通过 onActivityResult() 冒泡以另外破坏 C 和 B。

对于我之前的 Honycomb 片段版本,每个活动实际上都是片段 Af Bf Cf Df 的包装器。所有活动都是通过 startActivityForResult() 启动的,并且每个片段中的 onActivityResult() 都可以愉快地调用 getActivity().finish()

我遇到的问题是在我的 Honeycomb 版本中,我只有一个活动 A,并且使用 FragmentManager 加载片段 Bf、Cf、Df。

我不明白的是当按下“确定”以删除片段 Df、Cf 和 Bf 时在 Df 中做什么?

我尝试让片段从堆栈中弹出,但这导致了异常。 onActivityResult() 没用,因为我没有使用 startActivityForResult() 加载片段。

我在想这个完全错误的方式吗?我是否应该实现某种与父片段或活动通信的侦听器,以便使用事务管理器进行弹出?

怎么样 ((YourActivity) getActivity()).onBackPressed();
@ViswanathLekshmanan 您的评论回答对我很有用.. 1 点赞
@AbhishekSingh 很高兴听到:)
@ViswanathLekshmanan :)

M
Manfred Moser

虽然它可能不是最好的方法,但我能想到的最接近的等效方法是支持/兼容性库

getActivity().getSupportFragmentManager().beginTransaction().remove(this).commit();

或者

getActivity().getFragmentManager().beginTransaction().remove(this).commit();

否则。

此外,您可以使用 backstack 并弹出它。但是请记住,片段可能不在后台堆栈上(取决于将它放在那里的片段事务..),或者它可能不是最后一个进入堆栈的片段,因此弹出堆栈可能会删除错误的片段......


虽然这种方法有效,但如果您使用 addToBackStack(null) 它将使后退按钮处理程序 +1。所以你必须按两次。
从 FragmentManager 中“弹出”片段。
我已经尝试了上述过程,但它给出了这个错误“java-lang-illegalstateexception-can-not-perform-this-action-after-onsaveinstance”。所以我必须在哪里删除片段
这个答案是一种不好的做法,不应该提高投票率。片段并不意味着像这样具有自我意识。它扼杀了可重用性,这就是碎片的意义所在!片段应通过多种方式向活动发出信号以将其删除。回调接口方法是一种流行的选择。 developer.android.com/training/basics/fragments/…
@ManfredMoser 我不同意。这就是问题的重点。他有一个完整的片段序列要移除。此代码没有空检查或检查是否附加了活动。它会在生产中中断,因为它依赖于片段不知道的太多东西。
C
Carsten

您可以使用下面的方法,它工作正常:

getActivity().getSupportFragmentManager().popBackStack();

这个答案比公认的答案好 10 倍——直截了当。
它在设计方面也比公认的差 10 倍。片段应该是活动的小“助手”,并且永远不应该控制自己或其他片段
正如@avalancha 指出的那样,该解决方案不正确。看看developer.android.com/guide/components/…
我正在使用此方法 onActivityResult 并收到错误“在 onSaveInstanceState 之后无法执行此操作”。我该如何解决?
popBackStack() 是在删除片段后要将操作栏标题设置回之前状态时唯一有效的解决方案。否则,我不需要将 stackoverflow.com/questions/13472258/… 中的高评价解决方案和此处的此解决方案结合起来,以便在各种用例之后始终设置正确的操作栏标题。如后按、删除、添加替换等。
C
CommonsWare

我不明白的是当按下“确定”以删除片段 Df、Cf 和 Bf 时在 Df 中做什么?

第 1 步:让 Df 告诉 D“哟!我们点击确定!”通过在活动本身或活动提供的接口实例上调用方法。

第 2 步:让 D 通过 FragmentManager 删除片段。

托管活动 (D) 是知道活动中还有哪些其他片段的活动(相对于其他活动中的内容)。因此,可能影响片段混合的片段内事件应该传播到活动,这将使适当的编排移动。


但是在我的 Honeycomb 版本中没有 D,这是我的困难。有一个简单的活动 A,它加载片段 Bf,它加载 Cf,它使用 FragmentTransaction 加载 Df。
@PJL:对不起,我的意思是 A。这是使用侦听器接口的原因之一,因此多个活动都可以响应来自 Df 的“我们得到了 OK 点击”事件。
因为我目前正在移植,所以我从 Fragment Df 的 onActivityResult 方法中调用了一个监听器方法到活动中,然后我在 FragmentManager 上调用了 popBackStack。但是,这会导致异常“IllegalStateException:在 onSaveInstanceState 之后无法执行此操作”。关于如何克服这个问题的任何想法?
@DiegoPalomar:finish() 就足够了。
@ user3364963:自从我调查以来已经有一段时间了,但是IIRC,当它从后面的堆栈中弹出时它被破坏了。将 onDestroy() 方法添加到您的片段并查看它是否被调用。
B
Blundell

正如 CommonsWare 所说,您应该让 Activity 处理添加和删除片段,使用监听器。这是一个例子:

public class MyActivity extends FragmentActivity implements SuicidalFragmentListener {

    // onCreate etc

    @Override
    public void onFragmentSuicide(String tag) {
        // Check tag if you do this with more than one fragmen, then:
        getSupportFragmentManager().popBackStack();
    }
}

public interface SuicidalFragmentListener {
    void onFragmentSuicide(String tag);
}

public class MyFragment extends Fragment {

    // onCreateView etc

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
           suicideListener = (SuicidalFragmentListener) activity;
        } catch (ClassCastException e) {
           throw new RuntimeException(getActivity().getClass().getSimpleName() + " must implement the suicide listener to use this fragment", e);
        }
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        // Attach the close listener to whatever action on the fragment you want
        addSuicideTouchListener();
    }

    private void addSuicideTouchListener() {
        getView().setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
              suicideListener.onFragmentSuicide(getTag());
            }
        });
    }
}

自杀多 emo 风格? “SelfClosing”或“AutoClose”或“SmartClose”(r)怎么样
它没有关闭它会永远死去;-(
这是比其他答案更清洁的方法。活动创建并呈现片段,并应控制其生命周期。当发生某些事情表明该片段不应再在视图中时,它应该告诉 Activity 并让 Activity 将其删除。
从技术上讲,如果我们应该让活动杀死片段,那么片段不会自杀。该活动具有杀人性质。
C
Codeversed

在 Activity/AppCompatActivity 中:

@Override
public void onBackPressed() {
    if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
        // if you want to handle DrawerLayout
        mDrawerLayout.closeDrawer(GravityCompat.START);
    } else {
        if (getFragmentManager().getBackStackEntryCount() == 0) {
            super.onBackPressed();
        } else {
            getFragmentManager().popBackStack();
        }
    }
}

然后调用片段:

getActivity().onBackPressed();

或像其他答案中所述,在片段中调用它:

getActivity().getSupportFragmentManager().beginTransaction().remove(this).commit();

G
Gastón Saillén

如果您使用的是新的导航组件,则很简单

findNavController().popBackStack()

它会为你完成所有的 FragmentTransaction。


V
Vasudev

查看 DialogFragment 是否满足您的需求。 DialogFragment 有一个dismiss() 方法。在我看来更干净。


E
Eliasz Kubala

我为此创建了简单的方法

popBackStack(getSupportFragmentManager());

比把它放在我的 ActivityUtils 类中

public static void popBackStack(FragmentManager manager){
        FragmentManager.BackStackEntry first = manager.getBackStackEntryAt(0);
        manager.popBackStack(first.getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }

工作很棒,玩得开心!


我不明白你的方法的目的。原始的 popBackStack 似乎完全足够了。
C
CodeSi

创建时:

//Add comment fragment
            container = FindViewById<FrameLayout>(Resource.Id.frmAttachPicture);
            mPictureFragment = new fmtAttachPicture();

            var trans = SupportFragmentManager.BeginTransaction();
            trans.Add(container.Id, mPictureFragment, "fmtPicture");
            trans.Show(mPictureFragment); trans.Commit();

这就是我在点击事件 1 中隐藏片段的方式

//Close fragment
    var trans = SupportFragmentManager.BeginTransaction();
    trans.Hide(mPictureFragment);
    trans.AddToBackStack(null);
    trans.Commit();

然后将其显示回 int 事件 2

var trans = SupportFragmentManager.BeginTransaction();
            trans.Show(mPictureFragment); trans.Commit();

x
xarlymg89

如果你需要从 backstack 历史中的第四个片段弹回到第一个片段,使用标签!!!

当您添加第一个片段时,您应该使用如下内容:

getFragmentManager.beginTransaction.addToBackStack("A").add(R.id.container, FragmentA).commit() 

或者

getFragmentManager.beginTransaction.addToBackStack("A").replace(R.id.container, FragmentA).commit()

当你想显示片段 B、C 和 D 时,你可以使用:

getFragmentManager.beginTransaction.addToBackStack("B").replace(R.id.container, FragmentB, "B").commit()

和其他字母......

回到Fragment A,只要调用popBackStack(0, "A"),是的,使用你添加时指定的标志,注意它必须与命令addToBackStack()中的标志相同,而不是命令replace中使用的标志或添加。

别客气 ;)


我已经测试了'popBackStack(0,“A”)'并且我的应用程序返回到片段A,但我只想从返回堆栈中删除该片段......如何从堆栈中删除片段而不显示在屏幕上?
D
Dino Sunny

在同一片段内关闭片段

getActivity().onBackPressed();

科特林 -

requireActivity().onBackPressed()

N
Nicholas Chen
parentFragmentManager.apply {
    val f = this@MyFragment
    beginTransaction().hide(f).remove(f).commit()
}

请不要只发布代码作为答案,还要解释您的代码的作用以及它如何解决问题的问题。带有解释的答案通常更有帮助,质量更好,并且更有可能吸引赞成票。
W
Will

为什么不只是:

getActivity().finish();


这将完成整个活动,而不仅仅是片段。