Android Preference 笔记

本文深入探讨了Android中偏好设置(Preference)的使用方法,包括Preference的类结构、与Activity和Fragment的组合使用、ActionBar的控制、点击回调事件、持久化存储及自定义Preference等关键知识点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

目录

 

1.从PreferenceScreen 中 删除某个Preference

2. Preference类图

3.  Activity&Fragment / Preference&Fragment 组合使用

4. Actionbar (标题: 显示与隐藏 )

4.1  AppCompatActivity  默认有标题

4.2 PreferenceActivity 默认没有标题

5. Preference 点击回调事件(OnPreferenceClickListener 、OnPreferenceChangeListener)

6. persistent  是否存储在内存中

7. SharedPreferences


1.从PreferenceScreen 中 删除某个Preference

(1) . 先获取PreferenceScreen

PreferenceScreen ps = getPreferenceScreen();

(2).  获取要删除的Preference

Preference pf = findPreference(pfKey); // pfKey 为String类型


3. 删除
if (pf != null && ps != null) {
   ps.removePreference(pf);
}

其中removePreference 会返回 boolean 值, 删除成功true,  否正false

从 PreferenceCategory 中删除Preference 也是类似,先要获取PreferenceCategory

 

2. Preference类图

(1) PreferenceGroup 是Preference 的子类,也是一个抽象类,可以拥有一个或者多个Preference, 类似View 和ViewGroup.

 (2) PreferenceScreen 和PreferenceCategory 是PreferenceGroup的子类,扩展少量方法

(3) PreferenceScreen 作为xml 布局文件根标签时,其设置的Titile 是不会显示的(需要设置主题支持Actionbar类型的,才会显示)

     PreferenceScreen 内部再嵌套一个PreferenceScreen时(组合), 内部的PreferenceScreen会显示Titile(点跳转后!!!), 但是其内部的Preference需要点击后才会显示出来

如: 

<PreferenceScreen
        xmlns:android="http://schemas.android.com/apk/res/android"
        <!--Title 不显示-->
		android:title="WiFi"
        android:key="first_preferencescreen">
    <CheckBoxPreference
            android:key="wifi enabled"
            android:title="WiFi" />
    <PreferenceScreen
            android:key="second_preferencescreen"
            <!--Title 显示-->
            android:title="WiFi settings">
        <!--内部Preference 不显示!!!! 需要点击进入后再显示Prefer wifi-->
        <CheckBoxPreference
                android:key="prefer wifi"
                android:title="Prefer WiFi" />
    </PreferenceScreen>
</PreferenceScreen>

(4) 使用PreferenceCategory 可以显示标题, 并且Title这一行不能点击,因为PreferenceCategory内部覆写

public boolean isEnabled() {
        return false;
}

更多详细可以参考 https://blog.youkuaiyun.com/weixin_31767183/article/details/77748421

 

3.  Activity&Fragment / Preference&Fragment 组合使用

其中,PreferenceFragmentCompat 可以自定义定制化的风格,作为父类提供一个app或者一个系统使用,使得风格统一。 

(通过依赖库的方式编译进去,一样可以是androidx.preference的包名)

 

4. Actionbar (标题: 显示与隐藏 )

标题是否显示 与 它的主题 (Theme有关)

4.1  AppCompatActivity  默认有标题

    /**
     * Support library version of {@link android.app.Activity#getActionBar}.
     *
     * <p>Retrieve a reference to this activity's ActionBar.
     *
     * @return The Activity's ActionBar, or null if it does not have one.
     */
    @Nullable
    public ActionBar getSupportActionBar() {
        return getDelegate().getSupportActionBar();
    }

有两种方式隐藏标题

一种是在AndroidManifest 配置NoActionBar主题, 如 android:theme="@style/Theme.AppCompat.NoActionBar"

        <activity
            android:name=".XXXXActivity"
            android:theme="@style/Theme.AppCompat.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
            </intent-filter>
        </activity>

另一种是在代码里配置, 如

getSupportActionBar().hide()

4.2 PreferenceActivity 默认没有标题

如果要显示标题, 在代码里配置主题 (可以引用android 库里的主题)

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        if(Build.VERSION.SDK_INT> Build.VERSION_CODES.HONEYCOMB_MR2){
            this.setTheme(android.R.style.Theme_DeviceDefault);
        }
}

5. Preference 点击回调事件(onClick /OnPreferenceClickListener 、OnPreferenceChangeListener)

