13

注意: 時間を節約して、受け入れられた回答を参照してください。すべての質問を読む必要はありません。
質問の残りの部分と、私が提供した別の (あまり洗練されていない) 方法の回答を読むことができます。
また、関連するコードを設定アクティビティ クラスに追加することで、Android 2.X のバックグラウンド グリッチの修正を利用することもできます。

背景
Android コーディングの初心者ですが、他のプログラミング言語/フレームワークの経験は多少あるので、Android アプリケーションのコーディングへの道のりは楽しいものになるだろうと思っていました。私がこの問題に出くわすまではそうでした:

Android プロジェクトの Eclipse ウィザードは、最小 API を 8 (Android 2.2) に設定すると、デバイスの 95% に到達できることを示しました。いずれにせよ、自分のアプリで派手なことをする必要はなかったので、「いいよね」と思いました。すべて問題ありませんでしたが、最新の API バージョンで非推奨になったいくつかのメソッド/クラスを時折見つけることがあったため、古いデバイスで古い方法を使用し続ける方法を考案し、可能な限り新しい方法を使用するようにしなければなりませんでした。新しい Android バージョンの方法。これはそのような機会の 1 つです。

設定アクティビティを作成するために Eclipse ウィザードを使用した後、Eclipse プリコンパイラ/パーサー/チェッカー (またはそれが何と呼ばれるか) Lint が、古い API バージョンで設定を作成/管理する新しい方法を使用できないことについて文句を言うことに気付きました。だから私は「よし、新しい方法を台無しにする。古い方法でやろう。新しい API バージョンは下位互換性があるはずなので、大丈夫だろう」と思ったのですが、そうではありませんでした。非推奨としてマークされている古い方法で使用されるメソッド/クラス。つまり、現在の API では引き続き機能しますが、将来のリリースのある時点で機能しなくなるということです。

そこで、これを行う正しい方法を探し始め、最終的にこのページにアクセスしました: PreferenceActivity で "addPreferencesFromResource" の代わりに何を使用しますか? ここで、Garret Wilson が、新しい方法と互換性のある方法で古い設定画面リソースを使用する方法を説明しています。それは素晴らしいことでした。新しい API コードを使用していたため、古い API を対象とする場合は機能しないことを除けば、ようやくアプリのコーディングを進めることができると感じました。そのため、古い API と新しい API の両方で動作するようにする方法を考案する必要がありました。しばらくいじくり回した後、プリコンパイラ(またはそれが呼ばれるもの)アノテーションと優れた getClass().getMethod() と例外を使用して、方法を見つけることができました。

設定サブ画面を作成するまで、すべてが問題なく動作しているように見えました。Androidの新しいバージョンでは正しく表示されていましたが、古いバージョンで試してみると、黒い画面しか表示されませんでした. 多くの検索の後、問題を説明するこのページを見つけました: http://code.google.com/p/android/issues/detail?id=4611これは明らかに既知の不具合であり、かなり長い間、いくつかの Android バージョンで発生していました。私はスレッド全体を読み、問題に対するいくつかの提案された解決策を見つけましたが、私はそれらのどれも完全に好きではありませんでした. 私は、できる限り静的なものを避け、プログラムで物事を行うことを好みます。私は反復作業よりも自動化を好みます。一部のソリューションでは、サブ画面を親画面として作成し、それらをマニフェスト ファイルに追加して、インテントを通じて親画面から呼び出すことを提案していました。マニフェストのエントリ、分離された画面リソース ファイル、インテントなど、それらを追跡しなければならないのは本当に嫌です。私は探し続け、私がはるかに気に入ったプログラムによるアプローチを見つけましたが、それが機能しないことがわかりました。設定画面のビュー ツリー全体を反復処理し、適切な背景を設定サブ画面に割り当てることで構成されていましたが、後で多くのデバッグを行った後にわかったように、設定サブ画面のビューは設定画面ビューの子。私は自分でこれを達成する方法を見つけなければなりませんでした。私は思いつく限り多くのことを試し、調査し、調査しましたが、役に立ちませんでした。私は何度か断念する寸前でしたが、約 2 週間の継続的な努力と多くのデバッグの後、回避策を見つけ、コメント #35 に投稿しました。私は思いつく限り多くのことを試し、調査し、調査しましたが、役に立ちませんでした。私は何度か断念する寸前でしたが、約 2 週間の継続的な努力と多くのデバッグの後、回避策を見つけ、コメント #35 に投稿しました。私は思いつく限り多くのことを試し、調査し、調査しましたが、役に立ちませんでした。私は何度か断念する寸前でしたが、約 2 週間の継続的な努力と多くのデバッグの後、回避策を見つけ、コメント #35 に投稿しました。

