37

我的 Android 应用程序包含三个片段: A、B 和 C。它们被加载到MainActivity布局中定义的两个容器中。

当应用程序启动时,它会显示在 left_container 中加载的 fragmentA和在 right_container 中加载的fragmentC

如果您按下fragmentA中的按钮,a将FragmentCFragmentTransaction更改为FragmentB

目前一切正常。但是,当我尝试使用 获取对已加载片段 B 的引用时,就会出现问题 findFragmentByTag(),因为它会返回null。我在 中使用了方法 replaceFragmentTransaction并用 完成了它commit(),但是没有办法调用FragmentB方法。我的代码:

MainActivity.java:

 public class MainActivity extends Activity{
 static String fragmentTag = "FRAGMENTB_TAG";

 @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);


    //Adds the left container's fragment
    getFragmentManager().beginTransaction().add(R.id.left_container, new FragmentA()).commit(); //Adds the fragment A to the left container

    //Adds the right container's fragment
    getFragmentManager().beginTransaction().add(R.id.right_container, new FragmentC()).commit(); //Adds the Fragment C to the right container
 }

 /**
 * Called when the button "Activate Fragment B" is pressed
 */
public void buttonListener(View v){

        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.replace(R.id.right_container, new FragmentB(),fragmentTag); //Replaces the Fragment C previously in the right_container with a new Fragment B
        ft.commit(); //Finishes the transaction


        //!!HERE THE APP CRASHES (java.lang.NullPointerException = findFragmentByTag returns null
        ((FragmentB) getFragmentManager().findFragmentByTag(fragmentTag)).testView();


    }
}

片段B.java:

public class FragmentB extends Fragment {

public View onCreateView(LayoutInflater inflater,
        ViewGroup container,
        Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment_b, container,false);

}


/**
 * Gets a reference to the text_fragment_b TextView and calls its method setText(), changing "It doesn't work" text by "It works!"
 */
public void testView(){
    TextView tv = (TextView)getView().findViewById(R.id.text_fragment_b);
    tv.setText("It works!");
}

}

活动主.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >

<FrameLayout android:id="@+id/left_container" android:layout_width="0px" android:layout_weight="50" android:layout_height="match_parent"/>    
<FrameLayout android:id="@+id/right_container" android:layout_width="0px" android:layout_weight="50" android:layout_height="match_parent"/>

</LinearLayout>

片段_b.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" 
android:layout_margin="5sp">

<TextView 
    android:id="@+id/text_fragment_b"
    android:text="It doesn't works!"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>

</LinearLayout>

请帮我!我是Android开发的初学者!

4

8 回答 8

70

我已经修好了!getSupportFragmentManager().executePendingTransactions()我在完成交易后打电话,它成功了!调用该方法后,我可以同时使用findFragmentById()findFragmentByTag()方法获取片段。

于 2014-01-16T19:09:11.640 回答
3

如果你使用setRetainInstance(true)比你不能从活动findFragmentByTag()中使用。onCreate在 onResume 上做

请参阅文档:setRetainInstance

于 2015-09-15T18:17:47.487 回答
1

我首先要道歉,因为我自己还是个新手……

我认为问题可能在于 fragmentTag 静态字符串的声明没有正确地从类的实例中获取访问权限,只需将该行更改为:

private final static String FRAGMENT_TAG = "FRAGMENTB_TAG"; // using uppercase since it's a constant

另外,在声明实例时我会更加明确,例如:

public void buttonListener(View v){

    FragmentTransaction ft = getFragmentManager().beginTransaction();
    ft.replace(R.id.right_container, new FragmentB(), FRAGMENT_TAG);
    ft.commit();

    FragmentB fragB = (FragmentB) getFragmentManager().findFragmentByTag(FRAGMENT_TAG);
    fragB.testView();
}

我希望你能得到这个排序,因为我之前看到过这个问题,并且很惊讶它还没有任何活动。

此外,这里有几个关于替换的 android 文档的链接:

Android 培训 - 替换

Android 参考 - 替换

于 2013-12-29T18:37:10.967 回答
1

我遇到了同样的问题,并意识到有一种非常简单的方法可以解决这个问题。使用标签时,请务必添加

fragmentTransaction.addToBackStack(null); 

方法,以便恢复您的 Fragment 而不是如开发人员指南中所述被销毁。

如果您在执行删除片段的事务时不调用 addToBackStack(),则该片段在事务提交时被销毁并且用户无法导航回它。然而,如果您在删除片段时确实调用了 addToBackStack(),那么片段会停止,然后如果用户导航回来,则会恢复。

您可以在本节末尾找到它。

每次我试图引用我创建的 Fragment 时,事实证明它已经被销毁了,所以我花了大约 30 分钟试图找出为什么我的 Fragment 没有通过一个简单的findFragmentByTag();调用找到。

希望这可以帮助!

于 2018-10-17T12:42:34.833 回答
0

确保您以正确的方式添加或替换片段

下一条语句将添加片段,但在使用 getFragmentManager().findFragmentByTag(tag) 时将返回 null:

transaction.add(R.id.mainContent, fragment);


这样它就可以工作了;

transaction.add(R.id.mainContent, fragment, tag);
于 2016-10-16T10:33:55.880 回答
0

我们也看到了这个问题,但原因略有不同。https://stackoverflow.com/a/21170693/1035008建议的解决方案对我们不起作用。

void updateFragment(Fragment newFragment) {
    FragmentTransaction ft = getFragmentManager().beginTransaction();

    // We have these 2 lines extra
    Fragment current = getChildFragmentManager().findFragmentByTag(fragmentTag);           
    if (current != null) { ft.remove(current); }

    ft.replace(R.id.right_container, newFragment, fragmentTag); //Replaces the Fragment C previously in the right_container with a new Fragment B
    ft.commit(); //Finishes the transaction

    //!!HERE THE APP CRASHES (java.lang.NullPointerException = findFragmentByTag returns null
    ((FragmentB) getFragmentManager().findFragmentByTag(fragmentTag)).testView();
}

在阅读有关替换的文档后:

替换已添加到容器中的现有片段。这本质上与为所有当前添加的片段调用 remove(Fragment) 相同,这些片段使用相同的 containerViewId 添加,然后使用此处给出的相同参数调用 add(int, Fragment, String)。

我意识到remove调用是不必要的,因为它是replace自动完成的。所以在 delete 之后ft.remove(current),它工作正常。

于 2016-12-14T23:18:09.287 回答
0

就我而言,我使用代码替换并添加到 BackStack,但设置了错误的标签:

val fragment = { SomeFragment.newInstance() }
fragmentManager?.replaceAndAddToBackStack(R.id.container, fragment, WrongAnotherFragment.TAG)

当然,supportFragmentManager.findFragmentByTag(SomeFragment.TAG)没找到SomeFragment

于 2020-04-02T16:52:00.013 回答
0

对我来说,这可能是super.onCreate(savedInstanceState);我在尝试使用findFragmentByTag.

super.onCreate(savedInstanceState)按顺序向上移动,它开始为我工作。

于 2020-06-12T13:13:26.920 回答