2014年2月21日金曜日

Android - DialogFragmentと画面回転

画面回転の際、DialogFragmentの設定情報がnullになってしまい、NullPointerExceptionで落ちてしまったので、対策メモ。

画面が回転すると、Activityの再構築が始まるのですが、その際、普通に値を設定すると再構築の際に値がクリアーされてしまいます。

public static class TestDialogFragment extends DialogFragment {
    public TestDialogFragment() {}

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        // こんな感じ
        ProgressDialog progressDialog = new ProgressDialog(getActivity());
        progressDialog.setMessage("処理中です...");
        progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        return progressDialog;
    }
}

今回は、Bundleに設定を保存するという方法で回避しました。

TestFragment.java
public class TestFragment extends Fragment {
    private static final String TAG = "dialog";
    private static TestDialogFragment sTestDialogFragment;
    
    public void ConfigurationFragment() {}
    
    LoaderManager.LoaderCallbacks<Cursor> testCallbacks = new LoaderManager.LoaderCallbacks<Cursor>() {

        @Override
        public Loader<Cursor> onCreateLoader(int id, Bundle args) {
            sTestDialogFragment = TestDialogFragment.newInstance();
            sTestDialogFragment.show(getFragmentManager(), TAG);
            return new CursorLoader(getActivity(), …);
        }

        @Override
        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
            sTestDialogFragment.getDialog().dismiss();
        }

        @Override
        public void onLoaderReset(Loader<Cursor> loader) {
        }
    };
    
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        getLoaderManager().initLoader(0, null, testCallbacks);
    }
    
    public static class TestDialogFragment extends DialogFragment {
        public TestDialogFragment() {}
        public static TestDialogFragment newInstance() {
            TestDialogFragment testDialogFragment = new TestDialogFragment();
            Bundle bundle = new Bundle();
            bundle.putString("message", "処理中です...");
            bundle.putInt("style", ProgressDialog.STYLE_SPINNER);
            testDialogFragment.setArguments(bundle);
            return testDialogFragment;
        }
        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            Bundle bundle = getArguments();
            ProgressDialog progressDialog = new ProgressDialog(getActivity());
            progressDialog.setMessage(bundle.getString("message"));
            progressDialog.setProgressStyle(bundle.getInt("style"));
            return progressDialog;
        }
    }
}

ポイントは、TestDialogFragmentのインスタンスを作成する際、
TestDialogFragment prosessedDialogFragment = new TestDialogFragment();
のように取得するのではなく、TestDialogFragmentを返すメソッドを作成(newInstance())し、そのメソッド経由でインスタンスを取得します。

さらに、そのメソッド内で設定情報をBundleを使用してTestDialogFragmentのインスタンスの引数としてセットします。

ProgressDialogを作成する時は、インスタンスにセットされた引数を使って、値を設定します。

このような手順でProgressDialogを作成すると、画面が回転してActivityが再構築されても値はクリアーされません。

今回は、ProgressDialogでしたが、同じように値を持ったView等があった場合も、同じような手順で作成すれば、値がクリアーされることなく画面回転ができると思います。

注意点として、FragmentのインナークラスであるTestDialogFragmentは、「static」で作成しないと、怒られてしまいます。詳しい理由までは分かっていませんが、おまじないのように「static」をつけるようにしましょう。

あと、ProgressDialogを消す際の、dismiss()ですが、
sTestDialogFragment.dismiss();
のように、普通に消そうとすると落ちます。
sTestDialogFragment.getDialog().dismiss();
のように、getDialog()経由でDialogを取得すると正常に消えてくれます。


こんなところかな。

0 件のコメント:

コメントを投稿