意見
それは本当に完璧なソリューション/アプローチではなく、いくつかの欠点を認識していますが、機能するものであるため、共有することにしました。経験豊富なコーダーなら誰でも解決できるほど大きな問題ではないことはわかっているので、かなりの労力を費やしたと思われることを共有することに熱意を持ちすぎないことを願っています。でも、知識を共有することで、どんなに自慢しても、すべてを独り占めしている経験豊富なコーダーよりも少しは良くなると思います。これまで誰もこの問題を抱えていなかったとは信じられないので、私の意見を共有するだけですが、多くの人がこの問題を抱えていて、わざわざ知識を共有していないと思います.

Android のいくつかのバージョンで使用する提案されたクラスと、その使用法に関するいくつかの提案を回答として提示します。より良いクラスにするための議論と貢献を歓迎します。

既知の問題点:

  • 親画面の装飾ビューの背景が子画面の装飾ビューの背景にクローンされますが、これは明らかに正常な動作ではありません。
    ステータス: 誰かがこれを修正する正当な理由を思い付くまで却下
  • 画面回転時にクラッシュする
    ステータス: 修正済み。
    おそらく、新しい API 実装 (内部クラス PF) によるリソースの可視性に関連してい
    ます。明らかに、preferenceFragment から継承されたクラスは、すべてのメンバーを静的にする必要があります。新しいフラグメントを使用する必要があるたびに継承することになっているのであれば、それは理にかなっていると思います
4

3 に答える 3

18

最新の ADT プラグインを使用している場合は、ほとんどの古い Android バージョンとすべての新しいバージョンをサポートする設定アクティビティを簡単に作成するオプションがあります。

プロジェクトを右クリック -> その他 -> Android アクティビティ

次に、設定アクティビティを選択します ここに画像の説明を入力

作成されたアクティビティは、if ステートメントを使用して設定を表示する適切な方法を選択するため、API バージョンの高低の両方を処理します。


編集
良い点が持ち出されました.APIバージョンに関係なく、電話サイズのデバイスは古いPreferenceActivityメソッドを使用します。

API 11+ デバイスを使用する最も簡単な方法は、からFragments削除することです。!isXLargeTablet(context);isSimplePreferences()

private static boolean isSimplePreferences(Context context) {
    return ALWAYS_SIMPLE_PREFS
            || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB;
}

ただし、ユーザーはより多くのナビゲーションを行う必要があります。
ルートとしてのヘッダー

と呼ばれているからonBuildHeaders()です。

これを取り除くには、各 xml リソースを追加する独自の PreferenceFragment を作成する必要があります。

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public static class AllPreferencesFragment extends PreferenceFragment{
        @Override
        public void onCreate (Bundle savedInstanceState){
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.pref_general);

            // Add 'notifications' preferences, and a corresponding header.
            PreferenceCategory fakeHeader = new PreferenceCategory(getActivity());
            fakeHeader.setTitle(R.string.pref_header_notifications);
            getPreferenceScreen().addPreference(fakeHeader);
            addPreferencesFromResource(R.xml.pref_notification);

            // Add 'data and sync' preferences, and a corresponding header.
            fakeHeader = new PreferenceCategory(getActivity());
            fakeHeader.setTitle(R.string.pref_header_data_sync);
            getPreferenceScreen().addPreference(fakeHeader);
            addPreferencesFromResource(R.xml.pref_data_sync);

            // Bind the summaries of EditText/List/Dialog/Ringtone preferences to
            // their values. When their values change, their summaries are updated
            // to reflect the new value, per the Android Design guidelines.
            bindPreferenceSummaryToValue(findPreference("example_text"));
            bindPreferenceSummaryToValue(findPreference("example_list"));
            bindPreferenceSummaryToValue(findPreference("notifications_new_message_ringtone"));
            bindPreferenceSummaryToValue(findPreference("sync_frequency"));
        }
    }

