Android:应用程序更新时 PreferencesActivity onCreate 上的 ClassCastException(不在第一个 运行 中)

Android: ClassCastException on PreferencesActivity onCreate when app is updated (NOT in first run)

我即将启动我的应用程序更新,但遇到了问题。

其中一个首选项 class 已从 CheckBox 更改为 Switch,现在以前安装该应用程序的用户在尝试访问 PreferenceActivity 时遇到崩溃。

这是我的 StackTrace:

2021-12-03 19:42:51.824 18764-18764/? E/AndroidRuntime: FATAL EXCEPTION: main
    Process: xxx.xxx.xxx, PID: 18764
    java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Boolean
        at android.app.SharedPreferencesImpl.getBoolean(SharedPreferencesImpl.java:331)
        at androidx.preference.Preference.getPersistedBoolean(Preference.java:1955)
        at androidx.preference.TwoStatePreference.onSetInitialValue(TwoStatePreference.java:201)
        at androidx.preference.Preference.onSetInitialValue(Preference.java:1614)
        at androidx.preference.Preference.dispatchSetInitialValue(Preference.java:1587)
        at androidx.preference.Preference.onAttachedToHierarchy(Preference.java:1311)
        at androidx.preference.Preference.onAttachedToHierarchy(Preference.java:1326)
        at androidx.preference.PreferenceGroup.addPreference(PreferenceGroup.java:249)
        at androidx.preference.PreferenceGroup.addItemFromInflater(PreferenceGroup.java:170)
        at androidx.preference.PreferenceInflater.rInflate(PreferenceInflater.java:345)
        at androidx.preference.PreferenceInflater.rInflate(PreferenceInflater.java:346)
        at androidx.preference.PreferenceInflater.inflate(PreferenceInflater.java:157)
        at androidx.preference.PreferenceInflater.inflate(PreferenceInflater.java:109)
        at androidx.preference.PreferenceManager.inflateFromResource(PreferenceManager.java:216)
        at androidx.preference.PreferenceFragmentCompat.addPreferencesFromResource(PreferenceFragmentCompat.java:361)
        at xxx.xxx.xxx.ui.activities.settings.SettingsActivity$SettingsFragment.onCreatePreferences(SettingsActivity.java:164)
        at androidx.preference.PreferenceFragmentCompat.onCreate(PreferenceFragmentCompat.java:160)
        at xxx.xxx.xxx.ui.activities.settings.SettingsActivity$SettingsFragment.onCreate(SettingsActivity.java:149)
        at androidx.fragment.app.Fragment.performCreate(Fragment.java:2949)
        at androidx.fragment.app.FragmentStateManager.create(FragmentStateManager.java:475)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:278)
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2189)
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2100)
        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002)
        at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3138)
        at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:3072)
        at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:251)
        at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:502)
        at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:246)
        at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1440)
        at android.app.Activity.performStart(Activity.java:8109)
        at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3806)
        at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:235)
        at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:215)
        at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:187)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:105)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2386)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:213)
        at android.app.ActivityThread.main(ActivityThread.java:8178)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1101)

问题是,以前 CheckBox 值采用字符串格式,现在它们已迁移到布尔值,当尝试获取设置值时崩溃。

不幸的是,StackTrace 没有给我有用的信息,因为它在 onCreate 中崩溃,而不是在特定行中崩溃。

我尝试在启动时清除所有 SwitchPreference 值但无济于事:

//clear switch preferences
SharedPreferences prefs = TMPreferences.getPrefs();
prefs.edit().remove("SHUFFLE").apply();
prefs.edit().remove("NOTIFICATIONS_RANDOMNOTIFICATIONS").apply();
prefs.edit().remove("VIDEORECOMMENDATION").apply();
//set switch preferences
prefs.edit().putBoolean("SHUFFLE", false).apply();
prefs.edit().putBoolean("NOTIFICATIONS_RANDOMNOTIFICATIONS", false).apply();
prefs.edit().putBoolean("VIDEORECOMMENDATION", false).apply();

我知道一种解决方案是“强制”用户转到“应用程序”>“清除应用程序数据”,但不想结束这样做。

我期望的是一种重置旧的 CheckBoxes 值并用新的 SwitchPreferences 替换它们的方法,而不要求用户清除数据。

对于新用户,应用程序运行良好。

