如何获得一个片段来删除自己,即它等同于finish()?


230

我正在使用兼容性库将应用程序转换为使用片段。现在,我有许多活动(ABCD)相互链接,D有一个“ OK”按钮,按下该按钮即可结束通话,然后冒出气泡onActivityResult()来进一步破坏C和B。

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

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

我不了解的是,当按下“ OK”以删除片段Df,Cf和Bf时,在Df中该怎么做?

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

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


7
怎么样((YourActivity)getActivity())。onBackPressed();
Viswanath Lekshmanan

@ViswanathLekshmanan您的意见回答对我很有用。.1来自我的赞扬
Abhishek Singh

@AbhishekSingh很高兴听到:)
Viswanath Lekshmanan

@ViswanathLekshmanan :)
Abhishek Singh

Answers:


62

我不了解的是,当按下“ OK”以删除片段Df,Cf和Bf时,在Df中该怎么做?

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

步骤#2:让D通过删除碎片FragmentManager

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


但是在我的Honeycomb版本中没有D,这是我的困难。仅存在一个活动A,它加载片段Bf,后者加载Cf,后者使用FragmentTransaction加载Df。
PJL

1
@PJL:对不起,我的意思是A。这是使用侦听器界面的原因之一,因此多个活动都可以响应Df的“我们获得OK单击”事件。
CommonsWare,

1
当我当前正在移植时,我从片段Df的onActivityResult方法调用了一个侦听器方法,将其插入到活动中,然后我在FragmentManager上调用了popBackStack。但是,这会导致异常情况“ IllegalStateException:在onSaveInstanceState之后无法执行此操作。关于如何克服此问题的任何想法?
PJL

1
@DiegoPalomar:finish()应该足够了。
CommonsWare 2013年

1
@ user3364963:自从我调查以来已经有一段时间了,但是IIRC在它从后堆栈弹出时被销毁了。onDestroy()在片段中添加一个方法,看看是否被调用。
CommonsWare,2014年

313

虽然这可能不是最好的方法,但我能想到的最接近的等效方法是与支持/兼容性库一起使用

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

要么

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

除此以外。

另外,您可以使用后退栈并将其弹出。但是请记住,该片段可能不在堆栈上(取决于将其放在那里的fragmenttransaction ..),也可能不是最后一个进入堆栈的片段,因此弹出堆栈可以删除错误的片段...


11
尽管此方法有效,但是如果您使用addToBackStack(null),它将使后退按钮处理程序+1。因此,您必须按两次。
user123321

34
从FragmentManager“弹出”片段。
user123321

2
我已经尝试了上述过程,但给出了此错误“ java-lang-illegalstateexception无法在onsaveinstance之后执行此操作”。因此,我到底要删除
哪些

6
这个答案是一种不好的做法,不应获得选票。这样的片段并不意味着自我意识。它破坏了可重用性,这就是碎片的关键!片段应发出信号通知活动以通过多种方式将其删除。回调接口方法是一种流行的选择。developer.android.com/training/basics/fragments/...
colintheshots

2
@ManfredMoser我不同意。这是问题的关键。他要删除整个片段。此代码没有null检查或活动是否已附加的检查。它会中断生产,因为它取决于片段不知道的太多事情。
colintheshots 2015年

263

您可以使用以下方法,效果很好:

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

44
这个答案比公认的答案好10倍-直截了当。
nikib3ro

50
在设计方面,它比公认的还要差10倍。片段应该是活动的小“帮手”,并且永远不能控制自己或其他片段
Patrick

6
该解决方案是不正确的,如@avalancha所指出的。看看developer.android.com/guide/components/...
the_dark_destructor

2
我正在使用此方法onActivityResult并收到错误“ onSaveInstanceState之后无法执行此操作”。我该如何解决?
Jayeshkumar Sojitra 2014年

1
popBackStack()是您要在删除片段后将操作栏标题设置回先前状态的唯一解决方案。否则,我将不需要将stackoverflow.com/questions/13472258/…中的两个高评价的解决方案组合在一起,并且此解决方案可以在各种用例之后始终设置适当的操作栏标题。例如向后按,删除,添加替换等。
Bevor

36

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

5
自杀有多大的情绪风格?如何“自动关闭”或“自动关闭”或“智能关闭”(r)
DritanX 2014年

21
它没有关闭,而是永远死了;-(
Blundell

3
这是比其他答案更清洁的方法。该活动创建并呈现片段,并应控制其生命周期。当发生指示片段不再可见的事件时,应告知活动并让活动将其删除。
Christopher Pickslay 2014年

7
从技术上讲,如果我们要让该活动杀死该片段,那么该片段就不会自杀。该活动是杀人的。
Casey Murray

17

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

5

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

findNavController().popBackStack()

它将为您完成所有的FragmentTransaction。


4

查看DialogFragment是否满足您的需求。DialogFragment具有dismiss()方法。我认为干净得多。


3

我为此创建了简单的方法

popBackStack(getSupportFragmentManager());

比将其放在我的ActivityUtils类中

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

工作很棒,玩得开心!


2
我不明白你的方法的目的。原始的popBackStack似乎完全足够。
令人难以置信的

1

OnCreate:

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

1

如果您需要从堆栈历史记录中的第四个片段弹出到第一个片段,请使用标签!!!

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

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

和其他字母...

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

别客气 ;)


我已经测试了'popBackStack(0,“ A”)',我的应用回到了片段A,但是我只希望从Back Stack中删除该片段...如何在不显示屏幕的情况下从Stack中删除片段?
KryNaC 2015年


-9

为什么不只是:

getActivity()。finish();


4
这将完成整个活动,而不仅仅是片段。
Murtadha S.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.