設定を起動する外部から画面サイズを決定できる場合はActivity、起動するフラグメントを指定できますEXTRA_SHOW_FRAGMENT

i.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT, "com.example.test.SettingsActivity$AllPreferencesFragment");

または、SettingsActivityこの Fragment を表示するかどうかを決定することもできます (メソッドに満足しているisXLargeTablet()場合.

変更onBuildHeaders():

@Override
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void onBuildHeaders(List<Header> target) {
    if (!isSimplePreferences(this) && isXLargeTablet(this)) {
        loadHeadersFromResource(R.xml.pref_headers, target);
    }
}

このメソッドを追加します。

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void setupNewApiPhoneSizePreferences() {
    if (!isXLargeTablet(this) && Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB){
            getFragmentManager().beginTransaction().replace(android.R.id.content, new AllPreferencesFragment()).commit();
    }
}

そしてonPostCreate()、メソッド呼び出しを追加します。

setupNewApiPhoneSizePreferences();

これは、API 11 以降の非推奨でない呼び出しを使用する必要があります。

于 2012-12-30T17:22:08.390 に答える
4

このクラスを使用して、2.X から 4.X までのすべての Android バージョンで設定画面リソースをフィードすることで、設定画面を表示できます。

必要に応じて名前を変更して直接使用することもできますが、プロジェクトにそのまま追加し、それを継承することをお勧めします。これは、複数の親設定画面で作業する必要がある場合にはるかにクリーンです。

直接使用したい場合は、prefs の値を設定画面のリソース ID に置き換えてください。

それを継承したい場合は、次のようにする必要があります。

import android.os.Bundle;

public class MyPreferencesActivity extends CompatiblePreferenceActivity
{   
    @Override
    protected void onCreate(final Bundle savedInstanceState)
    {
        setPrefs(R.xml.mypreferencesactivity);
        super.onCreate(savedInstanceState);
    }   
}

super.onCreate(Bundle) を呼び出す前に、常に setPrefs(int) を呼び出します。

何らかの理由で、グリッチ修正を利用して自分で設定を作成したい場合は、グリッチ修正コードを自分の設定アクティビティにコピーするか、クラスから継承してキャッチします。 PrefsNotSet 例外は次のとおりです。

import android.os.Bundle;

public class MyPreferencesActivity extends CompatiblePreferenceActivity
{   
    @Override
    protected void onCreate(final Bundle savedInstanceState)
    {
        try{
            super.onCreate(savedInstanceState);
        }catch(PrefsNotSetException e){};
    }   
}

そして最後に、クラス:

import android.annotation.TargetApi;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
import android.preference.PreferenceScreen;

public class CompatiblePreferenceActivity extends PreferenceActivity
{
    private int prefs=0;

    //Get/Set
    public void setPrefs(int prefs)
    {
        this.prefs=prefs;
    }

    //Exception
    protected static class PrefsNotSetException extends RuntimeException
    {
        private static final long serialVersionUID = 1L;
        PrefsNotSetException()
        {
            super("\"prefs\" should be set to a valid preference resource ID.");
        }
    }

    //Creation
    @Override
    protected void onCreate(final Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        if (prefs==0)
            throw new PrefsNotSetException();
        else
            try {
                getClass().getMethod("getFragmentManager");
                AddResourceApi11AndGreater();
                }
            catch (NoSuchMethodException e) { //Api < 11
                    AddResourceApiLessThan11();
                }
    }

    @SuppressWarnings("deprecation")
    protected void AddResourceApiLessThan11()
    {
        addPreferencesFromResource(prefs);
    }

    @TargetApi(11)
    protected void AddResourceApi11AndGreater()
    {
        PF.prefs=prefs;
        getFragmentManager().beginTransaction().replace(
            android.R.id.content, new PF()).commit();
    }

    @TargetApi(11)
    public static class PF extends PreferenceFragment
    {
        private static int prefs;
        @Override
        public void onCreate(final Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(prefs);
        }
    }

    //Sub-screen background glitch fix
    @SuppressWarnings("deprecation")
    @Override
    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
        Preference preference)
    {
        super.onPreferenceTreeClick(preferenceScreen, preference);
        if (preference!=null)
            if (preference instanceof PreferenceScreen)
                if (((PreferenceScreen)preference).getDialog()!=null)
                    ((PreferenceScreen)preference).getDialog().
                        getWindow().getDecorView().
                        setBackgroundDrawable(this.getWindow().
                            getDecorView().getBackground().getConstantState().
                            newDrawable());
        return false;
    }
}
于 2012-12-28T21:32:09.177 に答える
1

