13

注意:请节省一些时间并参考已接受的答案,无需阅读所有问题。
您可以阅读问题的其余部分以及我为替代(虽然不太复杂)方法提供的答案。
此外,您可能希望通过将相关代码添加到您的偏好活动类中来利用 Android 2.X 中背景故障的修复。

背景
作为 Android 编码的新手,但在其他编程语言/框架方面有一定的经验,我期待我的 Android 应用程序编码之旅会是一个相当愉快的过程。就是这样,直到我偶然发现了这个问题:

Android 项目的 Eclipse 向导建议,如果我将最小 API 设置为 8(Android 2.2),我可以覆盖 95% 的设备。反正我不需要用我的应用程序做任何花哨的事情,所以我想,“当然,为什么不呢?”。一切都很好,除了偶尔我会发现一些在最近的 API 版本中被弃用的方法/类,所以我不得不想办法在旧设备上继续使用旧方法,并尝试尽可能多地使用新的较新的 Android 版本的方法。这是一个这样的场合。

在使用 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 版本。我阅读了整个线程并找到了几个解决问题的建议,但我真的不喜欢其中任何一个。一方面,我更喜欢尽可能多地避免静态的东西,并以编程方式做事。我更喜欢自动化而不是重复性工作。一些解决方案建议将子屏幕创建为父屏幕,然后将它们添加到清单文件中,并通过意图从父屏幕调用它们。我真的很讨厌必须跟踪这些事情:清单中的条目、分离的屏幕资源文件、意图......所以这对我来说是一个禁忌。我一直在寻找并找到了一种我更喜欢的程序化方法……却发现它不起作用。它包括遍历首选项屏幕的整个视图树并为首选项子屏幕分配适当的背景,但它只是不起作用,因为我后来在经过多次调试后发现,首选项子屏幕视图不是偏好屏幕视图的孩子。我必须自己想办法实现这一目标。我尝试了尽可能多的东西,研究和研究无济于事。有好几次我都处于放弃的边缘,但经过大约两周的持续努力和大量调试,我找到了一个解决方法,我在评论 #35 中发布了它。我尝试了尽可能多的东西,研究和研究无济于事。有好几次我都处于放弃的边缘,但经过大约两周的持续努力和大量调试,我找到了一个解决方法,我在评论 #35 中发布了它。我尝试了尽可能多的东西,研究和研究无济于事。有好几次我都处于放弃的边缘,但经过大约两周的持续努力和大量调试,我找到了一个解决方法,我在评论 #35 中发布了它。

意见
这确实不是完美的解决方案/方法,我知道它的一些缺点,但它是一个有效的方法,所以我决定分享它。希望我的热情不会太荒谬,因为我知道这不是什么大问题,任何有经验的编码人员都可以解决。但是,嘿,我认为分享知识让我更好一点,无论我多么吹嘘,都比一个经验丰富的程序员对自己保密。只是分享我的观点,因为我不敢相信以前没有人遇到过这个问题,但我相信很多人都遇到过这个问题并且懒得分享他们的知识。

我在答案中向您展示了一个在多个版本的 Android 上使用的建议类,以及一些关于其使用的建议。我愿意进行讨论和贡献,以使其成为更好的课程。

已知的问题:

  • 父屏幕装饰视图背景被克隆到子屏幕装饰视图背景上,这显然不是正常行为。
    状态:在有人提出解决此问题的充分理由之前被解雇
  • 屏幕旋转时崩溃
    状态:已修复。
    可能与较新的 API 实现(内部类 PF)的资源可见性有关
    显然从 preferenceFragment 继承的类需要使其所有成员都是静态的。我想如果每次需要使用新片段时都应该继承是有道理的
4

3 回答 3

18

如果您使用的是最新的 ADT 插件,则可以选择轻松创建支持大多数旧 Android 版本以及所有新版本的首选项 Activity。

右键单击您的项目 -> 其他 -> Android Activity

然后选择 SettingsActivity 在此处输入图像描述

创建的 Activity 将负责处理高和低 API 版本,因为它使用 if 语句来选择显示首选项的适当方法。


编辑
提出了一个很好的观点:电话大小的设备,无论 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()被称为。

为了摆脱这种情况,我们需要创建自己的 PreferenceFragment 来添加每个 xml 资源。

@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决定是否显示这个片段(假设你对这个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 很快就变得很老了。必须向上和向下滚动过去的样板代码 - 而且它充满了黄色警告,我讨厌黄色(虽然不能完全避免不推荐使用的警告 - 请参阅在 PreferenceActivity 中使用什么代替“addPreferencesFromResource”?,这也是问题所在还涉及到如何制作跨 API PreferenceActivity- 以及是否有意将 PreferenceFragment 从兼容性包中排除?进行讨论)。而且你也可以很容易地得到一个 NPE - 你知道那onPostCreate()实际上是-onPostStart()所以findPreference()返回nullonStart()

现在有一些涉及反射的解决方案,但要避免反射(就像地狱一样) - 因为我们对前 2 个版本的 android 不感兴趣,所以可以避免反射请参阅Is checks SDK_INT enough or is lazy loading required for using new android API?为什么?)。还有一些解决方案涉及在运行时选择一个类 - 但有 2 个类很糟糕,而且无论如何都不是 OOP(对于这些和其他解决方案,请参阅相关问题的答案:PreferenceActivity Android 4.0 及更早版本)。

所以我想出了一个抽象基类,这是正确的 Java 和 OO 做事方式(除非你需要 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 回答