为什么detch()不能处理FragmentTransaction而remove()呢?

时间:2014-03-14 15:00:30

标签: android android-fragments

我正在处理TabHost,其标签与Fragment相关联(每个标签不同)。这些Fragment中的每一个都在另一个Fragment的实例中,这是一个具有两种状态的登录栏:登录或不登录。

退出示例

Logged out

登录示例

Logged in

在布局术语中,这些状态中的每一个都已关联View(非登录情况下为TextView,登录情况为LinearLayout,因此如果其中一个是VISIBLE,则另一个是GONE。根据选项卡内容,这是其中一个(firsttab.xml)的代码示例:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:ads="http://schemas.android.com/apk/lib/com.google.android.gms.ads"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:background="#0000FF"
  android:orientation="vertical">

  <!-- That's the login bar -->
  <fragment 
    android:id="@+id/firsttab_loginrow"
    class="com.mydomain.myproject.LoginRowFragment"
    android:tag="1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

  <LinearLayout
    android:id="@+id/firsttab_content"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="10dp"
    android:gravity="center"
    android:orientation="horizontal">
  </LinearLayout>
</LinearLayout>

内部片段(com.mydomain.myproject.LoginRowFragment)以这种方式定义:

<!-- If the user is not logged in -->
<TextView
   android:id="@+id/identification_nologin"
   android:layout_width="wrap_content"
   android:layout_height="match_parent"
   android:textColor="#FFFFFF" />

<!-- if the user is logged in -->
<LinearLayout
   android:id="@+id/identification_didlogin"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:orientation="horizontal" >

   ...      
</LinearLayout>

一般模式可能是这样的:

Schema

当我通过attach()detach()对应的父母Fragment(在这种情况下,firsttab.xml处理标签更改事件时,问题就出现了)。在连接/分离父级之前,我尝试detach()登录Fragment(内部登录),但它不会触发onDetach()回调。 attach()时会发生同样的情况。奇怪的是,如果我用.detach()替换.remove(),它就可以了。

@Override
public void onTabChanged(final String tag) {
  final TabInfo newTab = mTabInfo.get(tag);

  if (lastTab != newTab) {

    final FragmentTransaction ft = this.getSupportFragmentManager().beginTransaction();
    if ((lastTab != null) && (lastTab.getFragment() != null)) {

      // This is where it fails detaching. tabInfo is just a structure where I store some data
      // about the tabs to handle them. If I use remove() instead of the next detach() on loginFrag,
      // the onAttach()/onDetach() callbacks are not called. I'm quite sure everything is ok, loginFrag
      // is not null, it's actually the Fragment that should be detached, etc.

      final Fragment loginFrag = (Fragment) lastTab.getFragment().getActivity().getSupportFragmentManager().findFragmentById(lastTab.getLoginFragId());
      ft.detach(loginFrag);

      ft.detach(lastTab.getFragment());
    }

    if (newTab != null) {
      if (newTab.getFragment() == null) {
        final TabFragmentInflater tabInf = new TabFragmentInflater();
        newTab.setFragment(Fragment.instantiate(this, tabInf.getClass().getName(), newTab.getArgs()));
        ft.add(R.id.realtabcontent, newTab.getFragment(), newTab.getTag());
      }
      else
        ft.attach(newTab.getFragment());
    }

    ft.commit();
    this.getSupportFragmentManager().executePendingTransactions();

    lastTab = newTab;
  }
}

所以问题如下:

为什么 onAttach() / onDetach()回调在使用LoginRowFragment.attach()时未在.detach()课程中触发,但如果我分别使用.add().remove()会被解雇?

1 个答案:

答案 0 :(得分:4)

您无法删除已在布局XML文件中声明的片段实例(按设计)

使用FragmentTransactions时,您将操纵包含片段布局的ViewGroups。

在布局中声明片段/类时,它是View层次结构的一部分,因此您无法将其删除。

但是,您可以在该布局中添加一个新片段,因为它将充当容器。

尝试从以下位置更改布局:

    <fragment 
      android:id="@+id/firsttab_loginrow"
      class="com.mydomain.myproject.LoginRowFragment"
      android:tag="1"
      android:layout_width="match_parent"
      android:layout_height="wrap_content" />

为:

    <FrameLayout 
      android:id="@+id/firsttab_loginrow"
      android:tag="1"
      android:layout_width="match_parent"
      android:layout_height="wrap_content" />

根据您的目的创建一个FragmentTransaction来添加/替换/显示/隐藏。