自動生成された SettingsActivity を操作すると、すぐに古くなってしまいました。過去の定型コードを上下にスクロールする必要があります-さらに、黄色の警告でいっぱいで、私は黄色が嫌いです(ただし、非推奨の警告を完全に回避することはできません-What to use instead of "addPreferencesFromResource" in a PreferenceActivity? を参照してください)。クロス API の作成方法についてPreferenceActivityも触れます - およびPreferenceFragment は互換性パッケージから意図的に除外されましたか?については、ディスカッションを参照してください)。onPostCreate()また、 NPEを簡単に取得することもonPostStart()できfindPreference()ます。nullonStart()

現在、リフレクションを含むソリューションがありますが、リフレクションは回避する必要があります(地獄のように)-2つ前のバージョンのAndroidには興味がないため、リフレクションを回避できます( SDK_INTを十分にチェックしているか、新しいAndroidを使用するには遅延読み込みが必要ですを参照してくださいAPI ? なぜ? )。また、実行時にクラスを選択することを含む解決策があります-しかし、2つのクラスを持つことは最悪であり、とにかくOOPではありません(それらおよび他の解決策については、関連する質問への回答を参照してください: PreferenceActivity Android 4.0 and older )。

だから私は抽象基本クラスを思いつきました。これはJavaとオブジェクト指向の正しい方法です(Eclairが必要な場合を除き、回避するためにクラスのリフレクションや遅延ロードが必要な場合を除きますVerifyErrors)、自動生成された定型コード:

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;

import java.util.List;

/**
 * A {@link PreferenceActivity} that presents a set of application settings. On
 * handset devices, settings are presented as a single list. On tablets,
 * settings are split by category, with category headers shown to the left of
 * the list of settings.
 * <p>
 * See <a href="http://developer.android.com/design/patterns/settings.html">
 * Android Design: Settings</a> for design guidelines and the <a
 * href="http://developer.android.com/guide/topics/ui/settings.html">Settings
 * API Guide</a> for more information on developing a Settings UI.
 *
 * Defines two abstract methods that need be implemented by implementators.
 */
public abstract class BaseSettings extends PreferenceActivity {

    /**
     * Determines whether to always show the simplified settings UI, where
     * settings are presented in a single list. When false, settings are shown
     * as a master/detail two-pane view on tablets. When true, a single pane is
     * shown on tablets.
     */
    private static final boolean ALWAYS_SIMPLE_PREFS = false;

    /**
     * Helper method to determine if the device has an extra-large screen. For
     * example, 10" tablets are extra-large.
     */
    @TargetApi(Build.VERSION_CODES.GINGERBREAD)
    private static boolean isXLargeTablet(Context context) {
        return (context.getResources().getConfiguration().screenLayout &
                Configuration.SCREENLAYOUT_SIZE_MASK)
                >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
    }

