?原來一個應用中的設置是這樣,如圖,布局代碼也就常規(guī)的那個樣子, 里面的值也是用SharedPreferences 自己去管理存儲和獲取,現(xiàn)在想用Preference 改造下, 看看哪種代碼少,便于維護,


放一些連接, 主要根據(jù)這里面的教程去實現(xiàn),中間有問題再去看別人寫的博客和總結?
https://developer.android.google.cn/guide/topics/ui/settings??
https://developer.android.google.cn/jetpack/androidx/releases/preference?hl=zh_cn
項目gradle中添加?
def preference_version = "1.1.1"
// Java language implementation
implementation
"androidx.preference:preference:$preference_version"http:// Kotlin
implementation
"androidx.preference:preference-ktx:$preference_version"
使用了androidx 的包項目需要支持androidx
一 概述
根據(jù)概述 在res/xml 下添加特殊的布局文件 和 fragment? 和承載fragment 的 Activity
二 管理您的設置中
如果設置不多 可以不管 ,案例暫時用PreferenceCategory 把三個ip設置歸為一欄??
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
? ? <PreferenceCategory android:title="@string/setting_ipset">
? ? ? ? <EditTextPreference
? ? ? ? ? ? ? ? android:defaultValue="172.20.20.48:8080"
? ? ? ? ? ? ? ? android:key="preference_printserver_ip"
? ? ? ? ? ? ? ? android:selectAllOnFocus="true"
? ? ? ? ? ? ? ? android:singleLine="true"
? ? ? ? ? ? ? ? android:title="@string/setting_inputipport" />
? ? ? ? <EditTextPreference
? ? ? ? ? ? ? ? android:defaultValue="192.168.1.111"
? ? ? ? ? ? ? ? android:key="preference_print_ip"
? ? ? ? ? ? ? ? android:selectAllOnFocus="true"
? ? ? ? ? ? ? ? android:singleLine="true"
? ? ? ? ? ? ? ? android:title="@string/setting_printip" />
? ? ? ? <EditTextPreference
? ? ? ? ? ? ? ? android:defaultValue="172.20.20.48:8081"
? ? ? ? ? ? ? ? android:key="preference_faceserver_ip"
? ? ? ? ? ? ? ? android:selectAllOnFocus="true"
? ? ? ? ? ? ? ? android:singleLine="true"
? ? ? ? ? ? ? ? android:title="@string/setting_faceipport" />
? ? </PreferenceCategory>
</PreferenceScreen>
三 自定義您的設置
介紹了使用?findPreference 獲取到每一個設置,和findById 功能類似?
可用?isVisible 來設置空間的顯示和隱藏?
這里使用了動態(tài)更新摘要 還是比較有用 可以顯示設置了的值,
然后是自定義對話框??這里只允許輸入數(shù)字和符號 InputType.TYPE_NUMBER_FLAG_SIGNED
后面的設置添加intent 和點擊監(jiān)聽暫時用不到,
private fun initEditText(editText:EditTextPreference?){
? ? editText?.summaryProvider =
Preference.SummaryProvider<EditTextPreference> { preference->
? ? ? ? ? ? val text = preference.text
? ? ? ? ? ? if (TextUtils.isEmpty(text)) {
? ? ? ? ? ? ? ? "Not Set"
? ? ? ? ? ????? } else {
? ? ? ? ? ? ? ? text
????????????????}
? ? ? ????? }
? ? editText?.setOnBindEditTextListener{ editTextTemp->
? ? ? ? editTextTemp.inputType = InputType.TYPE_NUMBER_FLAG_SIGNED
? ? }
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
? ? setPreferencesFromResource(R.xml.setting, rootKey)
? ? val printserverip = findPreference<EditTextPreference>("preference_printserver_ip")
? ? val printip = findPreference<EditTextPreference>("preference_print_ip")
? ? val faceserverip = findPreference<EditTextPreference>("preference_faceserver_ip")
? ? initEditText(printserverip)
? ? initEditText(printip)
? ? initEditText(faceserverip)
}
四 管理您的設置
上面第二點不適用, 設置有點長,如果全部寫一個頁面里, 需要滑動,頁面底部的設置滑動上不方便,所以還是根據(jù)官網(wǎng)中把每個拆開放單獨的頁面里.
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
? ? <PreferenceCategory android:title="">
? ? ? ? <Preference
? ? ? ? ? ? ? ? android:fragment="com.insolu.insoledemo.fragment.MySetting_IP"
? ? ? ? ? ? ? ? android:title="@string/setting_ipset">
? ? ? ? </Preference>
? ? <!-- 省略 -->
? ? </PreferenceCategory>
把所有設置拆 成四個 點擊后再進入具體的設置頁面?

