2

I have Preferences activity in my app that has ListPreference so the user can choose language for the app.

The app displays the new language just after the user close the Preferences activity.

I want to create a listener to the ListPreference so the app will restart when the Listener is triggers (just after the user choose a language/choose item from the ListPreference).

How can I do that?

SettingsActivity:

public class SettingsActivity extends AppCompatPreferenceActivity {
/**
 * A preference value change listener that updates the preference's summary
 * to reflect its new value.
 */
private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
    @Override
    public boolean onPreferenceChange(Preference preference, Object value) {
        String stringValue = value.toString();

        if (preference instanceof ListPreference) {
            // For list preferences, look up the correct display value in
            // the preference's 'entries' list.
            ListPreference listPreference = (ListPreference) preference;
            int index = listPreference.findIndexOfValue(stringValue);

            // Set the summary to reflect the new value.
            preference.setSummary(
                    index >= 0
                            ? listPreference.getEntries()[index]
                            : null);

        } else {
            // For all other preferences, set the summary to the value's
            // simple string representation.
            preference.setSummary(stringValue);
        }
        return true;
    }
};


/**
 * Binds a preference's summary to its value. More specifically, when the
 * preference's value is changed, its summary (line of text below the
 * preference title) is updated to reflect the value. The summary is also
 * immediately updated upon calling this method. The exact display format is
 * dependent on the type of preference.
 *
 * @see #sBindPreferenceSummaryToValueListener
 */
private static void bindPreferenceSummaryToValue(Preference preference) {
    // Set the listener to watch for value changes.
    preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);

    // Trigger the listener immediately with the preference's
    // current value.
    sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
            PreferenceManager
                    .getDefaultSharedPreferences(preference.getContext())
                    .getString(preference.getKey(), ""));
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setupActionBar();
    setTitle(R.string.action_settings);
}

/**
 * Set up the {@link android.app.ActionBar}, if the API is available.
 */
private void setupActionBar() {
    ActionBar actionBar = getSupportActionBar();
    if (actionBar != null) {
        // Show the Up button in the action bar.
        actionBar.setDisplayHomeAsUpEnabled(true);
    }
}

@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
    int id = item.getItemId();
    if (id == android.R.id.home) {
        if (!super.onMenuItemSelected(featureId, item)) {
            NavUtils.navigateUpFromSameTask(this);
        }
        return true;
    }
    return super.onMenuItemSelected(featureId, item);
}

/**
 * This method stops fragment injection in malicious applications.
 * Make sure to deny any unknown fragments here.
 */
protected boolean isValidFragment(String fragmentName) {
    return PreferenceFragment.class.getName().equals(fragmentName)
            || GeneralPreferenceFragment.class.getName().equals(fragmentName);
}

/**
 * This fragment shows general preferences only. It is used when the
 * activity is showing a two-pane settings UI.
 */
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class GeneralPreferenceFragment extends PreferenceFragment {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.pref_general);
        setHasOptionsMenu(true);

        // Bind the summaries of EditText/List/Dialog/Ringtone preferences
        // to their values. When their values change, their summaries are
        // updated to reflect the new value, per the Android Design
        // guidelines.
        bindPreferenceSummaryToValue(findPreference("example_text"));
        bindPreferenceSummaryToValue(findPreference(getString(R.string.language_shared_pref_key)));
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == android.R.id.home) {
            Intent intent = new Intent(getActivity(), MainActivity.class);
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            getActivity().finish();
            startActivity(intent);
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

}

pref_general.xml:

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">

<ListPreference
    android:defaultValue="@string/language_code"
    android:entries="@array/pref_languages_list_titles"
    android:entryValues="@array/pref_languages_list_values"
    android:key="@string/language_shared_pref_key"
    android:negativeButtonText="@null"
    android:positiveButtonText="@null"
    android:title="@string/pref_title_language" />

</PreferenceScreen>

Thank you!!!

Itiel Maimon
  • 834
  • 2
  • 9
  • 26
  • Just start the mainActivity again and in it's `onCreate` method be sure to check what language is chosen from sharedPrefs and change the locale accordingly. – Vucko Jun 29 '16 at 20:46
  • Already did that. That's not what I asked. I just want to create Listener to the ListPreference – Itiel Maimon Jun 29 '16 at 20:51
  • Well what did you ask then? You do not know how to start the MainActivity and destroy all the others? Use `preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener)` – Vucko Jun 29 '16 at 20:51
  • 1
    It sounds like you already know how to implement a shared prefs change listener; what exactly is tripping you up? – gabe3vino Jun 29 '16 at 20:53
  • How to create a Listener to the ListPreference and when it's triggers the app will restart. – Itiel Maimon Jun 29 '16 at 20:54
  • I can't add the code to restart the app in the listener. – Itiel Maimon Jun 29 '16 at 20:55

2 Answers2

12

Here is some real quick sample code for a shared prefs chaneg listener I have set-up in one of my projects; it's located in the onCreate of a Service but obviously can detect changes to my shared prefs that originate from anywhere in my app.

private SharedPreferences.OnSharedPreferenceChangeListener listener;


//Loads Shared preferences
prefs = PreferenceManager.getDefaultSharedPreferences(this);

//Setup a shared preference listener for hpwAddress and restart transport
listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
            public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
           if (key.equals(/*key for shared pref you're listening for*/) {
               //Do stuff; restart activity in your case
            }
        };

prefs.registerOnSharedPreferenceChangeListener(listener);
gabe3vino
  • 313
  • 1
  • 3
  • 10
  • Should I put that in onCreate method? – Itiel Maimon Jun 29 '16 at 21:13
  • Glad it worked kind of for you. Yeah you typically want it in the onCreate of your main activity so that the listener is set-up before those values can be changed. How is the behavior different from what you'd like, I might be able to help? – gabe3vino Jun 30 '16 at 17:10
0

One possible solution is to keep everything together, and implement the OnSharedPreferenceChangeListener interface inside your own GeneralPreferenceFragment.

You can do that by declaring that GeneralPreferenceFragment both inherits from PreferenceFragment, and implements SharedPreferences.OnSharedPreferenceChangeListener interface. This means that you need to define override for onSharedPreferenceChanged in GeneralPreferenceFragment.

Because preferences can change only if the fragment in question is active, you can register your fragment as listener in onResume for a fragment (via registerOnSharedPreferenceChangeListener), and unregister it on onStop.

The following example code is in Kotlin, not in Java, but it should be fairly easy to translate it.

class SettingsActivity : AppCompatActivity() {
    // ...
    class SettingsFragment : PreferenceFragmentCompat(),
                             SharedPreferences.OnSharedPreferenceChangeListener 
    {
        // ...

        override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?,
                                               key: String?) {
            if (key == "<something>")
                // do something
        }

        override fun onResume() {
            super.onResume()
            preferenceScreen.sharedPreferences
                ?.registerOnSharedPreferenceChangeListener(this)
        }

        override fun onPause() {
            super.onPause()
            preferenceScreen.sharedPreferences
                ?.unregisterOnSharedPreferenceChangeListener(this)
        }
}

Jakub Narębski
  • 309,089
  • 65
  • 217
  • 230