Android解决PreferenceFragmentCompat不能保存Int的缺陷

概要

这篇主要讲一下,我在使用PreferenceFragmentCompat发现不能保存Int的问题和解决方法

问题原因

主要原因不在PreferenceFragmentCompat本身,而是布局中使用的ListPreference,是ListPreference只支持String。既然找到原因所在那咱就开始分析源码看看有没有什么解决办法。

问题分析

看了PreferenceFragmentCompat之后得出以下几点:

  • PreferenceFragmentCompat需要一个PreferenceScreen作为根节点布局
  • PreferenceFragmentCompat的布局都继承Preference
  • ListPreference继承的是一个DialogPreference,从名字能看出来这是一个可以显示Dialog的Preference,继续往下看
  • 从报错时间分析,只要进入PreferenceFragmentCompat画面,第二次就会报错,那么肯定是第一次进入PreferenceFragmentCompat画面时,他会自动保存一次初始值,第二次进来一读取就会导致数据类型转换异常,那我们就需要找到初始存储和读取的地方

在这里插入图片描述
ListPreference一眼看就到了setValuegetValue,其中setValue

在这里插入图片描述
这里persistString就是用来存储字符串的,刚好这个方法是public这意味着我可以继承这个方法重写,接下找读取的地方,在getValue只是返回了一个mValue,那么这个值从那里读出来复制的呢?继续看
在这里插入图片描述
原来在onSetInitialValue呀,看到这个函数名字我心里就开始高兴了,一看就是初始赋值的地方,嘿嘿,这个函数是protected也能重写,太好了!

解决方法

既然都继承那就简单了呀,直接自定义一个IntListPreference继承ListPreference,再重写onSetInitialValuesetValue还有getValue

class IntListPreference : ListPreference {
    
    

    private var mValue = 0

    private var mValueSet = false

    constructor(
        context: Context,
        attrs: AttributeSet?,
        defStyleAttr: Int,
        defStyleRes: Int
    ) : super(context, attrs, defStyleAttr, defStyleRes)

    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    )

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)

    constructor(context: Context) : super(context)


    override fun onSetInitialValue(defaultValue: Any?) {
    
    
        value = getPersistedInt(defaultValue as? Int ?: 0).toString()
    }


    override fun setValue(value: String?) {
    
    
        val intValue = value?.toIntOrNull() ?: 0
        // Always persist/notify the first time.
        val changed = mValue != intValue
        if (changed || !mValueSet) {
    
    
            mValue = intValue
            mValueSet = true
            persistInt(intValue)
            if (changed) {
    
    
                notifyChanged()
            }
        }
    }

    override fun getValue(): String {
    
    
        return mValue.toString()
    }
}

OK,完美,亲测有效,目前没有任何问题,你们也可以根据需要举一反三不一定是int,比如floatlong看你们需求实现,不同数据类型的保存和取值就行了

小结

总得来说结果还是好的,ListPreference控件官方虽然没有直接支持设置保存类型的属性,但是可以上面这种自定义控件的方式实现,我这里为了实现方便就直接用的int,如果你们追求完美可以自定义一个ListPreference添加指定数据类型属性,这样就能保存任意数据类型了

有任何问题或好的解决办法都可以在下方留言,互相交流学习!

猜你喜欢

转载自blog.csdn.net/qq_39457683/article/details/133083594