这是我的 Preferences.xml 文件:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto">

    <PreferenceCategory
        android:key="pref_category_test"
        android:title="@string/pref_category_test"
        app:iconSpaceReserved="false">
        <ListPreference
            android:key="pref_testtime"
            android:title="@string/pref_testtime"
            android:entries="@array/testtime_texts"
            android:entryValues="@array/testtime_values"
            android:defaultValue="-1"
            app:iconSpaceReserved="false" />

        <SwitchPreference
            android:key="pref_shuffle"
            android:title="@string/pref_shuffle"
            android:defaultValue="false"
            app:iconSpaceReserved="false" />
        
        <ListPreference
            android:key="pref_fontsize"
            android:title="@string/pref_fontsize"
            android:entries="@array/fontsize_texts"
            android:entryValues="@array/fontsize_values"
            android:defaultValue="100"
            app:iconSpaceReserved="false" />

    </PreferenceCategory>
    
    <PreferenceCategory
        android:key="pref_category_language"
        android:title="@string/pref_category_language"
        app:iconSpaceReserved="false">
        <ListPreference
            android:key="pref_languages"
            android:title="@string/pref_language"
            android:entries="@array/language_texts"
            android:entryValues="@array/language_values"
            app:iconSpaceReserved="false" />
    </PreferenceCategory>
    
    <PreferenceCategory
        android:key="pref_category_notification"
        android:title="@string/pref_category_notifications"
        app:iconSpaceReserved="false">
        <ListPreference
            android:key="pref_notifications_interval"
            android:title="@string/pref_taketest_reminder"
            android:entries="@array/notification_texts"
            android:entryValues="@array/notification_values"
            android:defaultValue="1"
            app:iconSpaceReserved="false" />

        <SwitchPreference
            android:key="pref_notifications_randomnotifications"
            android:title="@string/pref_randomnotifications"
            android:defaultValue="false"
            app:iconSpaceReserved="false" />

        <SwitchPreference
            android:key="pref_videorecommendation"
            android:title="@string/pref_videorecommendation_notification"
            android:defaultValue="true"
            app:iconSpaceReserved="false" />

        <SwitchPreference
            android:key="pref_checkfornewtests"
            android:title="@string/pref_checkfornewtests_notification"
            android:defaultValue="true"
            app:iconSpaceReserved="false" />
    </PreferenceCategory>
    
    <PreferenceCategory
        android:key="pref_category_aspect"
        android:title="@string/pref_category_aspect"
        app:iconSpaceReserved="false">
    </PreferenceCategory>
    
    <PreferenceCategory
        android:key="pref_category_animation"
        android:title="@string/pref_category_animations"
        app:iconSpaceReserved="false">

        <SwitchPreference
            android:key="pref_transitionanimation"
            android:title="@string/pref_transitionanimation"
            android:defaultValue="true"
            app:iconSpaceReserved="false" />
    </PreferenceCategory>
    
    <PreferenceCategory
        android:key="pref_category_sounds"
        android:title="@string/pref_category_sounds"
        app:iconSpaceReserved="false">

        <SwitchPreference
            android:key="pref_buttonsound"
            android:title="@string/pref_buttonsound"
            android:defaultValue="false"
            app:iconSpaceReserved="false" />

        <SwitchPreference
            android:key="pref_pageflipsound"
            android:title="@string/pref_pageflipsound"
            android:defaultValue="false"
            app:iconSpaceReserved="false" />

        <SwitchPreference
            android:key="pref_endtestsound"
            android:title="@string/pref_endtestsound"
            android:defaultValue="false"
            app:iconSpaceReserved="false" />

    </PreferenceCategory>
    
    <PreferenceCategory
        android:key="pref_category_users"
        android:title="@string/pref_category_users"
        app:iconSpaceReserved="false">
        <Preference
            android:key="pref_loggedinas"
            android:title="@string/activitypreferences_loggedinas"
            app:iconSpaceReserved="false">
        </Preference>
        <Preference
            android:key="pref_deletecurrentuser"
            android:title="@string/activitypreferences_deletecurrentuser"
            app:iconSpaceReserved="false">
        </Preference>
        <Preference
            android:key="pref_changemypassword"
            android:title="@string/activitypreferences_changemypassword"
            app:iconSpaceReserved="false">
        </Preference>
    </PreferenceCategory>

    <PreferenceCategory
        android:key="pref_category_troubleshooting"
        android:title="@string/pref_category_troubleshooting"
        app:iconSpaceReserved="false">
        <Preference
            android:key="pref_resyncalldata"
            android:title="@string/activitypreferences_resyncalldata"
            app:iconSpaceReserved="false">
        </Preference>
    </PreferenceCategory>

</PreferenceScreen>

创建时设置活动:

protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
}

最后,我能够解决它的唯一方法是重命名 Switch“有问题的”首选项键。

这不是最好的解决方案,因为之前安装我的应用程序到这个新版本的用户将有一些“不必要的”键“挂在”这里,但它有效,应用程序在更新时不会再崩溃尝试访问 PreferencesActivity。