0

I'm having an issue with my preference page crashing my app. On the first visit, it acts as expected. But as soon as I revisit the page and try to change a switch, the app crashes. Here's what the XML looks like for my preferences:

    xmlns:app="http://schemas.android.com/apk/res-auto">

    <PreferenceCategory
        android:gravity="left"
        android:title="@string/description_title"
        app:iconSpaceReserved="false">

        <SwitchPreference
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:key="@string/pallet_pref_key"
            android:title="@string/pallet_pref"
            app:iconSpaceReserved="false" />
        <SwitchPreference
            android:key="@string/nose_pref_key"
            android:title="@string/nose_pref"
            app:iconSpaceReserved="false" />
        <SwitchPreference
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:key="@string/finish_pref_key"
            android:title="@string/finish_pref"
            app:iconSpaceReserved="false" />
    </PreferenceCategory>

</PreferenceScreen>

The Java looks like this:

import android.os.Bundle;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceManager;
import androidx.preference.SwitchPreference;

public class SettingsActivity extends AppCompatActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.settings_activity);

        getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.settings, new SettingsFragment())
                .commit();
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.setDisplayHomeAsUpEnabled(true);
        }

    }

    public static class SettingsFragment extends PreferenceFragmentCompat {

        private SharedPreferences sharedPref;
        private boolean pNose;
        private boolean pPallet;
        private boolean pFinish;

        @Override
        public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
            setPreferencesFromResource(R.xml.root_preferences, rootKey);
            sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
            sharedPref.registerOnSharedPreferenceChangeListener(new SharedPreferences.OnSharedPreferenceChangeListener() {
                @Override
                public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
                    if(s.equals(getResources().getString(R.string.pallet_pref_key))) {
                        pPallet = sharedPreferences.getBoolean(s,false);
                        SwitchPreference pNose = findPreference(getResources().getString(R.string.nose_pref_key));
                        SwitchPreference pFinish = findPreference(getResources().getString(R.string.finish_pref_key));
                        if (pPallet) {
                            pNose.setChecked(false);
                            pFinish.setChecked(false);
                        }
                    }
                    else if(s.equals(getResources().getString(R.string.nose_pref_key))) {
                        pNose = sharedPreferences.getBoolean(s,false);
                        SwitchPreference pPallet = findPreference(getResources().getString(R.string.pallet_pref_key));
                        SwitchPreference pFinish = findPreference(getResources().getString(R.string.finish_pref_key));
                        if (pNose) {
                            pPallet.setChecked(false);
                            pFinish.setChecked(false);
                        }
                    }
                    else if(s.equals(getResources().getString(R.string.finish_pref_key))) {
                        pFinish = sharedPreferences.getBoolean(s,false);
                        SwitchPreference pPallet = findPreference(getResources().getString(R.string.pallet_pref_key));
                        SwitchPreference pNose = findPreference(getResources().getString(R.string.nose_pref_key));
                        if (pFinish) {
                            pNose.setChecked(false);
                            pPallet.setChecked(false);
                        }
                    }
                }
            });
        }
    }
}

So basically I'm just trying to make it so only one switch can be enabled at a time. I did some research and found a few threads on here that mentioned I should add this code:

@Override
protected void onResume() {
    super.onResume();
    // Set up a listener whenever a key changes
    getPreferenceScreen().getSharedPreferences()
            .registerOnSharedPreferenceChangeListener(this);
}

@Override
protected void onPause() {
    super.onPause();
    // Unregister the listener whenever a key changes
    getPreferenceScreen().getSharedPreferences()
            .unregisterOnSharedPreferenceChangeListener(this);
}

I'm thinking that's probably the reason for the crash, but when I add that code below the "OnSharedPreferenceChangeListener() {" statement onResume() and onPause() are greyed out unless I hoist it to the top in which case the this keyword throws an error. Does anyone see what I'm doing wrong?

Here's the error that I get on the crash: logCat error

  • 1
    Please [edit] your question to provide the complete [stack trace from the crash](https://stackoverflow.com/a/23353174). – Mike M. Dec 20 '19 at 00:44
  • Just added that. Thanks for the recommendation. – Blackhawks182 Dec 20 '19 at 00:48
  • What does getPreferenceScreen().getSharedPreferences() return? Is the object initialized correctly? And the OnResume snippet is of the Activity or the Fragment? – Arnab Saha Dec 20 '19 at 00:56
  • that's a snippet of code I found in a related question [that was asked here](https://stackoverflow.com/questions/3799038/onsharedpreferencechanged-not-fired-if-change-occurs-in-separate-activity) if I put that in my code it grays out onResume – Blackhawks182 Dec 20 '19 at 01:03
  • 1
    Please don't post screenshots of code, XML, or logcat output. Please post all text as text. That said, your problem is that you're not unregistering the listener. You've got the right idea with the `onResume()` and `onPause()` overrides, but those go inside your `SettingsFragment`, at the class level; i.e., not inside an other method. Also, `SettingsFragment` itself would have to `implements SharedPreferences.OnSharedPreferenceChangeListener` for you to be able to pass `this` in those calls. If that's what you want to do, then add that `implements` to the `SettingsFragment` declaration... – Mike M. Dec 20 '19 at 01:11
  • 1
    ...and move the `onSharedPreferenceChanged()` out to class level, too. Then get rid of the registering stuff inside `onCreatePreferences()`. – Mike M. Dec 20 '19 at 01:12
  • Sorry. It was uploaded as a photo in the resource that you shared so I did it that way. This worked! Thanks for the heads up. – Blackhawks182 Dec 20 '19 at 01:23
  • Oh, yeah, right. I never thought about that, even though I've linked that post a thousand times. Sorry to mislead you. Anyhoo, glad you got it working. Cheers! – Mike M. Dec 20 '19 at 01:25

0 Answers0