如何避免将相同的Fragment添加到堆栈中

8

我需要帮助。我是这样将片段添加到活动中的。问题在于每次调用openFragment方法时,它都会创建并添加一个新的片段,这是很明显的。问题是:我应该做什么修改才能够仅添加一次片段?使用相同的片段标签再次调用时,它不会做任何操作。

案例:第一次按下按钮时,它会添加并显示片段。我再次按下同一按钮,它没有响应。

public static void openFragment(Activity activity, Fragment fragment) {

    FragmentManager fragmentManager = ((ActionBarActivity) activity)
            .getSupportFragmentManager();
        FragmentTransaction ftx = fragmentManager.beginTransaction();
        ftx.addToBackStack(fragment.getClass().getSimpleName());
        ftx.setCustomAnimations(R.anim.slide_in_right,
                R.anim.slide_out_left, R.anim.slide_in_left,
                R.anim.slide_out_right);
        ftx.add(R.id.main_content, fragment);
        ftx.commit();
}

请查看此链接 https://dev59.com/R5vga4cB1Zd3GeqP7tKI#55546069 - Ketan Ramani
6个回答

9

这里是解决方案,它只允许您将片段添加到堆栈中一次,否则它将从堆栈中弹出相同的片段。

public static void openFragment(Activity activity, Fragment fragment) {
    String fragmentTag = fragment.getClass().getName();
    FragmentManager fragmentManager= ((ActionBarActivity) activity)
            .getSupportFragmentManager();

    boolean fragmentPopped = fragmentManager
            .popBackStackImmediate(fragmentTag , 0);

    if (!fragmentPopped && fragmentManager.findFragmentByTag(fragmentTag) == null) {

    FragmentTransaction ftx = fragmentManager.beginTransaction();
    ftx.addToBackStack(fragment.getClass().getSimpleName());
    ftx.setCustomAnimations(R.anim.slide_in_right,
            R.anim.slide_out_left, R.anim.slide_in_left,
            R.anim.slide_out_right);
    ftx.add(R.id.main_content, fragment);
    ftx.commit();
  }
}

从右侧滑入

<?xml version="1.0" encoding="utf-8"?>
  <set xmlns:android="http://schemas.android.com/apk/res/android"
   android:shareInterpolator="true">
  <translate android:fromXDelta="100%"
    android:toXDelta="0%" android:fromYDelta="0%"
    android:toYDelta="0%" android:duration="200">
  </translate>
</set>

slide_out_right

<?xml version="1.0" encoding="utf-8"?>
   <set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate android:fromXDelta="0%" android:toXDelta="100%"
    android:fromYDelta="0%" android:toYDelta="0%"
    android:duration="200">
  </translate>
</set>

从左侧滑入

<?xml version="1.0" encoding="utf-8"?>
  <set xmlns:android="http://schemas.android.com/apk/res/android"
  android:shareInterpolator="true">
  <translate android:fromXDelta="-100%"
    android:toXDelta="0%" android:fromYDelta="0%"
    android:toYDelta="0%" android:duration="200">
  </translate>
</set>

滑动向左退出。
<?xml version="1.0" encoding="utf-8"?>
 <set xmlns:android="http://schemas.android.com/apk/res/android"
  android:shareInterpolator="true">
  <translate android:fromXDelta="0%"
    android:toXDelta="-100%" android:fromYDelta="0%"
    android:toYDelta="0%" android:duration="200">
  </translate>
</set>

这是如何调用该函数的方法:

openFragment(activity, new MyFragment());

请问如何调用函数openFragment(???,newfragment),以及实现动画滑动的xml代码... - Codelaby

7
请使用FragmentTransaction.replace()代替FragmentTransaction.add()
这本质上相当于为所有当前添加的具有相同containerViewId的片段调用remove(Fragment),然后使用此处给出的相同参数调用add(int, Fragment, String)
第一次调用FragmentTransaction.replace()将仅添加该片段,因为没有要删除的片段。

我无法使用替换功能,因为涉及到网络操作。所以每次访问相同的片段都会再次请求,这会增加开销。 - Mohsin

5

使用此方法检查片段是否已添加:

if(!Fragment.isAdded()){
//add fragment
}

1

根据您的需求,有多种方法可以解决这个问题:

  1. 在按钮被点击一次后禁用或移除该按钮。
  2. 如@hidro所建议的,在调用FragmentTransaction时使用replace()而不是add()。
  3. 保留一个字符串列表,其中包含每个片段添加到UI时的类名。

例如:

List<String> fragments = new ArrayList<String>();

button.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View view) {
        FragmentTransaction ftx = fragmentManager.beginTransaction();
        ftx.add(R.id.main_content, fragment);
        ftx.commit();
        fragments.add(fragment.getClass().toString());
    }
});

在使用FragmenTransaction.commit()添加片段之前,请检查其类是否存在于列表中,如果存在,则不要添加。
再次强调,这3种方法都可行,但选择哪种方法取决于您的应用程序。

我不能对所有按钮执行此操作(禁用btn)。而且替换而不是添加也不是一个好选择,因为我在每个片段上都进行网络操作,这会让我付出更多的代价。如果找不到更好的方法,我期待第三种解决方案。谢谢。 - Mohsin

0
你可以使用片段事务的show()方法。
 FragmentManager fragmentManager = ((ActionBarActivity) activity)
            .getSupportFragmentManager();
        FragmentTransaction ftx = fragmentManager.beginTransaction();

        ftx.setCustomAnimations(R.anim.slide_in_right,
                R.anim.slide_out_left, R.anim.slide_in_left,
                R.anim.slide_out_right);
    if(!fragment.isAdded())
    {
    //add fragment;
ftx.add(R.id.main_content, fragment).comit();
    }
    else
    {
   ftx.show(fragment).comit();
    }

已更新


我使用了它,但是它没有起作用。您能否根据我的代码修改此检查?谢谢。 - Mohsin
我修改了一下,并且从你所写的内容中读出来你正在进行网络调用,因此它将仅在创建片段时进行一次网络调用并且只会在下一次显示它时进行。请在 if 语句中进行网络调用。 - Hulk

0

为了仅添加一次片段,

在将片段添加到返回堆栈之前,您需要每次检查它是否已经被添加过。如果已经添加过,则应弹出该条目并添加另一个条目。

因此,您可以使用以下方法:

boolean fragmentPopped = manager.popBackStackImmediate (backStateName, 0);

如果 fragmentPoppedtrue,那么肯定已经有一个片段被添加到了回退栈并且已经被弹出,现在你可以将你的片段添加到回退栈。可以安全调用以下代码:

ftx.addToBackStack(fragment.getClass().getSimpleName());

如果fragmentPoppedfalse,则没有任何片段添加到后退栈中。
非常好的信息可以在这里获取:here

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接