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

点击按钮修改值时TimePicker抛出java.lang.NullPointerException异常

Android 14(AP1A.240305.019.A1)Pixel 8 Pro上TimePicker点击±按钮崩溃问题

问题详情

  • 仅在**Pixel 8 Pro升级到Android 14 Build #AP1A.240305.019.A1(2024年3月5日安全更新)**时触发,旧版本无此异常
  • 无需编写任何业务代码,仅在布局中添加TimePicker控件,点击其±调整值按钮就会崩溃
  • 崩溃核心原因:TimePickerSpinnerDelegate.updateInputState()方法中尝试对null的EditText调用hasFocus()

崩溃栈:

FATAL EXCEPTION: main
Process: com.police.nycmoneymanagement, PID: 32232
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.widget.EditText.hasFocus()' on a null object reference
at android.widget.TimePickerSpinnerDelegate.updateInputState(TimePickerSpinnerDelegate.java:480)
at android.widget.TimePickerSpinnerDelegate.-$$Nest$mupdateInputState(Unknown Source:0)
at android.widget.TimePickerSpinnerDelegate$2.onValueChange(TimePickerSpinnerDelegate.java:119)
at android.widget.NumberPicker.notifyChange(NumberPicker.java:2080)
at android.widget.NumberPicker.setValueInternal(NumberPicker.java:1850)
at android.widget.NumberPicker.changeValueByOne(NumberPicker.java:1879)
at android.widget.NumberPicker.-$$Nest$mchangeValueByOne(Unknown Source:0)
at android.widget.NumberPicker$1.onClick(NumberPicker.java:723)
at android.view.View.performClick(View.java:7729)
at android.view.View.performClickInternal(View.java:7706)
at android.view.View.-$$Nest$mperformClickInternal(Unknown Source:0)
at android.view.View$PerformClick.run(View.java:30484)
at android.os.Handler.handleCallback(Handler.java:959)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loopOnce(Looper.java:232)
at android.os.Looper.loop(Looper.java:317)
at android.app.ActivityThread.main(ActivityThread.java:8501)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:878)

解决方案

1. 切换TimePicker为时钟模式(推荐)

这是最简单的规避方案,直接修改布局或代码切换TimePicker的显示模式,绕过Spinner模式的系统bug:

布局中设置:

<TimePicker
    android:id="@+id/timePicker"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:timePickerMode="clock" />

或代码中动态设置:

TimePicker timePicker = findViewById(R.id.timePicker);
timePicker.setTimePickerMode(TimePicker.MODE_CLOCK);

2. 反射修复Spinner模式(若必须使用该模式)

如果业务要求必须用Spinner模式,可通过反射包装系统的监听逻辑,避免空指针:

try {
    // 获取TimePicker的Delegate实例
    Field delegateField = TimePicker.class.getDeclaredField("mDelegate");
    delegateField.setAccessible(true);
    Object delegate = delegateField.get(timePicker);

    if (delegate instanceof TimePickerSpinnerDelegate) {
        // 获取原有的值变化监听
        Field listenerField = TimePickerSpinnerDelegate.class.getDeclaredField("mOnValueChangeListener");
        listenerField.setAccessible(true);
        NumberPicker.OnValueChangeListener originalListener = (NumberPicker.OnValueChangeListener) listenerField.get(delegate);

        // 包装监听,先检查EditText是否为空
        NumberPicker.OnValueChangeListener wrappedListener = (picker, oldVal, newVal) -> {
            try {
                Field pickerInputField = NumberPicker.class.getDeclaredField("mInputText");
                pickerInputField.setAccessible(true);
                EditText pickerEditText = (EditText) pickerInputField.get(picker);
                if (pickerEditText != null) {
                    originalListener.onValueChange(picker, oldVal, newVal);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        };

        // 替换原监听
        listenerField.set(delegate, wrappedListener);
    }
} catch (NoSuchFieldException | IllegalAccessException e) {
    e.printStackTrace();
}

注意:反射依赖系统内部类结构,后续系统更新可能失效,需做好兼容处理。

3. 等待系统补丁

此问题属于Android系统层面的bug,Google后续大概率会通过OTA更新修复,可告知受影响用户等待系统推送更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 11:46:04