web-dev-qa-db-ja.com

例外が発生しました:フラグメントは既にアクティブです

フラグメント;

MyFragment myFrag = new MyFragment();

このフラグメントにバンドルデータを追加しました。

Bundle bundle = new Bundle(); 
bundle.putString("TEST", "test");
myFrag.setArguments(bundle);

次に、I replace old fragment with this fragment and put on backstack

//replace old fragment
fragmentTransaction.replace(R.id.fragment_placeholder, myFrag, "MyTag");
//put on backstack
fragmentTransaction.addToBackStack(null);
//commit & get transaction ID
int transId = fragmentTransaction.commit();

後で、I pop backstack上記のトランザクションID(transId)で:

//pop the transaction from backstack
fragmentManager.popBackStack(transId,FragmentManager.POP_BACK_STACK_INCLUSIVE); 

後で、フラグメントに再度引数としてバンドルデータを設定します(myFrag):

//Got Java.lang.IllegalStateException: fragment already active
myFrag.setArguments(bundle);

ご覧のとおり、上記のコードには例外がありましたJava.lang.IllegalStateException: fragment already active理由がわかりませんmyFragトランザクションをバックスタックからポップしましたが、まだアクティブです、とにかく、例外を受け取ったので、フラグメントを非アクティブにする以外に選択肢はありません。

Fragment activeFragment = fragMgr.findFragmentByTag("MyTag");
fragmentTransaction.remove(activeFragment);

フラグメントを非アクティブにする方法が見つからなかったため、上記のコードが本当にフラグメントをde-activeできるかどうかわかりません。 :(

その後、フラグメントmyFragにバンドルデータを再度設定しようとすると、同じエラーが発生しました。

Java.lang.IllegalStateException: fragment already active

フラグメントを削除しても、まだアクティブなようです...なぜ?フラグメントを非アクティブにする方法?

57
Leem.fin

setArguments(Bundle args) ソースを読むと、理解に役立ちます。

/**
* Supply the construction arguments for this fragment.  This can only
* be called before the fragment has been attached to its activity; that
* is, you should call it immediately after constructing the fragment.  The
* arguments supplied here will be retained across fragment destroy and
* creation.
*/
public void setArguments(Bundle args) {

    if (mIndex >= 0) {
        throw new IllegalStateException("Fragment already active");
    }
    mArguments = args;
}

同じ Fragment のコードで setArguments(Bundle args) を再度使用することはできません。あなたがしたいことは、 新しい フラグメント そして、引数を再設定します。または、 getArguments() を使用してから、バンドルのputメソッドを使用して値を変更できます。

149
Assaf Gamliel

新しいフラグメントを追加する前に、前のフラグメントを削除してみてください。 https://stackoverflow.com/a/6266144/969325

1
Warpzit

remove()フラグメントのステータスを非アクティブに変更します。あなたの場合、remove(..)の後にcommit()を呼び出さなかっただけです。

fragmentTransaction.remove(activeFragment);

Remove()の後にcommit()も実行します。

fragmentTransaction.remove(activeFragment).commit();
1
Joshua

フラグメントからパブリックメソッドを呼び出すだけ

if(userFragment==null){
                    userFragment = new UserFragment();
                    Bundle bundle = new Bundle();
                    bundle.putString(Constants.EXTRA_CUSTOMER, result);
                    userFragment.setArguments(bundle);
                }else{
                    try {
                        Customer customer = new Customer();
                        customer.parseCustomer(new JSONObject(result));
                        userFragment.updateVeiw(customer);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
0

最初に、なぜこれが起こるのかを説明することから始め、次に、私が見つけた解決策を考え出します..。

この問題は、Android=removingフラグメントをスタックから削除するがまだこれを確認するには、フラグメントのisRemoving()メソッドを使用できますfalse、つまりフラグメントがアクティブでない場合は、次を使用して引数を設定できますsetArguments(bundle)。それ以外の場合、既にアクティブなフラグメントに引数を設定することはできず、getArguments().putAll(bundle)を使用して同じ引数をアドレス指定することによってのみオーバーライドできます。

要約する、

_    if (myFrag.isRemoving()) {
        myFrag.getArguments().putAll(bundle);
    } else {
        myFrag.setArguments(bundle);
    }
_

これを避けたい場合、つまりアクティブなフラグメントがないようにフラグメントを一度に削除したい場合、onBackPressed()onBackStackChangedListener()を使用すると、isRemoving()からfalseへ。

0
Ali Nem

Xamarin.Androidでも同じ問題が発生しています。 ドキュメント の内容は次のとおりです。

これは、フラグメントがそのアクティビティにアタッチされる前にのみ呼び出すことができます

0
Jonathan

同じ問題がありました。フラグメントをバックスタックに追加していました。エラーは、popbackstack()を呼び出さなかったためです。 popbackstackを使用して助けてくれました

0