在 onBindViewHolder 的时候,设置 onClickListener,  这个listener 其实就是实现 View 的OnClickListener,   Preference 内部交给performClick 处理。 详见后面

    private final View.OnClickListener mClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            performClick(v);
        }
    };

    public void onBindViewHolder(PreferenceViewHolder holder) {
        View itemView = holder.itemView;
        Integer summaryTextColor = null;

        itemView.setOnClickListener(mClickListener);

 

提供点击监听的回调接口给客户端, 客户端可以决定是否响应事件 以及 在更新Preference 前进行设置操作(如设置Summary)

通过返回true 或者 false 告诉系统。 (例如 客户端在CheckBoxPreference中设置了监听, 实现了OnPreferenceChangeListener, 但是返回值为false, 则不会进行更新操作checked)

    /**
     * Interface definition for a callback to be invoked when a {@link Preference} is
     * clicked.
     *
     * @deprecated Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
     *      <a href="{@docRoot}reference/androidx/preference/package-summary.html">
     *      Preference Library</a> for consistent behavior across all devices.
     *      For more information on using the AndroidX Preference Library see
     *      <a href="{@docRoot}guide/topics/ui/settings.html">Settings</a>.
     */
    @Deprecated
    public interface OnPreferenceClickListener {
        /**
         * Called when a Preference has been clicked.
         *
         * @param preference The Preference that was clicked.
         * @return True if the click was handled.
         */
        boolean onPreferenceClick(Preference preference);
    }
    /**
     * Interface definition for a callback to be invoked when the value of this
     * {@link Preference} has been changed by the user and is
     * about to be set and/or persisted.  This gives the client a chance
     * to prevent setting and/or persisting the value.
     *
     * @deprecated Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
     *      <a href="{@docRoot}reference/androidx/preference/package-summary.html">
     *      Preference Library</a> for consistent behavior across all devices.
     *      For more information on using the AndroidX Preference Library see
     *      <a href="{@docRoot}guide/topics/ui/settings.html">Settings</a>.
     */
    @Deprecated
    public interface OnPreferenceChangeListener {
        /**
         * Called when a Preference has been changed by the user. This is
         * called before the state of the Preference is about to be updated and
         * before the state is persisted.
         *
         * @param preference The changed Preference.
         * @param newValue The new value of the Preference.
         * @return True to update the state of the Preference with the new value.
         */
        boolean onPreferenceChange(Preference preference, Object newValue);
    }

performClick 里的逻辑, 如果有为Preference 设置intent ,则会调用startActivity 跳转

    @RestrictTo(LIBRARY_GROUP_PREFIX)
    public void performClick() {

        if (!isEnabled() || !isSelectable()) {
            return;
        }

        onClick();

        if (mOnClickListener != null && mOnClickListener.onPreferenceClick(this)) {
            return;
        }

        PreferenceManager preferenceManager = getPreferenceManager();
        if (preferenceManager != null) {
            PreferenceManager.OnPreferenceTreeClickListener listener = preferenceManager
                    .getOnPreferenceTreeClickListener();
            if (listener != null && listener.onPreferenceTreeClick(this)) {
                return;
            }
        }

        if (mIntent != null) {
            Context context = getContext();
            context.startActivity(mIntent);
        }
    }

 

6. persistent  是否存储在内存中(android:persistent="true")

        <!-- Whether the Preference stores its value to the storage. -->
        <attr name="persistent" />
    <!-- Flag to control special persistent mode of an application.  This should
         not normally be used by applications; it requires that the system keep
         your application running at all times. -->
    <attr name="persistent" format="boolean" />

如果是false, 则退出Preference 后,再进入, 值不会保存。

 

6.1  CheckBoxPreference(TwoStatePreference)

在响应onClick 的时候,会回调(如果有注册监听), 并在setChecked的时候,调用persistXXX(例如 persistBoolean) 进行存储。

因此使用Preference 后, 会对其xml 定义的key值进行存储, 不需要手动调用SharePreference.edit.putXXX(key, value).apply 进行存储。

默认值可以用 android.defaultValue 设置, 会存储到Preference 对应的SharePreference中

//TwoStatePreference.java
    @Override
    protected void onClick() {
        super.onClick();

        final boolean newValue = !isChecked();
        if (callChangeListener(newValue)) {
            setChecked(newValue);
        }
    }

    /**
     * Sets the checked state and saves it to the {@link SharedPreferences}.
     *
     * @param checked The checked state.
     */
    public void setChecked(boolean checked) {
        // Always persist/notify the first time; don't assume the field's default of false.
        final boolean changed = mChecked != checked;
        if (changed || !mCheckedSet) {
            mChecked = checked;
            mCheckedSet = true;
            persistBoolean(checked);
            if (changed) {
                notifyDependencyChange(shouldDisableDependents());
                notifyChanged();
            }
        }
    }

 

//Preference.java
    /**
     * Attempts to persist a boolean if this Preference is persistent.
     *
     * @param value The value to persist.
     * @return True if this Preference is persistent. (This is not whether the
     *         value was persisted, since we may not necessarily commit if there
     *         will be a batch commit later.)
     * @see #persistString(String)
     * @see #getPersistedBoolean(boolean)
     */
    protected boolean persistBoolean(boolean value) {
        if (!shouldPersist()) {
            return false;
        }

        if (value == getPersistedBoolean(!value)) {
            // It's already there, so the same as persisting
            return true;
        }

        PreferenceDataStore dataStore = getPreferenceDataStore();
        if (dataStore != null) {
            dataStore.putBoolean(mKey, value);
        } else {
            SharedPreferences.Editor editor = mPreferenceManager.getEditor();
            editor.putBoolean(mKey, value);
            tryCommit(editor);
        }
        return true;
    }

6.2 普通Preference 存储字符串

/**
     * Attempts to persist a String if this Preference is persistent.
     *
     * @param value The value to persist.
     * @return True if this Preference is persistent. (This is not whether the
     *         value was persisted, since we may not necessarily commit if there
     *         will be a batch commit later.)
     * @see #getPersistedString(String)
     */
    protected boolean persistString(String value) {
        if (!shouldPersist()) {
            return false;
        }

        // Shouldn't store null
        if (TextUtils.equals(value, getPersistedString(null))) {
            // It's already there, so the same as persisting
            return true;
        }

        PreferenceDataStore dataStore = getPreferenceDataStore();
        if (dataStore != null) {
            dataStore.putString(mKey, value);
        } else {
            SharedPreferences.Editor editor = mPreferenceManager.getEditor();
            editor.putString(mKey, value);
            tryCommit(editor);
        }
        return true;
    }

读取存储的字符串

    /**
     * Attempts to get a persisted String if this Preference is persistent.
     *
     * @param defaultReturnValue The default value to return if either this
     *            Preference is not persistent or this Preference is not present.
     * @return The value from the data store or the default return
     *         value.
     * @see #persistString(String)
     */
    protected String getPersistedString(String defaultReturnValue) {
        if (!shouldPersist()) {
            return defaultReturnValue;
        }

        PreferenceDataStore dataStore = getPreferenceDataStore();
        if (dataStore != null) {
            return dataStore.getString(mKey, defaultReturnValue);
        }

        return mPreferenceManager.getSharedPreferences().getString(mKey, defaultReturnValue);
    }

 

 

7. SharedPreferences

是一个接口???


根据同一个Context 获取到的SharePreference, 对命名相同key赋值或者读取时,实际是对同一个Key操作

public class ContextWrapper extends Context {
    @UnsupportedAppUsage
    Context mBase;
    //....
    @Override
    public SharedPreferences getSharedPreferences(String name, int mode) {
        return mBase.getSharedPreferences(name, mode);
    }
}
 

8. 自定义Preference (如添加一个Preference 的属性值)

8.1 attrs.xml 添加自定义类型(declare-styleable)

其中,entryValue 为属性值,  groupKey 则可以拓展为当前Preference 属于哪一个Group 组

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="XXXPreference">
        <attr name="entryValue" format="string"></attr>
        <attr name="groupKey" format="string"></attr>
    </declare-styleable>
</resources>

8.2 获取自定义的属性值

通过TypedArray 

    public XXXPreference(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.XXXPreference, 0, 0);
        String key = getKey();
        if (key != null) {
            mKey = key;
        }
        mGroupKey = a.getText(R.styleable.RadioPreference_groupKey).toString();
        mValue = a.getText(R.styleable.RadioPreference_entryValue).toString();
        a.recycle();
    }

注意:XML 定义的Preference 的默认构造函数是

    public XXXGroupPreference(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
        setWidgetLayoutResource(R.layout.radiogroup);
        mContext = context;
    }

其中 radiogroup 为自定义的布局

 

8.3 XML 文件使用自定义Preference

其中app:entryValue 和  app:groupKey 即为自定义的属性  (xml文件的根标签 需要添加工具 xmlns:app="http://schemas.android.com/apk/res-auto")

                <com.example.Test.XXXPreference

                    android:key="@string/pref_test"
                    android:defaultValue="false"
                    android:persistent="true"
                    app:entryValue="@string/val_test_value"
                    app:groupKey="@string/pref_test_group"
                    android:title="@string/title_test" />

这样,可以为Preference 新增一个属性,并且可以在XML 使用时赋值, 简单明了。

(也可以在定义一个数组,在代码中为各个Preference的自定义属性赋值)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值