概要
这篇主要讲一下,我在使用PreferenceFragmentCompat
发现不能保存Int
的问题和解决方法
问题原因
主要原因不在PreferenceFragmentCompat
本身,而是布局中使用的ListPreference
,是ListPreference
只支持String
。既然找到原因所在那咱就开始分析源码看看有没有什么解决办法。
问题分析
看了PreferenceFragmentCompat
之后得出以下几点:
PreferenceFragmentCompat
需要一个PreferenceScreen
作为根节点布局PreferenceFragmentCompat
的布局都继承Preference
ListPreference
继承的是一个DialogPreference
,从名字能看出来这是一个可以显示Dialog的Preference,继续往下看- 从报错时间分析,只要进入
PreferenceFragmentCompat
画面,第二次就会报错,那么肯定是第一次进入PreferenceFragmentCompat
画面时,他会自动保存一次初始值,第二次进来一读取就会导致数据类型转换异常,那我们就需要找到初始存储和读取的地方
从ListPreference
一眼看就到了setValue
和getValue
,其中setValue
这里persistString
就是用来存储字符串的,刚好这个方法是public
这意味着我可以继承这个方法重写,接下找读取的地方,在getValue
只是返回了一个mValue
,那么这个值从那里读出来复制的呢?继续看
原来在onSetInitialValue
呀,看到这个函数名字我心里就开始高兴了,一看就是初始赋值的地方,嘿嘿,这个函数是protected
也能重写,太好了!
解决方法
既然都继承那就简单了呀,直接自定义一个IntListPreference
继承ListPreference
,再重写onSetInitialValue
和setValue
还有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
,比如float
、long
看你们需求实现,不同数据类型的保存和取值就行了
小结
总得来说结果还是好的,ListPreference控件官方虽然没有直接支持设置保存类型的属性,但是可以上面这种自定义控件的方式实现,我这里为了实现方便就直接用的int,如果你们追求完美可以自定义一个ListPreference添加指定数据类型属性,这样就能保存任意数据类型了
有任何问题或好的解决办法都可以在下方留言,互相交流学习!