    /** {@inheritDoc} */
    @Override
    public final boolean onIsMultiPane() { // never used by us
        return isXLargeTablet(this) && !isSimplePreferences(this);
    }

    /**
     * Determines whether the simplified settings UI should be shown. This is
     * true if this is forced via {@link #ALWAYS_SIMPLE_PREFS}, or the device
     * doesn't have newer APIs like {@link PreferenceFragment}, or the device
     * doesn't have an extra-large screen. In these cases, a single-pane
     * "simplified" settings UI should be shown.
     */
    private static final boolean isSimplePreferences(Context context) {
        return ALWAYS_SIMPLE_PREFS
            || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB
            || !isXLargeTablet(context);
    }

    @Override
    protected final void onCreate(Bundle savedInstanceState) {
        // disallow onCreate(), see comment in onPostCreate()
        super.onCreate(savedInstanceState);
    }

    @Override
    protected final void onStart() {
        // disallow onStart(), see comment in onPostCreate()
        super.onStart();
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        // onPostCreate() probably is needed because onBuildHeaders() is called
        // after onCreate() ? This piece of err code should be called
        // onPostStart() btw - so yeah
        super.onPostCreate(savedInstanceState);
        setupSimplePreferencesScreen();
        // findPreference will return null if setupSimplePreferencesScreen
        // hasn't run, so I disallow onCreate() and onStart()
    }

    /**
     * Shows the simplified settings UI if the device configuration if the
     * device configuration dictates that a simplified, single-pane UI should be
     * shown.
     */
    private void setupSimplePreferencesScreen() {
        if (!isSimplePreferences(this)) {
            return;
        }
        buildSimplePreferences();
    }

    /** {@inheritDoc} */
    /*
     * Subclasses of PreferenceActivity should implement onBuildHeaders(List) to
     * populate the header list with the desired items. Doing this implicitly
     * switches the class into its new "headers + fragments" mode rather than
     * the old style of just showing a single preferences list (from
     * http://developer
     * .android.com/reference/android/preference/PreferenceActivity.html) -> IE
     * this is called automatically - reads the R.xml.pref_headers and creates
     * the 2 panes view - it was driving me mad - @inheritDoc my - It does not
     * crash in Froyo cause isSimplePreferences is always true for
     * Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB - @Override has
     * nothing to do with runtime and of course on Froyo this is never called by
     * the system
     */
    @Override
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public final void onBuildHeaders(List<Header> target) {
        if (!isSimplePreferences(this)) {
            loadHeadersFromResource(getHeadersXmlID(), target);
        }
    }

    // =========================================================================
    // Abstract API
    // =========================================================================
    /**
     * Must return an id for the headers xml file. There you define the headers
     * and the corresponding PreferenceFragment for each header which you must
     * of course implement. This is used in the super implementation of
     * {@link #onBuildHeaders(List)}
     *
     * @return an id from the R file for the xml containing the headers
     */
    abstract int getHeadersXmlID();

    /**
     * Builds a pre Honeycomb preference screen. An implementation would use the
     * (deprecated)
*{@link android.preference.PreferenceActivity#addPreferencesFromResource(int)}
     */
    abstract void buildSimplePreferences();
}

サンプル実装:

