【问题标题】:findFragmentByTag() returns null after perform a FragmentTransaction using replace() methodfindFragmentByTag() 在使用 replace() 方法执行 FragmentTransaction 后返回 null
【发布时间】:2014-01-16 12:22:48
【问题描述】:

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

应用启动时,显示在left_container中加载的fragmentA在right_container中的fragmentC

如果您按下 fragmentA 中的按钮,FragmentTransaction 会将 FragmentC 更改为 FragmentB

目前一切正常。 但当我尝试使用 findFragmentByTag() 获取对已加载片段B 的引用时出现问题,因为它返回null。我在FragmentTransaction 中使用了replace 方法,并用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开发的初学者!

【问题讨论】:

    标签: android android-fragments fragmenttransaction


    【解决方案1】:

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

    【讨论】:

    • 我宁愿覆盖 onAttachFragment 并在片段准备好时采取行动。
    • 我不明白这是如何解决问题的,也不知道在哪里放置 executePendingTransactions()。
    • @igor-ganapolsky 你必须在调用 FragmentTransaction 的 .commit() 方法之后输入 executePendingTransactions()。这会强制系统执行尚未完成的事务。
    • 它对我不起作用。在commit() 之后添加它,仍然有一个null 值片段
    • 不高兴。即使在.commit() 调用之后放置getFragmentManager().executePendingTransactions();,仍然会为空。
    【解决方案2】:

    如果您使用setRetainInstance(true),则不能在活动中的onCreate 中使用findFragmentByTag()。在 onResume 执行此操作

    查看文档:setRetainInstance

    【讨论】:

      【解决方案3】:

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

      我认为问题可能在于 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 Training - Replace

      Android Reference - Replace

      【讨论】:

      • 它没有用。尽管您对我说进行了更改,但 findFragmentByTag() 方法仍然返回 null。
      • 然后尝试用普通字符串值替换 FRAGMENT_TAG,例如 ft.replace(R.id.right_container, new FragmentB(), "fragmentB");
      • 两者都不起作用。我无法在我的代码中找到错误,我已经尝试了很多更改,但我仍然在方法 findFragmentByTag() 中得到一个空片段
      • @Kenny164 FRAGMENT_TAG 无论如何都是一个字符串常量。更换它有什么意义??
      【解决方案4】:

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

      fragmentTransaction.addToBackStack(null); 
      

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

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

      你可以在末尾找到这个of this section

      每次我尝试引用我创建的 Fragment 时,结果发现它已经被销毁了,所以我浪费了大约 30 分钟试图通过简单的findFragmentByTag(); 调用找出我的 Fragment 没有被找到的原因。

      希望这会有所帮助!

      【讨论】:

        【解决方案5】:

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

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

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

        

        这样就可以了;

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

        【讨论】:

          【解决方案6】:

          我们也看到了这个问题,但原因略有不同。 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 自动完成的。所以删除ft.remove(current)后,它工作正常。

          【讨论】:

            【解决方案7】:

            在我的例子中,我使用the code 替换并添加到 BackStack,但设置了错误的标签:

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

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

            【讨论】:

              【解决方案8】:

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

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2017-12-22
                • 2018-07-14
                • 1970-01-01
                • 2014-03-04
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多