Android findFragmentByTag() 在使用 replace() 方法执行 FragmentTransaction 后返回 null
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20825600/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
findFragmentByTag() returns null after perform a FragmentTransaction using replace() method
提问by Guillermo Barreiro
My Android app consists three fragments: A, B and C. They're loaded in the two containers defined in the MainActivity
layout.
我的Android应用由三个片段:A,B和C。它们被加载到MainActivity
布局中定义的两个容器中。
When the app is started, it shows the fragmentA loaded in the left_containerand the fragmentC in the right_container.
当应用程序启动时,它会显示在 left_container 中加载的 fragmentA和在 right_container 中加载的fragmentC。
If you press the button in the fragmentA, a FragmentTransaction
changes FragmentCby FragmentB.
如果您按下fragmentA 中的按钮,aFragmentTransaction
将FragmentC更改为FragmentB。
At the moment everything OK. But the trouble appears when I try to get a reference to the loaded fragmentB usingfindFragmentByTag()
, because it returns null
. I've used the method replace in the FragmentTransaction
and I've finished it with commit()
, but there isn't way to call FragmentBmethod. My code:
目前一切正常。但是当我尝试使用 获取对加载的 fragmentB 的引用时出现问题findFragmentByTag()
,因为它返回null
. 我在 中使用了方法 replaceFragmentTransaction
并用 完成了它commit()
,但是没有办法调用FragmentB方法。我的代码:
MainActivity.java:
主活动.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:
片段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!");
}
}
activity_main.xml:
活动_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:
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>
Please help me! I'm a beginner in Android development!
请帮我!我是Android开发的初学者!
回答by Guillermo Barreiro
I've fixed it! I called getSupportFragmentManager().executePendingTransactions()
after doing the transaction and it worked! After calling that method I can get the fragment using both findFragmentById()
and findFragmentByTag()
methods.
我修好了!我getSupportFragmentManager().executePendingTransactions()
在完成交易后打电话,它奏效了!调用该方法后,我可以同时使用findFragmentById()
和findFragmentByTag()
方法获取片段。
回答by oli
if you use setRetainInstance(true)
than you can't use findFragmentByTag()
in onCreate
from the Activity. Do it at onResume
如果你使用setRetainInstance(true)
比你不能使用findFragmentByTag()
在onCreate
从活动。在 onResume 上做
see the documentation: setRetainInstance
请参阅文档:setRetainInstance
回答by Kenny164
I'll start by apologising since I'm still very new myself...
我首先要道歉,因为我自己还是个新手......
I think the problem may be in the declaration of the fragmentTag static String not properly getting access from the class's instances, just change that line to:
我认为问题可能出在 fragmentTag 静态字符串的声明中,无法正确地从类的实例中获取访问权限,只需将该行更改为:
private final static String FRAGMENT_TAG = "FRAGMENTB_TAG"; // using uppercase since it's a constant
Also, I would be more explicit when declaring instances, for example:
另外,我在声明实例时会更明确,例如:
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();
}
I hope you get this sorted, as I seen this question posted earlier and was surprised that it hadn't got any activity yet.
我希望你能解决这个问题,因为我之前看到了这个问题,但很惊讶它还没有任何活动。
Also, here are a couple of links to the android documentation on replace:
此外,这里有几个链接到关于替换的 android 文档:
回答by Panos Gr
I had the same problem and realized that there is a really simple way to fix this. When using a tag please do make sure to add the
我遇到了同样的问题,并意识到有一种非常简单的方法可以解决这个问题。使用标签时,请务必添加
fragmentTransaction.addToBackStack(null);
method so that your Fragment is resumed instead of destroyed as mentioned in the developer guides.
方法,以便您的 Fragment 恢复而不是像开发人员指南中提到的那样销毁。
If you don't call addToBackStack() when you perform a transaction that removes a fragment, then that fragment is destroyed when the transaction is committed and the user cannot navigate back to it. Whereas, if you do call addToBackStack() when removing a fragment, then the fragment is stopped and is later resumed if the user navigates back.
如果在执行删除片段的事务时不调用 addToBackStack(),那么在提交事务时该片段将被销毁并且用户无法导航回它。然而,如果您在删除片段时确实调用了 addToBackStack(),则该片段将停止并在用户返回时恢复。
You can find this at the end of this section.
您可以在本节末尾找到它。
Every time I tried to reference back to my created Fragment, it turns out it had already been destroyed so I lost about 30 minutes trying to figure out why my Fragment was not being found through a simple findFragmentByTag();
call.
每次我试图回溯到我创建的 Fragment 时,结果发现它已经被销毁了,所以我花了大约 30 分钟试图弄清楚为什么我的 Fragment 没有通过一个简单的findFragmentByTag();
调用被找到。
Hope this helps!
希望这可以帮助!
回答by CoolMind
In my case I used the codeto replace and add to BackStack, but set wrong tag:
就我而言,我使用代码替换并添加到 BackStack,但设置了错误的标签:
val fragment = { SomeFragment.newInstance() }
fragmentManager?.replaceAndAddToBackStack(R.id.container, fragment, WrongAnotherFragment.TAG)
Of course, supportFragmentManager.findFragmentByTag(SomeFragment.TAG)
didn't find SomeFragment
.
当然,supportFragmentManager.findFragmentByTag(SomeFragment.TAG)
没找到SomeFragment
。
回答by lm2a
Be sure you are adding or replacing the fragment in the proper way
确保以正确的方式添加或替换片段
Next statement will add the fragment but it will return null when using getFragmentManager().findFragmentByTag(tag):
下一条语句将添加片段,但在使用 getFragmentManager().findFragmentByTag(tag) 时将返回 null:
transaction.add(R.id.mainContent, fragment);?
This way it will work;
这样它就会起作用;
transaction.add(R.id.mainContent, fragment, tag);
回答by Yuchen Zhong
We are also seeing this problem but the cause is slightly different. The suggested solution by https://stackoverflow.com/a/21170693/1035008doesn't work for us.
我们也看到了这个问题,但原因略有不同。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();
}
And after reading the documentation about replace:
阅读有关替换的文档后:
Replace an existing fragment that was added to a container. This is essentially the same as calling remove(Fragment) for all currently added fragments that were added with the same containerViewId and then add(int, Fragment, String) with the same arguments given here.
替换添加到容器中的现有片段。这本质上与为所有当前添加的片段调用 remove(Fragment) 相同,这些片段使用相同的 containerViewId 添加,然后使用此处给出的相同参数 add(int, Fragment, String) 。
I realize that the remove
call was not necessary since it is done by replace
automatically. So after delete ft.remove(current)
, it works fine.
我意识到remove
调用是不必要的,因为它是replace
自动完成的。所以在 delete 之后ft.remove(current)
,它工作正常。