ページ

2011/05/21

Android Preferenceの内容が他の項目に変わる

|
カスタマイズしたPreferenceを作りました。
しばらく画面内に1つしかそのPreferenceを使っていなかったのですが、
数を増やしたところおかしなことになりました。

増やしたもののうち、Dependencyを設定しているカスタムPreferenceがあるのですが
依存先のチェックボックスを操作したところ
そのカスタムPreferenceと他のカスタムPreferenceが入れ替わる現象が起こりました。
さらに、カスタムPreferenceをタップしてダイアログを開き、
OKで閉じても他の項目と表示が入れ替わってしまいます。
しかし、他の項目と思ってタップすると、開くダイアログは入れ替わり前の内容です。

Preferenceの一覧表示だけがおかしい?と見当をつけて調べたところ、
原因はonBindView()にありました。

Preferenceは通常、ListViewの項目として表示されます。
(PreferenceActivityはListActivityのサブクラスです。)
ListViewの項目を表示するときはgetView()が呼び出されますが、
毎回新しいオブジェクトが生成されるわけではなく
非表示になったものをリサイクルして使います。

つまり、例えば
1.onCreateViewの中で現在の設定値表示用のTextViewを取得してフィールドに持つ
2.設置値が変わったらフィールドのTextViewに反映する
ということをやっていると
「実はそのTextViewは既に他の項目のものになっていて、他の項目の表示が変わる」
ということが起こります。

こうならないようにするには、onCreateView()ではなくonBindView()で各Viewの値を設定します。
また、ViewのオブジェクトはPreferenceクラス内で保持しないようにします。

以下はNG例です。
違う項目の値が変わってしまうことがあります。
    private TextView mTitleView;

    @Override
    protected View onCreateView(final ViewGroup parent) {
        final LayoutInflater inflater = (LayoutInflater) getContext()
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View view = inflater.inflate(R.layout.font_preference, null);
        mTitleView = (TextView) view.findViewById(R.id.text1);
        mTitleView.setText("Initial value");
        return view;
    }
    :
    // 値を変更したとき
    mTitleView.setText("New value");

上記は以下のようにすれば適切に動作します。
Viewではなく、そのViewに表現する値をフィールドとして保持し、
Viewへの設定はonBindViewで行います。
値を変更したときはnotifyChanged()を呼び出すことで再描画されます。
    private String mTitle = "Initial value";

    @Override
    protected View onCreateView(final ViewGroup parent) {
        final LayoutInflater inflater = (LayoutInflater) getContext()
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        return inflater.inflate(R.layout.font_preference, null);
    }

    @Override
    protected void onBindView(final View view) {
        ((TextView) view.findViewById(R.id.text1)).setText(mTitle);
    }
    :
    // 値を変更したとき
    mTitle = "New value";
    notifyChanged();

0 件のコメント: