在用户设置时更新 Android 中的首选项摘要

Updating a preference summary in Android when the user sets it

我想使用偏好摘要来显示偏好的当前值,因此我想在偏好更改时更新摘要。有问题的首选项是一个存储位置,由用户通过意图以交互方式选择,使用 Android 的存储访问框架。几个小时以来,我一直在为此苦思冥想,尝试在 SO 线程中找到的各种东西,但我无法弄清楚 setSummaryfindPreferenceonSharedPreferenceChanged 的组合,onSharedPreferenceChangeListener,在其中调用class,我需要

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

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: 
            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: 
            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:" />

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

由于您是在首选项本身之外手动更改设置,因此您无法使用 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: 
        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", "")
    }
}

,如果您想以在片段中提供更清晰代码的方式解决此问题,您可以创建 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 中将此设置为您的偏好类型。

然后你的片段看起来像这样。请注意,您通过创建的 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: 
        if (requestCode == REQUEST_TARGET_FOLDER && resultCode == RESULT_OK && intent != null) {
            val treeUri = intent.data
            if (treeUri != null) {
                // do stuff
            }
            targetDirPreference.value = intent.data.toString()
        }
    }

}