【问题标题】:Updating a preference summary in Android when the user sets it在用户设置时更新 Android 中的首选项摘要
【发布时间】:2022-01-23 11:07:19
【问题描述】:

我想使用首选项摘要来显示首选项的当前值,因此我想在首选项更改时更新摘要。所讨论的首选项是一个存储位置,由用户通过意图交互选择,使用 Android 的存储访问框架。我已经为此苦苦思索了好几个小时,尝试了在 SO 线程中找到的各种东西,但我就是不知道调用了 setSummaryfindPreferenceonSharedPreferenceChangedonSharedPreferenceChangeListener 的组合我需要在哪个班级。

我的代码目前看起来像这样:

const val REQUEST_TARGET_FOLDER = 4

class SettingsActivity : AppCompatActivity() {

    private lateinit var prefs: SharedPreferences
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.settings_activity)
        if (savedInstanceState == null) {
            supportFragmentManager
                .beginTransaction()
                .replace(R.id.settings, SettingsFragment())
                .commit()
        }

    }

    class SettingsFragment : PreferenceFragmentCompat() {
        override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
            setPreferencesFromResource(R.xml.root_preferences, rootKey)
            // from: https://stackoverflow.com/questions/63575398/how-to-correctly-receive-and-store-a-local-directory-path-in-android-preferences
            val targetDirPreference: Preference? = findPreference("export_dir")
            targetDirPreference?.setOnPreferenceClickListener {
                val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
                activity?.startActivityForResult(intent, REQUEST_TARGET_FOLDER)
                true
            }
        }

        override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
            super.onActivityResult(requestCode, resultCode, intent)
            // from: https://stackoverflow.com/questions/34331956/trying-to-takepersistableuripermission-fails-for-custom-documentsprovider-via
            if (requestCode == REQUEST_TARGET_FOLDER && resultCode == RESULT_OK && intent != null) {
                val treeUri = intent.data
                if (treeUri != null) {
                    // do stuff
                }
                with(prefs.edit()) {
                    putString("export_dir", intent.data.toString())
                    apply()
                }
            }
        }
    }

这是所涉及的偏好:

   <Preference
        android:key="export_dir"
        android:title="Export to directory:" />

有人可以帮我弄清楚当用户选择目录时如何设置/更新首选项的摘要吗? (目录选择部分本身目前有效。)

【问题讨论】:

    标签: android kotlin preferences


    【解决方案1】:

    由于您是在 Preference 本身之外手动更改设置,因此无法使用 SummaryProvider 执行此操作。相反,您必须在 (1) 首次出现摘要时和 (2) 当您手动更改首选项值并提交时手动更改摘要。 (您可以使用 OnSharedPreferenceChangeListener 自动执行第二步,但这更复杂。)

    因此,创建一个更新其摘要的函数并在两个位置调用它:onCreatePreferencesonActivityResult 您设置值的位置。

    顺便说一句,您可以使用preferences.edit { ... } 扩展函数而不是with(preferences.edit) { ... ; apply() } 来获得更简单的代码。

    class SettingsFragment : PreferenceFragmentCompat() {
    
        private val TARGET_DIR_KEY = "export_dir"
        private val prefs by lazy { preferenceManager.sharedPreferences }
        private val targetDirPreference: Preference by lazy {
            findPreference<Preference>(TARGET_DIR_KEY) ?: error("Missing target directory preference!")
        }
    
        override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
            setPreferencesFromResource(R.xml.root_preferences, rootKey)
    
            targetDirPreference.setOnPreferenceClickListener {
                val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
                startActivityForResult(intent, REQUEST_TARGET_FOLDER)
                true
            }
    
            updateTargetDirPreferenceSummary()
        }
    
        override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
            super.onActivityResult(requestCode, resultCode, intent)
            // from: https://stackoverflow.com/questions/34331956/trying-to-takepersistableuripermission-fails-for-custom-documentsprovider-via
            if (requestCode == REQUEST_TARGET_FOLDER && resultCode == RESULT_OK && intent != null) {
                val treeUri = intent.data
                if (treeUri != null) {
                    // do stuff
                }
                prefs.edit {
                    putString(TARGET_DIR_KEY, intent.data.toString())
                }
                updateTargetDirPreferenceSummary()
            }
        }
    
        private fun updateTargetDirPreferenceSummary() {
            targetDirPreference.summary = prefs.getString("feedback", "")
        }
    }
    

    OR,如果您想以一种在 Fragment 中提供更简洁代码的方式解决此问题,您可以创建一个 Preference 的子类来帮助管理设置值的更改,并在内部使用 SummaryProvider自动更新的机制。

    class ManualStringPreference @JvmOverloads constructor(
        context: Context,
        attrs: AttributeSet? = null
    ): Preference(context, attrs) {
    
        init {
            setSummaryProvider { getPersistedString("") }
        }
    
        var value: String = ""
            set(inValue) {
                if (inValue != field) {
                    field = inValue
                    persistString(inValue)
                    notifyChanged()
                }
            }
    
        override fun onSetInitialValue(defaultValue: Any?) {
            value = getPersistedString(defaultValue as? String ?: "")
        }
    
    }
    

    您需要在 XML 中将此设置为您的偏好类型。

    那么你的 Fragment 看起来像这样。请注意,您通过创建的 Preference 子类更改了 SharedPreferences 值。

    class SettingsFragment : PreferenceFragmentCompat() {
    
        private val prefs by lazy { preferenceManager.sharedPreferences }
        private val targetDirPreference: ManualStringPreference by lazy {
            findPreference<ManualStringPreference>("export_dir") ?: error("Missing target directory preference!")
        }
    
        override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
            setPreferencesFromResource(R.xml.root_preferences, rootKey)
    
            targetDirPreference.setOnPreferenceClickListener {
                val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
                startActivityForResult(intent, REQUEST_TARGET_FOLDER)
                true
            }
        }
    
        override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
            super.onActivityResult(requestCode, resultCode, intent)
            // from: https://stackoverflow.com/questions/34331956/trying-to-takepersistableuripermission-fails-for-custom-documentsprovider-via
            if (requestCode == REQUEST_TARGET_FOLDER && resultCode == RESULT_OK && intent != null) {
                val treeUri = intent.data
                if (treeUri != null) {
                    // do stuff
                }
                targetDirPreference.value = intent.data.toString()
            }
        }
    
    }
    

    【讨论】:

    • 谢谢,但是当我尝试您的建议时,它们都没有奏效。 prefs.edit 语法会生成以下错误:Too many arguments for public abstract fun edit(): SharedPreferences.Editor! defined in android.content.SharedPreferencesUnresolved reference: putString
    • updateTargetDirPreferenceSummary 函数会生成以下错误:findPreferenceNot enough information to infer type variable TsummaryVariable expected。我一定是做错了什么,但我已经遇到这些错误好几个小时了——我只是把一些类或函数放在了错误的地方吗?
    • 这只是一个建议。您不必更改那段代码。它需要导入扩展函数,并且您需要依赖项中的 Jetpack 代码库的 -ktx 版本才能使用它。
    • 应该是findPreference&lt;Preference&gt;(。抱歉,没有测试该部分并假设编译器可以推断它。
    • 啊,好吧。我有-ktx 的东西;我刚刚忘记了导入。对不起,噪音。我添加了类型声明并修复了另一个函数。
    猜你喜欢
    • 2013-02-27
    • 1970-01-01
    • 1970-01-01
    • 2015-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-06
    相关资源
    最近更新 更多