public final class SettingsActivity extends BaseSettings implements
        OnSharedPreferenceChangeListener {

    private static final int PREF_HEADERS_XML = R.xml.pref_headers;
    private static CharSequence master_enable;
    private OnPreferenceChangeListener listener;
    private static Preference master_pref;
    private static final String TAG = SettingsActivity.class.getSimpleName();
    private SharedPreferences sp;
    /** Used as canvas for the simple preferences screen */
    private static final int EMPTY_PREF_RESOURCE = R.xml.pref_empty;
    private static int PREF_RESOURCE_SETTINGS = R.xml.pref_data_sync;

    // abstract overrides   
    @Override
    int getHeadersXmlID() {
        return PREF_HEADERS_XML;
    }

    @Override
    void buildSimplePreferences() {
        // In the simplified UI, fragments are not used at all and we instead
        // use the older PreferenceActivity APIs.
        // THIS is a blank preferences layout - which I need so
        // getPreferenceScreen() does not return null - so I can add a header -
        // alternatively you can very well comment everything out apart from
        // addPreferencesFromResource(R.xml.pref_data_sync);
        addPreferencesFromResource(EMPTY_PREF_RESOURCE);
        // Add 'data and sync' preferences, and a corresponding header.
        PreferenceCategory fakeHeader = new PreferenceCategory(this);
        fakeHeader.setTitle(R.string.pref_header_data_sync);
        getPreferenceScreen().addPreference(fakeHeader);
        addPreferencesFromResource(PREF_RESOURCE_SETTINGS);
    }

    // here is the work done
    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        master_enable = getResources().getText(
            R.string.enable_monitoring_master_pref_key);
        listener = new ToggleMonitoringListener();
        // DefaultSharedPreferences - register listener lest Monitor aborts
        sp = PreferenceManager.getDefaultSharedPreferences(this);
        sp.registerOnSharedPreferenceChangeListener(this);
        master_pref = findPreference(master_enable.toString());
    }

    @Override
    protected void onResume() {
        super.onResume();
        master_pref.setOnPreferenceChangeListener(listener); // no way to
        // unregister, see: https://stackoverflow.com/a/20493608/281545 This
        // listener reacts to *manual* updates - so no need to be active
        // outside onResume()/onPause()
    }

    @Override
    protected void onDestroy() {
        // may not be called (as onDestroy() is killable), but no leak,
        // see: https://stackoverflow.com/a/20493608/281545
        sp.unregisterOnSharedPreferenceChangeListener(this);
        super.onDestroy();
    }

    /**
     * Toggles monitoring and sets the preference summary.Triggered on *manual*
     * update of the *single* preference it is registered with, but before this
     * preference is updated and saved.
     */
    private static class ToggleMonitoringListener implements
            OnPreferenceChangeListener {

        ToggleMonitoringListener() {}

        @Override
        public boolean
                onPreferenceChange(Preference preference, Object newValue) {
            if (newValue instanceof Boolean) {
                final boolean enable = (Boolean) newValue;
                Monitor.enableMonitoring(preference.getContext(), enable);
                final CheckBoxPreference p = (CheckBoxPreference) preference;
                preference.setSummary((enable) ? p.getSummaryOn() : p
                    .getSummaryOff());
                return true;
            }
            return false;
        }
    }

    /**
     * This fragment is used when the activity is showing a two-pane
     * settings UI.
     */
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public final static class DataSyncPreferenceFragment extends
            PreferenceFragment {

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Log.w(TAG, "onCreate");
            addPreferencesFromResource(PREF_RESOURCE_SETTINGS);
            master_pref = findPreference(master_enable.toString());
        }
    }

    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
            String key) {
        if (master_enable == null || master_pref == null) return;
        if (master_enable.toString().equals(key)) {
            refreshMasterPreference();
        }
    }

    /**
     * @param key
     */
    private void refreshMasterPreference() {
        final Boolean isMonitoringEnabled = AccessPreferences.get(this,
            master_enable.toString(), false);
        Log.w(TAG, "Stored value: " + isMonitoringEnabled);
        final CheckBoxPreference p = (CheckBoxPreference) master_pref;
        final boolean needsRefresh = p.isChecked() != isMonitoringEnabled;
        if (needsRefresh) {
            p.setChecked(isMonitoringEnabled);
            p.setSummary((isMonitoringEnabled) ? p.getSummaryOn() : p
                .getSummaryOff());
        }
    }
}

