获取当前片段对象

181

在我的main.xml中,我有以下代码:

  <FrameLayout
        android:id="@+id/frameTitle"
        android:padding="5dp"
        android:layout_height="wrap_content"
        android:layout_width="fill_parent"
        android:background="@drawable/title_bg">
            <fragment
              android:name="com.fragment.TitleFragment"
              android:id="@+id/fragmentTag"
              android:layout_width="fill_parent"
              android:layout_height="wrap_content" />

  </FrameLayout>

我正在这样设置片段对象

FragmentManager fragmentManager = activity.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Fragment newFragment = new FragmentType1();
fragmentTransaction.replace(R.id.frameTitle, casinodetailFragment, "fragmentTag");

// fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();

代码正在设置不同类型的Fragment对象(FragmentType2,FragmentType3,...),并在不同的时间进行设置。现在,在某个时间点上,我需要确定目前存在哪个对象。

简而言之,我需要做类似以下的事情:

Fragment currentFragment = //what is the way to get current fragment object in FrameLayout R.id.frameTitle

我尝试了以下方法:

TitleFragment titleFragmentById = (TitleFragment) fragmentManager.findFragmentById(R.id.frameTitle);
    TitleFragment titleFragmentByTag = (TitleFragment) fragmentManager.findFragmentByTag("fragmentTag");

但是这两个对象(titleFragmentById和titleFragmentByTag)都是null
我错过了什么吗?
我正在使用Compatibility Package, r3并且为API level 7开发。

findFragmentById()findFragmentByTag()将在我们使用fragmentTransaction.replacefragmentTransaction.add设置片段时起作用,但是如果我们在xml中设置对象(就像我在我的main.xml中所做的那样),它们将返回null。我想我在我的XML文件中漏掉了一些东西。


相关 - https://dev59.com/vGoy5IYBdhLWcg3wFqFT#21104084 - Jay Wick
@CommonsWare的回答有帮助吗?因为我仍然得到null。 - IntoTheDeep
19个回答

269

现在我需要确定当前是哪个对象

FragmentManager上调用findFragmentById(),并确定哪个片段位于您的R.id.frameTitle容器中。

如果您正在使用现代应用程序中应该使用的androidx版本的Fragment,请在您的FragmentActivity/AppCompatActivity上使用getSupportFragmentManager()而不是getFragmentManager()


2
感谢您的回复。如果我们使用fragmentTransaction.replacefragmentTransaction.add来设置片段,它将起作用,但如果我们在xml中设置它,则无法获取。请查看我的第二次编辑。 - Labeeb Panampullan
10
@Labeeb P:您不能修改在布局资源中声明的片段。 - CommonsWare
创建一个类来保存当前可见的选项卡/片段也可以,我刚试过了。希望没有失败。 - Skynet
1
@MuhammadBabar:在调用事务的commit()之后,您可以尝试在FragmentManager上使用executePendingTransactions(),虽然我没有尝试过这样做。或者您可以使用setContentView()来使用带有<fragment>标记的布局文件。这两种方法都是同步发生的,因此片段将存在于您使用executePendingTransaction()setContentView()onCreate()调用本身中。否则,普通的FragmentTransaction会异步处理,而且在onCreate()结束时它甚至还没有开始处理。 - CommonsWare
我刚刚浏览了一堆相关内容 - 似乎主要的混淆是因为findFragmentByTag()没有使用BackStackEntry提供的标记(有点假设)。这两个标记是独立指定的 - 如果您想使用条目中的标记查找片段,则findFragmentByTag()会使用片段上的getTag(),您必须单独指定它。如果将其保留为空,则不会默认为条目引用的片段的标记。 - peterk
显示剩余15条评论

116

试试这个,

Fragment currentFragment = getActivity().getFragmentManager().findFragmentById(R.id.fragment_container);

这将为您提供当前的片段,然后您可以将其与片段类进行比较并执行您需要做的事情。

    if (currentFragment instanceof NameOfYourFragmentClass) {
     Log.v(TAG, "find the current fragment");
  }

放在哪里呢? - Anand Savjani
13
有时候你需要使用getSupportFragmentManager(),否则没有添加support的话可能会得到空值。 - Muz
从“NAME OF YOUR FRAGMENT CLASS”周围移除引号。 - Alan Nelson

38

我认为你可以使用onAttachFragment事件来捕获当前活动的片段。

@Override
public void onAttachFragment(Fragment fragment) {
    // TODO Auto-generated method stub
    super.onAttachFragment(fragment);

    Toast.makeText(getApplicationContext(), String.valueOf(fragment.getId()), Toast.LENGTH_SHORT).show();

}

