动态添加 PreferenceCategory 到 PreferenceScreen 时出错

Getting an error when dynamically adding PreferenceCategory to PreferenceScreen

我目前正计划在我的应用程序中实施动态通知设置。如果当前设备是 运行 Android Oreo,显示通知通道设置。如果不是 Android Oreo,则显示另一个设置 (PreferenceCategory)

这是我的代码片段,用于在设备版本不是 Oreo 时显示:

for (MyNotificationChannel notificationChannel : notificationChannels) {
    System.out.println("Notification channel created at index " + notificationChannel.getIndex());
    PreferenceCategory preferenceCategory = new PreferenceCategory(preferenceScreen.getContext());
    preferenceCategory.setTitle(notificationChannel.getNotificationTitle());
    preferenceCategory.setSummary(notificationChannel.getNotificationDesc());
    SwitchPreference enableNotificationPreference = new SwitchPreference(preferenceScreen.getContext());
    enableNotificationPreference.setDefaultValue(true);
    enableNotificationPreference.setTitle("Enable notification channel");
    enableNotificationPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            System.out.println("Preference change: " + newValue);
            return true;
        }
    });
    preferenceCategory.addPreference(enableNotificationPreference);
    SwitchPreference enableVibratePreference = new SwitchPreference(preferenceScreen.getContext());
    enableVibratePreference.setTitle("Vibrate");
    enableVibratePreference.setSummary("Whether to vibrate when there are notifications available");
    enableVibratePreference.setDefaultValue(true);
    enableVibratePreference.setIcon(R.drawable.ic_vibrate_white_24dp);
    enableVibratePreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            System.out.println("Preference change: " + newValue);
            return true;
        }
    });
    RingtonePreference notificationRingtonePreference = new RingtonePreference(preferenceScreen.getContext());
    notificationRingtonePreference.setIcon(R.drawable.ic_music_white_24dp);
    notificationRingtonePreference.setTitle("Set ringtone");
    bindPreferenceSummaryToValue(notificationRingtonePreference);
    preferenceCategory.addPreference(notificationRingtonePreference);
    preferenceScreen.addPreference(preferenceCategory);
}

(顺便说一下,MyNotificationChannel 只是一个 class,作为我的通知设置的界面,可以更轻松地从 strings.xml 获取内容)

但是,当我尝试导航到通知片段时遇到此错误:

java.lang.NullPointerException: Attempt to invoke virtual method 'long android.preference.PreferenceManager.getNextId()' on a null object reference
  at android.preference.Preference.onAttachedToHierarchy(Preference.java:1326)
  at android.preference.PreferenceGroup.addPreference(PreferenceGroup.java:163)
  at com.edricchan.studybuddy.SettingsActivity$NotificationPreferenceFragment.onCreate(SettingsActivity.java:345)
  at android.app.Fragment.performCreate(Fragment.java:2489)
  at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1237)
  at android.app.FragmentManagerImpl.addAddedFragments(FragmentManager.java:2407)
  at android.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2186)
  at android.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2142)
  at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2043)
  at android.app.FragmentManagerImpl.run(FragmentManager.java:719)
  at android.os.Handler.handleCallback(Handler.java:790)
  at android.os.Handler.dispatchMessage(Handler.java:99)
  at android.os.Looper.loop(Looper.java:164)
  at android.app.ActivityThread.main(ActivityThread.java:6494)
  at java.lang.reflect.Method.invoke(Native Method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:440)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

编辑:这是我的首选项文件:

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- This preference screen will be filled in via code -->
</PreferenceScreen>

编辑#2:当我恢复到我原来的实现(对于 Android 奥利奥)时,它起作用了:

PreferenceCategory notificationPrefCategory = new PreferenceCategory(preferenceScreen.getContext());
notificationPrefCategory.setTitle("Notification Channels");
preferenceScreen.addPreference(notificationPrefCategory);
Preference allNotificationsPreference = new Preference(preferenceScreen.getContext());
allNotificationsPreference.setTitle(R.string.notification_channel_all_channels_title);
allNotificationsPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
    @Override
    public boolean onPreferenceClick(Preference preference) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
            intent.putExtra(Settings.EXTRA_APP_PACKAGE, getActivity().getPackageName());
            startActivity(intent);
        }
        return false;
    }
});
notificationPrefCategory.addPreference(allNotificationsPreference);
for (MyNotificationChannel notificationChannel : notificationChannels) {
    Preference notificationPreference = new Preference(preferenceScreen.getContext());
    notificationPreference.setTitle(notificationChannel.getNotificationTitle());
    notificationPreference.setSummary(notificationChannel.getNotificationDesc());
    notificationPreference.setKey(notificationChannelIds[notificationChannel.getIndex()]);
    notificationPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
        @Override
        public boolean onPreferenceClick(Preference preference) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
                intent.putExtra(Settings.EXTRA_APP_PACKAGE, getActivity().getPackageName());
                intent.putExtra(Settings.EXTRA_CHANNEL_ID, preference.getKey());
                startActivity(intent);
            }
            return false;
        }
    });
    notificationPrefCategory.addPreference(notificationPreference);
}

我通过将向首选项屏幕添加首选项类别的行上移到定义所有其他首选项之前解决了这个问题:

// This line
preferenceScreen.addPreference(preferenceCategory);

(P.S。我在定义 PreferenceCategory)

后将其移动到