6

同様の回答がいくつかありますが、この状況には当てはまりません。


私の状況は単純です。

1 つは縦向き、もう 1 つは横向きの 2 つの異なるレイアウトを持つアクティビティがあります。

ポートレートでは、動的に使用<FrameLayout>して追加Fragmentします。

Landscapeでは<fragment>Fragmentis staticを使用します。(実際は関係ありません)

それは最初にPortraitFragmentで始まり、次に単純に by を追加しました:

ListFrag listFrag = new ListFrag();
getSupportFragmentManager().beginTransaction()
        .replace(R.id.FragmentContainer, listFrag).commit();

どこでListFrag extends ListFragment

次に、画面の回転を行います。listFrag がランドスケープ モードで再作成されていることがわかりました。onCreate()(メソッドがnull以外のバンドルで再度呼び出される ことに気付きました)

この投稿setRetainInstance(false)で@NPikeが言ったように使用しようとしました。しかし、これはすでにデフォルトです。ドキュメントが言ったように、私が期待したことはしません。誰か説明してくれませんか?getRetainInstance()false


私が扱っているフラグメントは、ListFragmentでありsetListAdapter()onCreate()です。したがって、このif (container == null) return null;メソッドはここでは使用できません。(または、申請方法がわからない)。

この投稿からいくつかのヒントを得ました。で使用する必要がif (bundle != null) setListAdapter(null); else setListAdapter(new ...);ありListFragmentますか? しかし、作成時に行うのではなく、フラグメントが破棄/切り離されたときにフラグメントを実際に削除/削除するより良い方法はありますか? (if (container == null) return null;方法として)


編集:

私が見つけた唯一のきちんとした方法は、で行うことgetSupportFragmentManager().beginTransaction().remove(getSupportFragmentManager().findFragmentById(R.id.FragmentContainer)).commit();ですonSaveInstanceState()。しかし、それは別の問題を引き起こすでしょう。

  1. WhatsApp や TXT のダイアログ ボックスがポップアップするなど、画面が部分的に隠れていると、フラグメントも消えます。(これは比較的マイナーで、視覚的な問題です)

  2. 画面が回転すると、Activity は完全に破棄され、再作成されます。onCreate(Bundle)したがって、またはにフラグメントを再度追加できonRestoreInstanceState(Bundle)ます。ただし、(1) の場合、アクティビティの切り替えと同様に、ユーザーがアクティビティに戻ったときにどちらonCreate(Bundle)も呼び出されません。onRestoreInstanceState(Bundle)アクティビティを再作成する (およびバンドルからデータを取得する) 場所がありません。

申し訳ありませんが、はっきりとは言いませんでした。私はすでに意思決定を行っており、getSupportFragmentManager()...replace(...).commit();ラインはポートレート モードでのみ実行されます。


サンプルコード

状況をよりよく説明するために、単純なコードを抽出しました:)

MainActivity.java

package com.example.fragremovetrial;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;

public class MainActivity extends FragmentActivity {

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

        if (findViewById(R.id.FragmentContainer) != null) {
            System.out.println("-- Portrait --");       // Portrait
            ListFrag listFrag = new ListFrag();
            getSupportFragmentManager().beginTransaction()
                    .replace(R.id.FragmentContainer, listFrag).commit();
        } else {
            System.out.println("-- Landscape --");      // Landscape
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (findViewById(R.id.FragmentContainer) != null) {
            System.out.println("getRetainInstance = " +
                    getSupportFragmentManager().findFragmentById(R.id.FragmentContainer).getRetainInstance());
        }
    }
}

レイアウト/アクティビティ_main.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/FragmentContainer"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" />

layout-land/activity_main.xml (どちらでも構いません)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
</LinearLayout>

ListFrag.java

package com.example.fragremovetrial;

import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.widget.ArrayAdapter;

public class ListFrag extends ListFragment {
    private String[] MenuItems = { "Content A", "Contnet B" };

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

        System.out.println("ListFrag.onCreate(): " + (savedInstanceState == null ? null : savedInstanceState));

        setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, MenuItems));
    }
}

私は次のようになったことに注意してください

デバッグ メッセージ

