web-dev-qa-db-ja.com

フラグメントは、方向が変更されたときに状態を復元します

アプリに「標準」フラグメントナビゲーションを実装する必要があります( リンク を参照してください)。

問題は、デバイスがポートレートモードの場合、1つのフラグメントのみが表示され、ランドスケープモードに回転すると、2つのフラグメントが表示される必要があることです。

私はこれを2つの異なる方法で実行しようとしました:

1)ポートレートとランドスケープのレイアウトが異なる1つのアクティビティのみを使用します。

ポートレートレイアウトxml:

<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:tools="http://schemas.Android.com/tools"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent" >

    <FrameLayout
        Android:id="@+id/main_frame_fragment_container"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent" />

</RelativeLayout>

そしてここに風景のレイアウトがあります:

<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:baselineAligned="false"
    Android:orientation="horizontal" >

    <FrameLayout
        Android:id="@+id/main_frame_fragment_container_left"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:layout_weight="1" />

    <FrameLayout
        Android:id="@+id/main_frame_fragment_container_right"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:layout_weight="1" />

</LinearLayout>

アクティビティのonCreateメソッド:

    private static ItemsFragment mItemsFragment;
    private static ItemDetailsFragment mItemDetailsFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (mItemsFragment == null) {
            mItemsFragment = ItemsFragment.newInstance();
        }
        if (mItemDetailsFragment == null) {
            mItemDetailsFragment = ItemDetailsFragment.newInstance();
        }

        if (isLandscape()) {
            getSupportFragmentManager().beginTransaction().replace(R.id.main_frame_fragment_container_left, mItemsFragment)
                    .commit();
            getSupportFragmentManager().beginTransaction()
                    .replace(R.id.main_frame_fragment_container_right, mItemDetailsFragment).commit();
        } else {
            getSupportFragmentManager().beginTransaction().replace(R.id.main_frame_fragment_container, mItemsFragment)
                    .commit();
        }
    }

そして、それは私が2番目のフラグメントを更新する方法です:

Bundle bundle = new Bundle();
bundle.putSerializable(BaseFragment.KEY_BUNDLE_ITEM, response.getItem());
mItemDetailsFragment = ItemDetailsFragment.newInstance(bundle);
if (isLandscape()) {
    getSupportFragmentManager().beginTransaction()
                            .replace(R.id.main_frame_fragment_container_right, mItemDetailsFragment).commit();
} else {
    getSupportFragmentManager().beginTransaction()
                            .replace(R.id.main_frame_fragment_container, mItemDetailsFragment).addToBackStack(null).commit();
}

また、フラグメントの状態を保存および復元するので、ローテーション後にデータが消えることはありません。一般的に、このコードは私の場合は正しく機能します。

2)1番目のアクティビティのポートレートモードとランドスケープモードに2つのアクティビティと同じレイアウトを使用します。

xmlレイアウトは、ランドスケープの前のレイアウトと同じです。

    <FrameLayout
        Android:id="@+id/main_frame_fragment_container_left"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:layout_weight="1" />

    <FrameLayout
        Android:id="@+id/main_frame_fragment_container_right"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:layout_weight="1" />

</LinearLayout>

onCreateメソッド(最初のケースのように、フラグメントエンティティは静的ではないことに注意してください):private ItemsFragment mItemsFragment;プライベートItemDetailsFragmentmItemDetailsFragment;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    if (savedInstanceState == null) {
        mItemsFragment = ItemsFragment.newInstance();
        mItemDetailsFragment = ItemDetailsFragment.newInstance();

        getSupportFragmentManager().beginTransaction().replace(R.id.main_frame_fragment_container_left, mItemsFragment)
        .commit();
        getSupportFragmentManager().beginTransaction()
        .replace(R.id.main_frame_fragment_container_right, mItemDetailsFragment).commit();
    }
}

そして今、デバイスがポートレートモードの場合、新しいアクティビティを開始します。

if (isLandscape()) {
    Bundle bundle = new Bundle();
    bundle.putSerializable(BaseFragment.KEY_BUNDLE_ITEM, response.getItem());
    mItemDetailsFragment = ItemDetailsFragment.newInstance(bundle);
    getSupportFragmentManager().beginTransaction()
        .replace(R.id.main_frame_fragment_container_right, mItemDetailsFragment).commit();
} else {
    Intent intent = new Intent(getApplicationContext(), DetailsActivity.class);
    intent.putExtra(KEY_ITEM, response.getItem());
    startActivity(intent);
}

そして最後に、2番目のアクティビティのonCreateメソッド:

protected void onCreate(Bundle arg0) {
    super.onCreate(arg0);
    setContentView(R.layout.activity_details);

    if (isLandscape()) {
        finish();
    }

    Item item = (Item) getIntent().getExtras().getSerializable(KEY_ITEM);

    Bundle bundle = new Bundle();
    bundle.putSerializable(BaseFragment.KEY_BUNDLE_ITEM, item);

    ItemDetailsFragment mItemDetailsFragment = ItemDetailsFragment.newInstance(bundle);

    getSupportFragmentManager().beginTransaction()
        .replace(R.id.main_frame_fragment_container, mItemDetailsFragment).commit();
}

デバイスを横向きモードに回転すると、2番目のアクティビティが終了し、最初のアクティビティが2つのフラグメントで表示されます(予想どおり)。

質問:

最初のケースでは、フラグメントを静的変数として保存します。このため、ポートレートモードまたはランドスケープモードで2番目のフラグメントの状態を変更してもかまいません(同じフラグメントが使用されます)。しかし、静的フィールドとして保存するのは良い考えではないと思います。

2番目のケースでは、アクティビティAのフラグメントB(風景)とアクティビティBのフラグメントB(ポートレート)を同期する方法がわかりません。フラグメント内の何か(つまり、トグルボタンなど)を変更してデバイスを回転させる場合、変更は別のフラグメントに適用する必要があります。

一般的に、どちらの場合が良いですか。2番目の場合、同期の問題を解決するにはどうすればよいですか。または、別の簡単な方法があるかもしれません。読んでくれてありがとう、私はあなたが私を助けることができることを願っています:)

11
UneXp

この仲間に従ってください http://developer.Android.com/guide/components/fragments.html 。フラグメントを静的にしないでください(それはただ奇妙です)

3
Pulkit Sethi