web-dev-qa-db-ja.com

Android向きの変更に対するフラグメントのライフサイクル

互換性パッケージを使用して、フラグメントを使用して2.2をターゲットにします。

アプリでフラグメントを使用するようにアクティビティを再コーディングした後、向きの変更/状態管理を機能させることができなかったため、単一のFragmentActivityと単一のFragmentを含む小さなテストアプリを作成しました。

向きの変更からのログは奇妙で、フラグメントOnCreateViewへの複数の呼び出しがあります。

私は明らかに何かを見逃しています-新しいインスタンスを作成するのではなく、フラグメントをデタッチして再アタッチしますが、どこが間違っているのかを示すドキュメントは表示されません。

誰かが私がここで間違っていることについて少し光を当てることができますか?ありがとう

向きの変更後のログは次のとおりです。

Initial creation
12-04 11:57:15.808: D/FragmentTest.FragmentTestActivity(3143): onCreate
12-04 11:57:15.945: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:57:16.081: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState null


Orientation Change 1
12-04 11:57:39.031: D/FragmentTest.FragmentOne(3143): onSaveInstanceState
12-04 11:57:39.031: D/FragmentTest.FragmentTestActivity(3143): onCreate
12-04 11:57:39.031: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:57:39.031: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState not null
12-04 11:57:39.031: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:57:39.167: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState null


Orientation Change 2
12-04 11:58:32.162: D/FragmentTest.FragmentOne(3143): onSaveInstanceState
12-04 11:58:32.162: D/FragmentTest.FragmentOne(3143): onSaveInstanceState
12-04 11:58:32.361: D/FragmentTest.FragmentTestActivity(3143): onCreate
12-04 11:58:32.361: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:58:32.361: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState not null
12-04 11:58:32.361: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:58:32.361: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState not null
12-04 11:58:32.498: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:58:32.498: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState null

主なアクティビティ(FragmentActivity)

public class FragmentTestActivity extends FragmentActivity {
/** Called when the activity is first created. */

private static final String TAG = "FragmentTest.FragmentTestActivity";


FragmentManager mFragmentManager;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Log.d(TAG, "onCreate");

    mFragmentManager = getSupportFragmentManager();
    FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();

    FragmentOne fragment = new FragmentOne();

    fragmentTransaction.add(R.id.fragment_container, fragment);
    fragmentTransaction.commit();
}

そしてその断片

public class FragmentOne extends Fragment {

private static final String TAG = "FragmentTest.FragmentOne";

EditText mEditText;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {

    Log.d(TAG, "OnCreateView");

    View v = inflater.inflate(R.layout.fragmentonelayout, container, false);

    // Retrieve the text editor, and restore the last saved state if needed.
    mEditText = (EditText)v.findViewById(R.id.editText1);

    if (savedInstanceState != null) {

        Log.d(TAG, "OnCreateView->SavedInstanceState not null");

        mEditText.setText(savedInstanceState.getCharSequence("text"));
    }
    else {
        Log.d(TAG,"OnCreateView->SavedInstanceState null");
    }
    return v;
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    Log.d(TAG, "FragmentOne.onSaveInstanceState");

    // Remember the current text, to restore if we later restart.
    outState.putCharSequence("text", mEditText.getText());
}

マニフェスト

<uses-sdk Android:minSdkVersion="8" />

<application
    Android:icon="@drawable/ic_launcher"
    Android:label="@string/app_name" >
    <activity
        Android:label="@string/app_name"
        Android:name=".activities.FragmentTestActivity" 
        Android:configChanges="orientation">
        <intent-filter >
            <action Android:name="Android.intent.action.MAIN" />

            <category Android:name="Android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>
114
MartinS

フラグメントを上下に重ねています。

構成の変更が発生すると、古いフラグメントは、再作成時に新しいアクティビティに自分自身を追加します。これはほとんどの場合、後部での大きな痛みです。

新しいフラグメントを再作成するのではなく、同じフラグメントを使用してエラーの発生を停止できます。このコードを追加するだけです:

if (savedInstanceState == null) {
    // only create fragment if activity is started for the first time
    mFragmentManager = getSupportFragmentManager();
    FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();

    FragmentOne fragment = new FragmentOne();

    fragmentTransaction.add(R.id.fragment_container, fragment);
    fragmentTransaction.commit();
} else {        
    // do nothing - fragment is recreated automatically
}

ただし、ライフサイクルが微妙に変化するため、フラグメント内からアクティビティビューにアクセスしようとすると問題が発生します。 (フラグメントから親アクティビティからビューを取得するのは簡単ではありません)。

182
Graeme

この本 を引用するには、「一貫したユーザーエクスペリエンスを確保するために、Androidは、構成の変更によりアクティビティが再開されたときに、フラグメントレイアウトと関連するバックスタックを保持します。」 (p。124)

そして、それにアプローチする方法は、最初にフラグメントバックスタックが既に読み込まれているかどうかをチェックし、まだ読み込まれていない場合にのみ新しいフラグメントインスタンスを作成します。

@Override
public void onCreate(Bundle savedInstanceState) {

        ...    

    FragmentOne fragment = (FragmentOne) mFragmentManager.findFragmentById(R.id.fragment_container); 

    if (fragment == null) {
        FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
        fragmentTransaction.add(R.id.fragment_container, new FragmentOne());
        fragmentTransaction.commit();
    }
}
83
k29

アクティビティのonCreate()メソッドは、見たように方向が変更された後に呼び出されます。したがって、アクティビティの方向の変更後にFragmentを追加するFragmentTransactionを実行しないでください。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState==null) {
        //do your stuff
    }
}

フラグメントは変更する必要があり、変更する必要があります。

10
Αλέκος

onSaveInstanceState()を使用して、@Override FragmentActivityを実行できます。メソッドでsuper.onSaveInstanceState()を呼び出さないようにしてください。

4
Victor.Chan

常にnullpointer exceptionを防ぐようにする必要があるため、saveinstanceメソッドで最初にバンドル情報を確認する必要があります。このブログをチェックする簡単な説明 link

public static class DetailsActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (getResources().getConfiguration().orientation
            == Configuration.ORIENTATION_LANDSCAPE) {
            // If the screen is now in landscape mode, we can show the
            // dialog in-line with the list so we don't need this activity.
            finish();
            return;
        }

        if (savedInstanceState == null) {
            // During initial setup, plug in the details fragment.
            DetailsFragment details = new DetailsFragment();
            details.setArguments(getIntent().getExtras());
            getFragmentManager().beginTransaction().add(Android.R.id.content, details).commit();
        }
    } 
}
0
abhi

構成が変更されると、フレームワークはフラグメントの新しいインスタンスを作成し、アクティビティに追加します。したがって、これの代わりに:

FragmentOne fragment = new FragmentOne();

fragmentTransaction.add(R.id.fragment_container, fragment);

これを行う:

if (mFragmentManager.findFragmentByTag(FRAG1_TAG) == null) {
    FragmentOne fragment = new FragmentOne();

    fragmentTransaction.add(R.id.fragment_container, fragment, FRAG1_TAG);
}

SetRetainInstance(true)を呼び出さない限り、フレームワークは方向変更時にFragmentOneの新しいインスタンスを追加することに注意してください。この場合、FragmentOneの古いインスタンスが追加されます。

0
vlazzle