-- ポートレート --
ListFrag.onCreate(): null
getRetainInstance = false

(ポートを回転 -> ランド)

ListFrag.onCreate(): Bundle[{android:view_state=android.util.SparseArray@4052dd28}]
-- ランドスケープ --
以前はフォーカスされたビューは、保存中に ID 16908298 を報告しましたが、復元中には見つかりません。

(ランドを回転 -> ポート)

ListFrag.onCreate(): Bundle[{android:view_state=android.util.SparseArray@405166c8}]
-- ポートレート --
ListFrag.onCreate(): null
getRetainInstance = false

(ポートを回転 -> ランド)

ListFrag.onCreate(): Bundle[{android:view_state=android.util.SparseArray@4050fb40}]
-- ランドスケープ --
以前にフォーカスされたビューは、保存中に ID 16908298 を報告しましたが、復元中には見つかりません。

(ランドを回転 -> ポート)

ListFrag.onCreate(): Bundle[{android:view_state=android.util.SparseArray@40528c60}]
-- ポートレート --
ListFrag.onCreate(): null
getRetainInstance = false

画面が回転し続けると、作成されるフラグメントの数が無限に増加するわけではありませんが、これは説明できません。(助けてください)

4

4 に答える 4

2

私は最終的に、アクティビティの再作成時に不要なフラグメントが再作成されるのを防ぐための解決策を考え出しました。それは私が質問で述べたようなものです:

私が見つけた唯一のきちんとした方法は、で行うことgetSupportFragmentManager().beginTransaction().remove(getSupportFragmentManager().findFragmentById(R.id.FragmentContainer)).commit();ですonSaveInstanceState()。しかし、それは別の問題を引き起こすでしょう...

...いくつかの改善があります。

onSaveInstanceState()

@Override
protected void onSaveInstanceState(Bundle outState) {
    if (isPortrait2Landscape()) {
        remove_fragments();
    }
    super.onSaveInstanceState(outState);
}

private boolean isPortrait2Landscape() {
    return isDevicePortrait() && (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE);
}

は次のisDevicePortrait()ようになります。

private boolean isDevicePortrait() {
    return (findViewById(R.id.A_View_Only_In_Portrait) != null);
}

*デバイスが現在文字通り縦向きであるかどうかを判断するために使用できないことに注意してください。これは、画面が回転した直後にオブジェクトが変更されるためです-EVEN BEFOREが呼び出されます!!getResources().getConfiguration().orientationResources onSaveInstanceState()

オリエンテーションをテストするために使用したくない場合findViewById()(何らかの理由で、結局あまりきれいではありません)、グローバル変数を保持し、in でprivate int current_orientation;初期化します。これはよりきれいに見えます。ただし、Activity のライフサイクル中にどこでも変更しないように注意する必要があります。current_orientation = getResources().getConfiguration().orientation;onCreate()

※必ずremove_fragments() 事前に super.onSaveInstanceState()ご確認ください。

(私の場合、レイアウトとアクティビティからフラグメントを削除するためです。それが後である場合super.onSaveInstanceState()、レイアウトは既にバンドルに保存されています。アクティビティが再作成された後、フラグメント再作成されます。 ###)

### この現象を証明しました。しかし、アクティビティの再作成時にフラグメントの復元を決定する理由は何ですか? は私の推測によるものです。それについて何かアイデアがあれば、私の別の質問に答えてください。

于 2013-04-01T19:04:59.020 に答える
0

あなたの方法では、ポートレートモードの場合にonCreate()のみ作成する必要があります。ListFrag縦向きレイアウトでのみ持っている FrameLayout ビューが ではないかどうかを確認することで、それを行うことができますnull

if (findViewById(R.id.yourFrameLayout) != null) {
    // you are in portrait mode
    ListFrag listFrag = new ListFrag();
    getSupportFragmentManager().beginTransaction()
            .replace(R.id.FragmentContainer, listFrag).commit();
} else {
    // you are in landscape mode
    // get your Fragment from the xml
}

最終的に、縦向きから横向きのレイアウトに切り替える場合、別の ListFrag を作成する必要はありませんが、xml で指定した Fragment を使用します。

于 2013-03-19T10:37:03.110 に答える