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等逻辑... }
为什么这样改?
- 移除了错误的
TargetFragment接口实现:这个接口的作用是让DialogFragment找到对应的Fragment来处理结果,而不是让Preference本身实现它,之前的错误实现触发了系统的异常检查。 - 采用
FragmentResultAPI:这是Google推荐的替代setTargetFragment的组件通信方式,它不受Fragment生命周期影响,也能处理配置变更(比如屏幕旋转)后的状态恢复问题。 - 逻辑更清晰:DialogFragment负责发送结果,SettingsFragment负责监听和处理,符合单一职责原则。
内容的提问来源于stack exchange,提问作者Clandes
相关产品推荐
相关产品推荐

