web-dev-qa-db-ja.com

replace()メソッドを使用してFragmentTransactionを実行した後、findFragmentByTag()はnullを返します

My Androidアプリは3つのフラグメント:A、B、Cで構成されています。これらはMainActivityレイアウトで定義された2つのコンテナにロードされます。

アプリが起動すると、left_containerにロードされたfragmentAおよびright_containerのfragmentCが表示されます。

fragmentAでボタンを押すと、FragmentTransactionFragmentCによって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!

33

修正しました!トランザクションを行った後にgetSupportFragmentManager().executePendingTransactions()を呼び出しましたが、うまくいきました!そのメソッドを呼び出した後、findFragmentById()メソッドとfindFragmentByTag()メソッドの両方を使用してフラグメントを取得できます。

66

setRetainInstance(true)を使用する場合、アクティビティのonCreatefindFragmentByTag()を使用することはできません。 onResumeで行う

ドキュメントを参照してください: setRetainInstance

3
oli

私はまだ非常に新しいので、謝罪から始めます...

問題は、クラスのインスタンスから適切にアクセスできない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トレーニング-置換

Androidリファレンス-置換

1
Kenny164

私は同じ問題を抱えていて、これを修正するための本当に簡単な方法があることに気付きました。タグを使用する場合は、必ず追加してください

_fragmentTransaction.addToBackStack(null); 
_

開発者ガイドに記載されているように、フラグメントが破棄される代わりに再開されるようにメソッドを作成します。

フラグメントを削除するトランザクションを実行するときにaddToBackStack()を呼び出さない場合、トランザクションがコミットされるとそのフラグメントは破棄され、ユーザーはそのフラグメントに戻ることができません。一方、フラグメントを削除するときにaddToBackStack()を呼び出すと、フラグメントは停止し、ユーザーが戻って戻ると後で再開されます。

これは末尾にあります このセクションの

作成したフラグメントを参照しようとするたびに、すでにフラグメントが破壊されていたことが判明したため、単純なfindFragmentByTag();呼び出しでフラグメントが見つからなかった理由を理解しようとして約30分失われました。

お役に立てれば!

1
Panos Gr

この問題も発生していますが、原因はわずかに異なります。 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)を削除すると、正常に機能します。

0
Yuchen Zhong

適切な方法でフラグメントを追加または置換していることを確認してください

次のステートメントはフラグメントを追加しますが、getFragmentManager()。findFragmentByTag(tag)を使用するとnullを返します。

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


このように動作します。

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