You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PreferenceActivity中DialogPreference适配:替换过时setTargetFragment为setFragmentResultListener遇TargetFragment接口实现异常求助

解决DialogPreference中setTargetFragment过时及TargetFragment接口异常问题

看起来你在替换过时的setTargetFragment时踩了两个关键坑:一是错误地让DialogPreference实现了TargetFragment接口,二是FragmentResultListener的逻辑搞反了。下面是完整的修复方案:

第一步:修正DialogPreferenceClearStats类

DialogPreference.TargetFragment接口是给Fragment实现的,不是给Preference类的,这正是你抛出异常的原因。我们先把这个错误的实现去掉:

class DialogPreferenceClearStats(context: Context, attrs: AttributeSet?) : DialogPreference(context, attrs) {
    // 这里不需要任何额外接口实现,保持基础DialogPreference即可
}

第二步:改造DialogPrefCompat使用FragmentResult传递结果

我们用Jetpack推荐的FragmentResult API替代过时的setTargetFragment,让DialogFragment通过FragmentResultManager把结果传递给SettingsFragment:

class DialogPrefCompat : PreferenceDialogFragmentCompat() {
    companion object {
        // 定义唯一的请求Key和结果Key
        const val REQUEST_KEY_CLEAR_STATS = "request_clear_stats"
        const val KEY_POSITIVE_CONFIRM = "key_positive_confirm"

        fun newInstance(key: String): DialogPrefCompat {
            val fragment = DialogPrefCompat()
            val bundle = Bundle(1)
            bundle.putString(PreferenceDialogFragmentCompat.ARG_KEY, key)
            fragment.arguments = bundle
            return fragment
        }
    }

    override fun onDialogClosed(positiveResult: Boolean) {
        super.onDialogClosed(positiveResult)
        // 用FragmentResult把点击结果发送给SettingsFragment
        parentFragmentManager.setFragmentResult(REQUEST_KEY_CLEAR_STATS, Bundle().apply {
            putBoolean(KEY_POSITIVE_CONFIRM, positiveResult)
        })
    }
}

第三步:修正SettingsFragment的逻辑

现在我们在SettingsFragment中正确监听Dialog的结果,并在onDisplayPreferenceDialog中直接显示DialogFragment即可:

class SettingsFragment : PreferenceFragmentCompat() {
    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        setPreferencesFromResource(R.xml.root_preferences, rootKey)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // 监听DialogFragment返回的结果
        parentFragmentManager.setFragmentResultListener(DialogPrefCompat.REQUEST_KEY_CLEAR_STATS, viewLifecycleOwner) { _, resultBundle ->
            val isConfirmed = resultBundle.getBoolean(DialogPrefCompat.KEY_POSITIVE_CONFIRM, false)
            if (isConfirmed) {
                Toast.makeText(activity, "yes", Toast.LENGTH_LONG).show()
                // 这里添加你的清除统计逻辑
            }
        }
    }

    override fun onDisplayPreferenceDialog(preference: Preference?) {
        val clearStatsDialog = preference as? DialogPreferenceClearStats
        if (clearStatsDialog != null) {
            // 直接显示DialogFragment,不需要setTargetFragment
            val dialogFragment = DialogPrefCompat.newInstance(clearStatsDialog.key)
            dialogFragment.show(parentFragmentManager, DialogPrefCompat::class.java.simpleName)
        } else {
            super.onDisplayPreferenceDialog(preference)
        }
    }

    // 保留你原有的onPreferenceTreeClick等逻辑...
}

为什么这样改?

  1. 移除了错误的TargetFragment接口实现:这个接口的作用是让DialogFragment找到对应的Fragment来处理结果,而不是让Preference本身实现它,之前的错误实现触发了系统的异常检查。
  2. 采用FragmentResult API:这是Google推荐的替代setTargetFragment的组件通信方式,它不受Fragment生命周期影响,也能处理配置变更(比如屏幕旋转)后的状态恢复问题。
  3. 逻辑更清晰:DialogFragment负责发送结果,SettingsFragment负责监听和处理,符合单一职责原则。

内容的提问来源于stack exchange,提问作者Clandes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 17:44:08