主要是?? android:fragment="com.insolu.insoledemo.fragment.MySetting_IP"? 指定設置頁面,具體跳轉(zhuǎn)內(nèi)部會自己管理
五 自定義您的設置
上面第三點已經(jīng)描述了寫法和作用 這里敘述下遇到的幾個問題??EditTextPreference 和 layout 中使用EditText 有些設置不一樣.比如ip 只需要數(shù)字,點 和:冒號 layout 使用?android:digits="1234567890.:" 設置就可以, 在EditTextPreference? 中沒有這個設置,文檔中讓使用inputType 但也沒有數(shù)字加符號的設置,最后是設置的 filters ,創(chuàng)建一個IpFilter類實現(xiàn)?InputFilter 接口,創(chuàng)建 一個內(nèi)部類IpFilterTemp 再繼承IpFilter 重寫?isAllowed 方法 .寫法是參照android.text.LoginFilter 里面的UsernameFilterGMail 去編寫的:
@Override
public boolean isAllowed(char c) {
? ? // Allow [a-zA-Z0-9@.]
? ? if ('0' <= c && c <='9')
? ? ? ? return true;
? ? if ('.' == c)
? ? ? ? return true;
? ? if (':' == c)
? ? ? ? return true;
return false;
}
達到設置的目的. 網(wǎng)上搜到過類似做法.
2. 然后就是密碼 的設置 使用?edit.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD .
3. 定時重啟有個時間的設置 格式要是 03:33 這種 ,做的比較暴力 直接在值修改的監(jiān)聽上,判斷新的值是否滿足 正則表達式
// 設置監(jiān)聽?
rebootTime?.setOnPreferenceChangeListener{ preference, newValue->
? ? val daytime: String = newValue as String
? ?val temp = checkDayTime(daytime)
? ? temp
}
// 返回是否滿足正則表達是?
fun checkDayTime(daytime: String): Boolean{
? ? val regex2 ="^(((0|1)[0-9])|(2[0-3])):[0-5][0-9]"
? ? return Pattern.matches(regex2, daytime)
}
六 使用
使用就很簡單了? ,官網(wǎng)中的代碼.
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this /* Activity context */)val name = sharedPreferences.getString("signature", "")
七 總結
整體修改 肯定是 Preference 代碼更少, 以后維護也更方便, 最開始那種寫法 在退出設置頁面 還需要監(jiān)聽返回按鍵 退出還要把修改的項自己保存進?SharedPreferences? , 而且所有的內(nèi)容都在一個頁面,整個文件代碼也比較多,? ?以前的設置頁面代碼行數(shù)大約 720 現(xiàn)在大約? 348 .布局代碼 以前400 現(xiàn)在161 .少了很多,.
最后.? Preference 現(xiàn)在默認使用的還是?SharedPreferences? 存儲數(shù)據(jù) ,可以改為 datastore 存儲數(shù)據(jù).數(shù)據(jù)獲取變成Flow 的方式.之后整改的時候再記錄了.
datastore? 的官方鏈接 : https://developer.android.google.cn/topic/libraries/architecture/datastore?
第一次寫 多多包涵,二 三, 和四,五 ,內(nèi)容差不多,但最后沒有去整理, 因為在真實改造時候確實是按照文章的先后順序來的,當你的設置內(nèi)容少,可能二,三就完了,? 這也是改造中的一個過程,看肯定是不夠的, 希望你也可以按照官方文檔實際操作一番, 可能會發(fā)現(xiàn)對你更有用的介紹, 比如后面一些監(jiān)聽的設置. 如果你有關于文檔任何地方更好的建議或?qū)懛?可以評論告訴我. 謝謝,