使用replace()方法执行FragmentTransaction后,findFragmentByTag()返回null

时间:2013-12-29 13:27:13

标签: android android-fragments fragmenttransaction

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

当应用启动时,它会显示 fragmentA加载在left_container 中, fragmentC加载在right_container 中。

如果按 fragmentA 中的按钮,FragmentTransaction会通过 FragmentB 更改 FragmentC

此刻一切都好。 但是当我尝试使用 findFragmentByTag()获取对加载的fragmentB的引用时会出现问题,因为它返回null。我已经在FragmentTransaction中使用了替换方法,并且我已经使用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();


    }
}

FragmentB.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!");
}

}

activity_main.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>

fragment_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开发的初学者!

8 个答案:

答案 0 :(得分:64)

我修好了!在完成交易后我打电话给getSupportFragmentManager().executePendingTransactions()并且它有效!调用该方法后,我可以使用findFragmentById()findFragmentByTag()方法获取片段。

答案 1 :(得分:3)

如果您使用soft kill,则无法在活动setRetainInstance(true)中使用findFragmentByTag()。在onResume上做它

请参阅文档:setRetainInstance

答案 2 :(得分:1)

我开始道歉,因为我自己还很新......

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

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 Training - Replace

Android Reference - Replace

答案 3 :(得分:1)

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

fragmentTransaction.addToBackStack(null); 

方法,以便您的Fragment可以恢复而不是像开发人员指南中提到的那样销毁。

  

如果在执行删除片段的事务时未调用addToBackStack(),则在提交事务时该片段将被销毁,并且用户无法导航回该片段。而如果您在删除片段时确实调用addToBackStack(),则该片段将停止,并且如果用户向后导航,该片段将在以后恢复。

您可以在of this section的末尾找到它。

每次我尝试引用创建的Fragment时,事实证明它已被销毁,因此我浪费了大约30分钟的时间,试图找出为什么通过简单的findFragmentByTag();调用找不到我的Fragment的原因。

希望这会有所帮助!

答案 4 :(得分:0)

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

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

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


这样它会起作用;

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

答案 5 :(得分:0)

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

using namespace std;

阅读有关替换的文档后

  

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

我意识到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自动完成的。所以在删除replace之后,它运行正常。

答案 6 :(得分:0)

就我而言,我使用the code替换并添加到BackStack,但是设置了错误的标记:

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

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

答案 7 :(得分:0)

对于我来说,尝试使用super.onCreate(savedInstanceState);访问Fragment之后,我打电话给findFragmentByTag可能是一个新手错误。

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