【问题标题】:Fragment.isAdded returns true after fragment removed from a containerFragment.isAdded 在从容器中删除片段后返回 true
【发布时间】:2012-05-23 07:03:45
【问题描述】:

我有一个布局如下的活动

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal" >

    <FrameLayout
        android:id="@+id/frameLayoutA"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:layout_weight="1" >
    </FrameLayout>
    <FrameLayout
        android:id="@+id/frameLayoutB"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:layout_weight="1" >
    </FrameLayout>
</LinearLayout>

在活动的onCreate中,我在frameLayoutA中加载Fragment_A,在frameLayoutB中加载Fragment_B。

public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    fmA=(FrameLayout) findViewById(R.id.frameLayoutA);
    fmB=(FrameLayout) findViewById(R.id.frameLayoutB);

    fragA=new FragmentA();
    fragB=new FragmentB();
    fragC=new FragmentC();
    addFragmentsInActivity(R.id.frameLayoutA,fragA);
    addFragmentsInActivity(R.id.frameLayoutB,fragB);
}

public void addFragmentsInActivity(int id, Fragment fragment)
{
    FragmentManager fragmentManager = getFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
    fragmentTransaction.add(id, fragment);
    fragmentTransaction.commit();
}

使用菜单操作我想在 frameLayoutA 中加载 Fragment_B,在 frameLayoutB 中加载 Fragment_C。菜单操作是:

    removeFragmentsInActivity(R.id.frameLayoutB,fragB);
    addFragmentsInActivity(R.id.frameLayoutB,fragC);
    if(!fragB.isAdded()){
            Log.e("check", "fragB already removed from frameLayoutB");
        removeFragmentsInActivity(R.id.frameLayoutB,fragB);
        addFragmentsInActivity(R.id.frameLayoutA,fragB);
    }
    else{
        Log.e("check", "fragB already added");
    }    

    public void removeFragmentsInActivity(int id, Fragment fragment)
    {
        FragmentManager fragmentManager = getFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.remove(fragment);
        fragmentTransaction.commit();
    }

Fragment_B 不显示在 frameLayoutA 中。 frameLayoutA 显示 Fragment_A。再次单击菜单操作时,会加载 Fragment_B。

调试我发现 fragB.isAdded() 在 fragB.remove() 操作完成后返回 true。在第二个菜单操作期间,fragB.isAdded() 返回 false 并执行 fragB.add() 并且 FragmentB 显示在 frameLayoutA 中。

我知道提交是一个异步操作。 isAdded 返回 true,因为提交是异步的,并且删除操作提交直到调用 fragB.isAdded() 时才完成。是真的吗?

请提出解决问题的可能解决方案或方法。

问候, 维宝

【问题讨论】:

    标签: android android-fragments


    【解决方案1】:

    是的,事务是异步提交的。如果你想在执行isAdded之前确保所有的事务都已经完成,运行:

    getFragmentManager().executePendingTransactions();
    

    来自executePendingTransactions() 的文档:

    在 FragmentTransaction 提交后 FragmentTransaction.commit(),预定执行 在进程的主线程上异步。如果你想 立即执行任何此类挂起的操作,您可以调用它 函数(仅来自主线程)这样做。请注意,所有回调 和其他相关行为将在此调用中完成,所以 注意从哪里调用它。

    所以你的代码应该是这样的:

    removeFragmentsInActivity(R.id.frameLayoutB,fragB);
    addFragmentsInActivity(R.id.frameLayoutB,fragC);
    getFragmentManager().executePendingTransactions();
    if(!fragB.isAdded()){
            Log.e("check", "fragB already removed from frameLayoutB");
        removeFragmentsInActivity(R.id.frameLayoutA,fragA);
        addFragmentsInActivity(R.id.frameLayoutA,fragB);
    }
    else{
        Log.e("check", "fragB already added");
    }
    

    注意还修复了片段 A 的删除。

    【讨论】:

      【解决方案2】:

      也许你可以像这样捕获 FragmentTransaction 的提交

      private void commitFragmentTransaction(final FragmentTransaction ft, boolean allowStateLoss, boolean now) {
          if (ft == null || ft.isEmpty()) {
              return;
          }
      
          if (allowStateLoss) {
              if (now) {
                  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                      ft.commitNowAllowingStateLoss();
                  } else {
                      ft.commitAllowingStateLoss();
                      mFragmentManager.executePendingTransactions();
                  }
              } else {
                  ft.commitAllowingStateLoss();
              }
          } else {
              if (now) {
                  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                      ft.commitNow();
                  } else {
                      ft.commit();
                      mFragmentManager.executePendingTransactions();
                  }
              } else {
                  ft.commit();
              }
          }
      }
      

      commitNow() 和 commitNowAllowingStateLoss() 在 API 级别 24 中添加

      调用 commitNow 比调用 commit() 后跟 executePendingTransactions() 更可取,因为后者会产生尝试提交所有当前未决事务的副作用,无论这是否是所需的行为。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-21
        • 2021-09-29
        • 1970-01-01
        • 1970-01-01
        • 2015-10-01
        • 1970-01-01
        • 2016-01-19
        相关资源
        最近更新 更多