したがって、主なアイデアは、ヘッダーを使用して設定用の xml を提供することです。

    public final void onBuildHeaders(List<Header> target) {
        if (!isSimplePreferences(this)) {
            loadHeadersFromResource(getHeadersXmlID(), target);
        }
    }

どこ:

    @Override
    int getHeadersXmlID() {
        return PREF_HEADERS_XML;
    }

PREF_HEADERS_XML:

<preference-headers xmlns:android="http://schemas.android.com/apk/res/android" >
    <!-- These settings headers are only used on tablets. -->
    <header
        android:fragment=".activities.SettingsActivity$DataSyncPreferenceFragment"
        android:title="@string/pref_header_data_sync" />
</preference-headers>

で簡単な設定を設定しますbuildSimplePreferences()

これをより一般的な API にすることに興味があります (おそらく を含むsBindPreferenceSummaryToValueListener)。アイデアは歓迎します。

ああ、はい、sBindPreferenceSummaryToValueListener の綿毛:

// FLUFF AHEAD:
// the fluff that follows is for binding preference summary to value -
// essentially wrappers around OnPreferenceChangeListener - just so
// you get an idea of the mess this autogenerated piece of, code, was
// formatter:off
/**
 * A preference value change listener that updates the preference's summary
 * to reflect its new value.
 */
/* private static Preference.OnPreferenceChangeListener
        sBindPreferenceSummaryToValueListener =
        new Preference.OnPreferenceChangeListener() {

        @Override
        public boolean onPreferenceChange(Preference preference,
                            Object value) {
            String stringValue = value.toString();
            if (preference instanceof ListPreference) {
                // For list preferences, look up the correct display value
                // in the preference's 'entries' list.
                ListPreference listPreference = (ListPreference) preference;
                int index = listPreference.findIndexOfValue(stringValue);
                // Set the summary to reflect the new value.
                preference.setSummary(index >= 0
                        ? listPreference.getEntries()[index] : null);
            } else if (preference instanceof RingtonePreference) {
                // For ringtone preferences, look up the correct display
                // value using RingtoneManager.
                if (TextUtils.isEmpty(stringValue)) {
                    // Empty values correspond to 'silent' (no ringtone).
                    // preference.setSummary(R.string.pref_ringtone_silent);
                } else {
                    Ringtone ringtone = RingtoneManager.getRingtone(
                        preference.getContext(), Uri.parse(stringValue));
                    if (ringtone == null) {
                        // Clear the summary if there was a lookup error.
                        preference.setSummary(null);
                    } else {
                        // Set the summary to reflect the new ringtone
                        // display name.
                        String name = ringtone
                            .getTitle(preference.getContext());
                        preference.setSummary(name);
                    }
                }
            } else if (preference instanceof CheckBoxPreference) {
                boolean b = (Boolean) value;
                Log.w(TAG, "::::value " + b);
                final CheckBoxPreference p =(CheckBoxPreference)preference;
                preference.setSummary((b) ? p.getSummaryOn() : p
                    .getSummaryOff());
                Log.w(TAG, p.getKey() + " :: " + p.isChecked());
            } else {
                // For all other preferences, set the summary to the value's
                // simple string representation.
                preference.setSummary(stringValue);
            }
            return true;
        }
    }; */

/**
 * Binds a preference's summary to its value. More specifically, when the
 * preference's value is changed, its summary (line of text below the
 * preference title) is updated to reflect the value. The summary is also
 * immediately updated upon calling this method. The exact display format is
 * dependent on the type of preference.
 *
 * @see #sBindPreferenceSummaryToValueListener
 */
/* private static void bindPreferenceSummaryToValue(Preference preference) {
    // Set the listener to watch for value changes.
    preference
      .setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
    // Trigger the listener immediately with the preference's
    // current value.
    sBindPreferenceSummaryToValueListener.onPreferenceChange(
        preference,
        PreferenceManager.getDefaultSharedPreferences(
            preference.getContext()).getString(preference.getKey(), ""));
} */
于 2013-12-25T21:48:52.300 に答える