I'm trying to implement PreferenceFragmentCompat
and SharedPreferences.OnSharedPreferenceChangeListener
.
My app consists of main activity and fragments. The home fragment has a list of URLs with a title, and I would like to add a setting to add a URL to this list. This is what I've tried so far:
Here's the SettingsFragment.java
:
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Preference preference = findPreference(key);
if (preference instanceof EditTextPreference) {
EditTextPreference editTextPreference = (EditTextPreference) preference;
String value = editTextPreference.getText();
new HomeFragment().addLink(value);
} else {
assert preference != null;
preference.setSummary(sharedPreferences.getString(key, ""));
}
}
And the HomeFragment.java
:
private ArrayList<LinkItem> urls = new ArrayList<>(Arrays.asList(
new LinkItem("LifeHacker RSS Feed", "https://lifehacker.com/rss"),
new LinkItem("Google News Feed", "https://news.google.com/news/rss");
private LinkItemAdapter itemAdapter;
private ListView listView;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_home, container, false);
listView = view.findViewById(R.id.postListView);
itemAdapter = new LinkItemAdapter(getActivity(), R.layout.link_item, urls);
listView.setAdapter(itemAdapter);
listView.setOnItemClickListener(onItemClickListener);
itemAdapter.notifyDataSetChanged();
return view;
}
void addLink(String title) {
urls.add(new LinkItem(title, "https://google.com"));
itemAdapter.notifyDataSetChanged();
}
private AdapterView.OnItemClickListener onItemClickListener = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
HomeFragmentDirections.ActionHomeFragmentToRssFragment action =
HomeFragmentDirections.actionHomeFragmentToRssFragment(urls.get(position).Link, urls.get(position).Title);
NavHostFragment.findNavController(HomeFragment.this).navigate(action);
}
};
If I try doing it like this, the itemAdapter will be null, crashing the app, so I am unsure of how to implement this. If I try recreating it in addLink like in the onCreate method of HomeFragment, the activity ends up being null. If I try passing the activity or the context from settings fragment, the same result occurs.
LinkItemAdapter
adapts the following object:
public class LinkItem {
public String Title;
public String Link;
}
My results so far have always been the same: crash as soon as I click "OK" on the edit text field after changing it, due to a null pointer. Could anyone help me out with this, please? I am new to android.
Stack trace:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.myfragmentapp, PID: 5185
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.example.myfragmentapp.adapters.LinkItemAdapter.notifyDataSetChanged()' on a null object reference
at com.example.myfragmentapp.screens.HomeFragment.addLink(HomeFragment.java:86)
at com.example.myfragmentapp.screens.SettingsFragment.onSharedPreferenceChanged(SettingsFragment.java:42)
at android.app.SharedPreferencesImpl$EditorImpl.notifyListeners(SharedPreferencesImpl.java:560)
at android.app.SharedPreferencesImpl$EditorImpl.apply(SharedPreferencesImpl.java:443)
at androidx.preference.Preference.tryCommit(Preference.java:1632)
at androidx.preference.Preference.persistString(Preference.java:1663)
at androidx.preference.EditTextPreference.setText(EditTextPreference.java:80)
at androidx.preference.EditTextPreferenceDialogFragmentCompat.onDialogClosed(EditTextPreferenceDialogFragmentCompat.java:99)
at androidx.preference.PreferenceDialogFragmentCompat.onDismiss(PreferenceDialogFragmentCompat.java:267)
at android.app.Dialog$ListenersHandler.handleMessage(Dialog.java:1377)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6709)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:769)