3
我可以确定我所附着的片段。我的疑问是,当我改变方向时,我需要显示相同的视图而不是另一个视图,那么该如何实现呢? - Androi Developer
7
这种方法不可行,因为在返回时它无法更新活动片段。 - Justin
1
@Justin 所以我们只需要在弱引用列表中使用 onDetach。 - letroll

13

我认为你应该做:

Fragment currentFragment = fragmentManager.findFragmentByTag("fragmentTag");

这是因为您将"fragmentTag"标签设置为您添加的最后一个片段(当您调用replace时)。


谢谢,我已经更正了。这是一个打字错误,在编写问题时犯了一个错误。如果我们使用fragmentTransaction.replacefragmentTransaction.add设置片段,它就可以工作,但如果我们在xml中设置它,则无法获取。请查看我的编辑2。 - Labeeb Panampullan
2
这个解决方案不是意味着你必须为多个片段放置相同的标签吗?否则你怎么知道fragmentTag是当前片段的标签呢? - Thupten

12

您可以获取片段列表,并查看最后一个。

    FragmentManager fm = getSupportFragmentManager();
    List<Fragment> fragments = fm.getFragments();
    Fragment lastFragment = fragments.get(fragments.size() - 1);

但有时候(当你返回导航时),列表的大小保持不变,但是最后一些元素为空。因此,在遍历该列表时,我迭代到最后一个非空片段并使用了它。

    FragmentManager fm = getSupportFragmentManager();
    if (fm != null) {
        List<Fragment> fragments = fm.getFragments();
        if (fragments != null) {
            for(int i = fragments.size() - 1; i >= 0; i--){
                Fragment fragment = fragments.get(i);
                if(fragment != null) {
                    // found the current fragment

                    // if you want to check for specific fragment class
                    if(fragment instanceof YourFragmentClass) {
                        // do something
                    }
                    break;
                }
            }
        }
    }

3
不要使用 getFragments() 方法。它被标记为 @hide,不应该包含在支持库 jar 中。它不应被视为导出 API 的一部分。 - James Wald
嘿,那么他们应该创建一个方法,让你可以像getFragments()一样做,因为你经常需要它。我认为现在它实际上是公开可用的了。 - EpicPandaForce

10
这是最简单的解决方案,适用于我。
1.) 你添加你的片段。
ft.replace(R.id.container_layout, fragment_name, "fragment_tag").commit();

2.)

FragmentManager fragmentManager = getSupportFragmentManager();

Fragment currentFragment = fragmentManager.findFragmentById(R.id.container_layout);

if(currentFragment.getTag().equals("fragment_tag"))

{

 //Do something

}

else

{

//Do something

}

9
可能有点晚,但我希望它能帮到其他人。另外@CommonsWare已经发布了正确的答案。
FragmentManager fm = getSupportFragmentManager();
Fragment fragment_byID = fm.findFragmentById(R.id.fragment_id);
//OR
Fragment fragment_byTag = fm.findFragmentByTag("fragment_tag");

9
由于您可能不知道ID或标签,因此无法获取活动片段。 - Justin

7
您可以在父Activity类中创建字段:

您可以在父Activity类中创建字段:

public class MainActivity extends AppCompatActivity {

    public Fragment fr;

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

}

然后在每个片段类内部:

public class SomeFragment extends Fragment {

@Override
    public View onCreateView(LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {

        ((MainActivity) getActivity()).fr = this;
}

您的“fr”字段是当前片段对象。
使用popBackStack()也可以正常工作。

6
也许最简单的方法是:
public MyFragment getVisibleFragment(){
    FragmentManager fragmentManager = MainActivity.this.getSupportFragmentManager();
    List<Fragment> fragments = fragmentManager.getFragments();
    for(Fragment fragment : fragments){
        if(fragment != null && fragment.getUserVisibleHint())
            return (MyFragment)fragment;
    }
    return null;
}

这对我有用


4

我知道已经有一段时间了,但为了帮助别人,我会在这里提供一些信息。

迄今为止(并被选中的)最好的答案是CommonsWare的答案。我遇到了与发布的问题相同的问题,如下所示:

MyFragmentClass fragmentList = 
            (MyFragmentClass) getSupportFragmentManager().findFragmentById(R.id.fragementID);

返回值一直为空。我的错误非常愚蠢,在我的xml文件中:

<fragment
    android:tag="@+id/fragementID"
    android:name="com.sf.lidgit_android.content.MyFragmentClass"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
/>

错误在于我使用了android:tag而不是android:id

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