16

これについて間違っている場合は修正してください。どこにも明示的に書かれているのを見たことがないので、これは一種の明確な質問です。

Android 4 では、 を呼び出しsetRetainInstance(true)て、Fragment構成の変更 (基本的にはデバイスのローテーションを意味します) でFragmentJava オブジェクトが破棄されず、その新しいインスタンスが作成されないようにすることができます。つまり、インスタンスは保持されます。

これは、すべてのデータを処理してバンドルする必要がないため、Android 1-3 よりもはるかに正気で腹立たしいことではなく、新しい(または) インスタンスに渡して再度バンドルを解除するだけで済みます。それは基本的にあなたが期待することであり、おそらく最初から s がどのように機能するべきだったかです。onRetainNonConfigurationStateInstance()FragmentActivityActivity

ご想像のとおり、回転時setRetainInstance(true)にビューも再作成 (onCreateView()が呼び出されます) されます。そして、リソース解決(layoutvs layout-land)が機能すると(テストされていませんが)想定しています。

だから私の質問は2つあります:

  1. なんでActivities最初からこうじゃなかったんだろう。
  2. これがデフォルトではないのはなぜですか?ローテーションで無意味に破壊されて再作成されること実際に望んでいる理由はありますか? Fragment何も思いつかないから。

編集

私がそれを行う方法を明確にするために:

class MyFragment extends Fragment
{
    // All the data.
    String mDataToDisplay;
    // etc.

    // All the views.
    TextView mViewToDisplayItIn;
    // etc.

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
        mDataToDisplay = readFromSomeFileOrWhatever(); // Ignoring threading issues for now.
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        return inflater.inflate(R.layout.my_fragment, container, false);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState)
    {
        // At this point if mViewToDisplayItIn was not null, the old one will be GC'd.
        mViewToDisplayItIn = view.findViewById(R.id.the_text_view);
        mViewToDisplayItIn.setText(mDataToDisplay);
    }

    // Optionally:
    @Override
    public void onDestroyView()
    {
        // All the view (and activity) to be GC'd.
        mViewToDisplayItIn = null;
    }
}
4

2 に答える 2

13

そのため、構成の変更時(基本的にデバイスのローテーションを意味します)

ロケールの変更、SIM の変更、デフォルトのフォント サイズの変更、外部キーボードの接続または取り外し、デバイスのドックへの挿入またはドックからの取り外しなど。

onRetainNonConfigurationState() に対処する必要はありません

それはonRetainNonConfigurationInstance()

すべてのデータをバンドルして、新しい Fragment (または Activity) インスタンスに渡して、再びバンドル解除するだけにします

データはすでに「バンドル」されている必要があります (たとえば、private static 内部クラスのインスタンス)。したがって、「バンドル」または「バンドル解除」する必要はありません。また、メモリリークのファンでない限り、「すべてのデータ」であってはならないことがよくあります。

また、リソースの解決 (レイアウトとレイアウトランド) が機能すると想定しています (テストしていません)。

正しい。

Fragment を無意味に破壊し、ローテーションで再作成したい理由はありますか?

もちろん。

お気づきのように、すべてのウィジェットが再作成されるため、ウィジェットに関連付けられたデータ メンバーは保持する必要がないだけではありません。nullが再び呼び出されるまで、何らかの方法で保持されたフラグメントにそれらを具体的にリセットしない限りonCreateView()、それらのデータ メンバーは古いウィジェットを保持し、古いウィジェットは古いアクティビティ インスタンスを保持し、古いアクティビティ インスタンスがガベージ コレクションされるのを防ぎます。私の知る限り、onCreateView()フラグメントが再表示されるまで呼び出されることはありません。これはしばらくの間ではない可能性があります(フラグメントが新しい向きで使用されていないか、フラグメントがViewPagerユーザーが古い向きでアクセスしたが、新しい向きでは再訪しないなど)。つまり、保持されたフラグメントによって、古いアクティビティ オブジェクトがかなりの期間保持される可能性があります。アクティビティが保持している可能性のあるのもの(たとえば、大きなBitmapオブジェクト) によっては、それが悪い可能性があります。

同様に、それ自体が大きなデータを保持しているフラグメントは、構成の変更後に使用される場合と使用されない場合がありますが、保持すべきではありません。

また、単に保持する必要がないフラグメントもあります (たとえば、Loaders構成の変更を既に認識し、適切に処理する によってすべてのデータが取り込まれます)。

等々。

フラグメントを保持しないというデフォルトは、ガベージ コレクションの問題に関して最も安全な方法です。一部のフラグメントを保持することを選択できますが、そうすることで自分を台無しにしないようにする責任はあなたにあります.

于 2012-09-19T11:32:06.450 に答える
0

最初の質問の答えがわかりません。最初からそうあるべきだった。Google の誰かが、このスキームを思いついたのは本当に賢いと思ったのでしょう。

ただし、2 番目の質問ははるかに簡単です。これは、Android 開発者が期待することを学んだものではないため、デフォルトではありません。Android 開発は、インスタンスがローテーションで終了することを認識し、それを予期します。デフォルトを変更すると、多くの開発者が本当に腹を立てることになります。

于 2012-09-19T11:07:51.393 に答える