My Androidアプリは3つのフラグメント:A、B、Cで構成されています。これらはMainActivity
レイアウトで定義された2つのコンテナにロードされます。
アプリが起動すると、left_containerにロードされたfragmentAおよびright_containerのfragmentCが表示されます。
fragmentAでボタンを押すと、FragmentTransaction
がFragmentCによってFragmentBに変更されます。
現時点ではすべてOKです。 ただし、null
を返すため、ロードされたfragmentBへの参照を取得しようとすると問題が発生しますfindFragmentByTag()
。 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 development!
修正しました!トランザクションを行った後にgetSupportFragmentManager().executePendingTransactions()
を呼び出しましたが、うまくいきました!そのメソッドを呼び出した後、findFragmentById()
メソッドとfindFragmentByTag()
メソッドの両方を使用してフラグメントを取得できます。
setRetainInstance(true)
を使用する場合、アクティビティのonCreate
でfindFragmentByTag()
を使用することはできません。 onResumeで行う
ドキュメントを参照してください: setRetainInstance
私はまだ非常に新しいので、謝罪から始めます...
問題は、クラスのインスタンスから適切にアクセスできない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ドキュメントへのリンクがいくつかあります:
私は同じ問題を抱えていて、これを修正するための本当に簡単な方法があることに気付きました。タグを使用する場合は、必ず追加してください
_fragmentTransaction.addToBackStack(null);
_
開発者ガイドに記載されているように、フラグメントが破棄される代わりに再開されるようにメソッドを作成します。
フラグメントを削除するトランザクションを実行するときにaddToBackStack()を呼び出さない場合、トランザクションがコミットされるとそのフラグメントは破棄され、ユーザーはそのフラグメントに戻ることができません。一方、フラグメントを削除するときにaddToBackStack()を呼び出すと、フラグメントは停止し、ユーザーが戻って戻ると後で再開されます。
これは末尾にあります このセクションの 。
作成したフラグメントを参照しようとするたびに、すでにフラグメントが破壊されていたことが判明したため、単純なfindFragmentByTag();
呼び出しでフラグメントが見つからなかった理由を理解しようとして約30分失われました。
お役に立てれば!
この問題も発生していますが、原因はわずかに異なります。 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();
}
_
そして、置換に関するドキュメントを読んだ後:
コンテナに追加された既存のフラグメントを置き換えます。これは、同じcontainerViewIdで追加された現在追加されているすべてのフラグメントに対してremove(Fragment)を呼び出し、次にここで指定された同じ引数でadd(int、Fragment、String)を呼び出すことと本質的に同じです。
remove
の呼び出しはreplace
によって自動的に行われるため、必要ありませんでした。したがって、ft.remove(current)
を削除すると、正常に機能します。
適切な方法でフラグメントを追加または置換していることを確認してください
次のステートメントはフラグメントを追加しますが、getFragmentManager()。findFragmentByTag(tag)を使用するとnullを返します。
transaction.add(R.id.mainContent, fragment);
このように動作します。
transaction.add(R.id.mainContent, fragment, tag);