AndroidX环境下无法使用DialogPreference的解决方案咨询
解决AndroidX下自定义DialogPreference的类型转换异常
你碰到的com.example.todolist.TimePickerPreference cannot be cast to androidx.preference.Preference异常,确实是因为自定义Preference继承了旧框架的android.preference.DialogPreference,但项目里其他组件用的是AndroidX库——这俩属于完全不同的框架体系,自然没法互相转换。下面我一步步教你把代码迁移到AndroidX版本:
1. 替换导入包
把所有旧的android.preference相关导入,全部换成AndroidX的androidx.preference包。比如直接把import android.preference.DialogPreference;改成import androidx.preference.DialogPreference;,其他涉及旧Preference的导入也同理替换。
2. 修正构造方法
AndroidX的DialogPreference构造方法和旧版本有细微差别,建议使用标准的重载形式,这样兼容性更好:
public TimePickerPreference(Context context, AttributeSet attrs) { this(context, attrs, androidx.preference.R.attr.dialogPreferenceStyle); } public TimePickerPreference(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); setDialogLayoutResource(R.layout.timepickerpreferencelayout); setPositiveButtonText("ok"); setNegativeButtonText("cancel"); }
3. 修正时间计算逻辑(额外小修复)
你的getMinute方法原来的计算会返回毫秒数,不是分钟数,这会导致时间显示错误,我帮你修正了这个问题。
修改后的完整代码
import android.content.Context; import android.content.res.TypedArray; import android.os.Build; import android.util.AttributeSet; import android.view.View; import android.widget.TextView; import android.widget.TimePicker; import androidx.preference.DialogPreference; public class TimePickerPreference extends DialogPreference { private static final int DEFAULT_TIME = 0; private TimePicker mTimePicker; private int currentTime; public TimePickerPreference(Context context, AttributeSet attrs) { this(context, attrs, androidx.preference.R.attr.dialogPreferenceStyle); } public TimePickerPreference(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); setDialogLayoutResource(R.layout.timepickerpreferencelayout); setPositiveButtonText("ok"); setNegativeButtonText("cancel"); } private static int getTime(int hour, int minute){ return hour*60*60*1000 + minute*60*1000; } private static int getHour(int value){ return (int)(value / (60*60*1000)); } private static int getMinute(int value){ // 修正:把毫秒数转成分钟 return (int)((value % (60*60*1000)) / (60*1000)); } @Override protected View onCreateDialogView() { View view = super.onCreateDialogView(); mTimePicker = view.findViewById(R.id.timePicker); mTimePicker.setIs24HourView(true); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { mTimePicker.setHour(getHour(currentTime)); mTimePicker.setMinute(getMinute(currentTime)); } else { mTimePicker.setCurrentHour(getHour(currentTime)); mTimePicker.setCurrentMinute(getMinute(currentTime)); } mTimePicker.setOnTimeChangedListener((timePicker, hour, minute) -> currentTime = getTime(hour, minute)); TextView messageTextView = view.findViewById(R.id.messageTextView); if (getDialogMessage() == null || getDialogMessage().toString().trim().isEmpty()) { messageTextView.setVisibility(View.GONE); } else { messageTextView.setText(getDialogMessage()); } return view; } @Override protected Object onGetDefaultValue(TypedArray a, int index) { return a.getInt(index, DEFAULT_TIME); } @Override protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) { if(restorePersistedValue) { currentTime = getPersistedInt(defaultValue == null ? DEFAULT_TIME : (int) defaultValue); } else { currentTime = (int) defaultValue; if (shouldPersist()) { persistInt(currentTime); } } } @Override protected void onDialogClosed(boolean positiveResult) { if (positiveResult) { persistInt(currentTime); } } }
最后提醒:Preference布局的引用
在你的PreferenceScreen布局文件里引用这个自定义Preference时,要使用app:前缀的属性(AndroidX的标准写法),比如:
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto"> <com.example.todolist.TimePickerPreference app:key="alarm_time" app:title="设置闹钟时间" app:dialogMessage="选择每日提醒时间"/> </PreferenceScreen>
内容的提问来源于stack exchange,提问作者David Yao
相关产品推荐
相关产品推荐

