19

I'm a learning how to develop in Android and want to make a setting activity,

My setting activity

public class Main extends Activity  {


    protected SettingsFragment settingsFragment;


    @SuppressLint("NewApi")
    @TargetApi(11)
    public class SettingsFragment extends PreferenceFragment implements
            SharedPreferences.OnSharedPreferenceChangeListener {


        @Override
        public void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.preferences);
            setSummaries();


        }


        @Override
        public void onResume() {
            final SharedPreferences sh = getPreferenceManager().getSharedPreferences() ;
            super.onResume();
            sh.registerOnSharedPreferenceChangeListener(this);

        }

        @Override
        public void onPause() {
            final SharedPreferences sh = getPreferenceManager().getSharedPreferences() ;
            super.onPause();
            sh.unregisterOnSharedPreferenceChangeListener(this);
        }

        @SuppressLint("NewApi")
        public void setSummaries(){

           final SharedPreferences sh = getPreferenceManager().getSharedPreferences() ;


            //Pref1
            Preference stylePref = findPreference("editTextPref");
            stylePref.setSummary(sh.getString("editTextPref", ""));

            //here the other preferences..
        }


        @Override
        public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
            if (key.equals("editTextPref")) {
                Preference pref = settingsFragment.findPreference(key);
                // Set summary to be the user-description for the selected value
                pref.setSummary(sharedPreferences.getString(key, ""));

            }
            //here the others preferences
        }
    }//End fragment

    @SuppressLint("NewApi")
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        settingsFragment = new SettingsFragment();
        getFragmentManager().beginTransaction()
                .replace(android.R.id.content, settingsFragment)
                .commit();


    }


}

and my res/preferences.xml file

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


        <EditTextPreference
            android:key="editTextPref"
            android:title="Numero de telephone"
            android:summary="This allows you to enter a string"
            android:defaultValue="*"/>

    </PreferenceCategory>

</PreferenceScreen>

So now i have the activity for the setting activity. But i want to display the value of the EditTextPref in android:summary. I have found many topics but all the functions was deprecated.

EDIT : thanks to @Ace_McIntosh , I edited my code for people who want it, it's working now.

serv-inc
  • 35,772
  • 9
  • 166
  • 188
user3130417
  • 223
  • 1
  • 3
  • 9

9 Answers9

21

If you are using AndroidX Preference library you can use the property app:useSimpleSummaryProvider. For example:

<EditTextPreference
        app:key="edittext"
        app:title="@string/title_edittext_preference"
        app:useSimpleSummaryProvider="true"
        app:dialogTitle="@string/dialog_title_edittext_preference"/>

You can read a fully working example here.

RobertoAllende
  • 8,744
  • 4
  • 30
  • 49
  • 2
    This should be accepted as an answer as well. Also at runtime: `preference.summaryProvider = EditTextPreference.SimpleSummaryProvider.getInstance() //kotlin` – heshuimu Apr 23 '20 at 01:57
9

Just override getSummary of EditTextPreference, then you will get a EditTextPreference with its value displayed as summary.

public class EditSummaryPreference extends EditTextPreference {
    ...// omit constructor

    @Override
    public CharSequence getSummary() {
        return getText();
    }
}
Shaw
  • 1,445
  • 16
  • 21
  • This is actually the most easy answer as it does not require changing any code in the fragment or activity or any code related to how the settings are handled or created. – Martin Oct 20 '18 at 11:16
  • 2
    But if the user changes the value the summary doesn't get updated, does it? – tobltobs Nov 21 '18 at 14:10
5

Just use the setSummary method on the desired Preference object. Call it upon resuming your settings fragment for each entry that you wish to update (i.e., all the EditTextPreference entries in your case) and register an OnSharedPreferenceChangeListener on the concrete SharedPreferences object (so that you can update the summary in case it is changed) – and pass it the desired EditTextPreference's value (which you can obtain via its getText() method).

Implement it in your MyPreferenceFragment like this (I don't guarantee that it will work right of the bat, it serves the purpose to just give you an idea):

public class MyPreferenceFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
    SharedPreferences sharedPreferences;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // load the preferences from your XML resource (which I assume you already do anyway)
        addPreferencesFromResource(R.xml.preferences);
    }

    @Override
    public void onResume() {
        super.onResume();

        sharedPreferences = getPreferenceManager().getSharedPreferences();

        // we want to watch the preference values' changes
        sharedPreferences.registerOnSharedPreferenceChangeListener(this);

        Map<String, ?> preferencesMap = sharedPreferences.getAll();
        // iterate through the preference entries and update their summary if they are an instance of EditTextPreference
        for (Map.Entry<String, ?> preferenceEntry : preferencesMap.entrySet()) {
            if (preferenceEntry instanceof EditTextPreference) {
                updateSummary((EditTextPreference) preferenceEntry);
            }
        }
    }

    @Override
    public void onPause() {
        sharedPreferences.unregisterOnSharedPreferenceChangeListener(this);
        super.onPause();
    }

    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
                                          String key) {
        Map<String, ?> preferencesMap = sharedPreferences.getAll();

        // get the preference that has been changed
        Object changedPreference = preferencesMap.get(key);
        // and if it's an instance of EditTextPreference class, update its summary
        if (preferencesMap.get(key) instanceof EditTextPreference) {
            updateSummary((EditTextPreference) changedPreference);
        }
    }

    private void updateSummary(EditTextPreference preference) {
        // set the EditTextPreference's summary value to its current text
        preference.setSummary(preference.getText());
    }
}
Ace_McIntosh
  • 122
  • 2
  • 2
  • 12
  • 3
    the problem is that addPreferencesFromResource is deprecated. – user3130417 Dec 15 '15 at 14:04
  • 3
    It is deprecated only in `PreferenceActivity` class, you have to call it in the `PreferenceFragment` class (where it's not deprecated, as you may see [in the documentation](http://developer.android.com/reference/android/preference/PreferenceFragment.html#addPreferencesFromResource%28int%29)). Be sure to utilize the fragment (you haven't posted the code of it, I only see that you create a new instance of `MyPreferenceFragment` in your activity class). Also note that the parent activity of a `PreferenceFragment` doesn't have to extend `PreferenceActivity`, it can be just an ordinary activity. – Ace_McIntosh Dec 15 '15 at 14:38
  • 1
    Done , just another question , now i have the value in the summary but when i modify it, i have to close and re open the app to see the change, i googled and i found that i have to add `setPreferenceScreen(null); addPreferencesFromResource(R.xml.preferences);` , but i don't find where i have to add it. – user3130417 Dec 15 '15 at 14:52
  • 4
    You need to register a listener for preference changes via `registerOnSharedPreferenceChangeListener` method of your `SharedPreferences` object and handle the update in the listener. There is an example how to do this in the code I posted you, the said listener is the class `MyPreferenceFragment` itself (it has to implement the appropriate interface) and as you can see it contains the `onSharedPreferenceChanged` callback where you should update the summary of the preference that's being changed. If you do this, the summary will be updated every time when the value of a preference changes. – Ace_McIntosh Dec 15 '15 at 15:43
  • Good morning, i updated the code above, can you explain me if i can register the listener registerOnSharedPreferenceChangeListener in the `setSummaries()` method, and how? – user3130417 Dec 16 '15 at 08:26
  • 3
    You should put that code in the `onResume()` lifecycle method, because you need it called every time the fragment comes into foreground. I recommend that you introduce your `sh` variable as a class field and in your `onResume()`, you call this: `sh.registerOnSharedPreferenceChangeListener(Main.this)`. And also don't forget to unregister the callback in the `onPause()` method, with `sh.unregisterOnSharedPreferenceChangeListener(Main.this)` (if you don't do this, you may get a null pointer exception when abandoning and returning to the settings fragment and invoking the listener). – Ace_McIntosh Dec 16 '15 at 10:49
  • 3
    Yes, and make your `SettingsFragment` class instantiable, not static, otherwise you wouldn't be able to access the parent object. To make things more convenient, I would however recommend that you keep the parent activity class clean and make the fragment implement the `SharedPreferences.OnSharedPreferenceChangeListener` instead – in that way, you would be able to reuse your `SharedPreferences` class field (after having introduced it, provided that you will). – Ace_McIntosh Dec 16 '15 at 10:58
  • 1
    Thank you very much, it's working now. i will edit my code for people who has the same problem. – user3130417 Dec 16 '15 at 12:51
  • 1
    Glad you have got it working, just a note how I meant to "_introduce the `sh` variable as a class field_" – the same way as you see the `sharedPreferences` variable in the code I posted, then it's sufficient to assign the value only once (see the `onResume` method in my example, specifically the `sharedPreferences = getPreferenceManager().getSharedPreferences()`, where the variable is assigned the value and reused throughout the class [I just noticed that it was not actually reused in the onPause method, so I edited it]). It won't affect the functionality, but it's a more efficient code. – Ace_McIntosh Dec 16 '15 at 13:06
5

(In Kotlin) I would prefer to do something a bit more simple and just create a class which extends the EditTextPreference:

import android.content.Context
import android.support.v7.preference.EditTextPreference
import android.util.AttributeSet

/**
 * This class was created by Anthony M Cannon on 17/04/2018.
 */
class SummarisedEditTextPreference @JvmOverloads constructor(context: Context,
    attrs: AttributeSet? = null) : EditTextPreference(context, attrs) {

    private var mOnChangeListener: OnPreferenceChangeListener? = null

    init {
        super.setOnPreferenceChangeListener { preference, newValue ->
            summary = newValue as String
            mOnChangeListener?.onPreferenceChange(preference, newValue) ?: true
        }
    }

    /**
    * Called when this Preference has been attached to a Preference hierarchy.
    * Make sure to call the super implementation.
    *
    * @param preferenceManager The PreferenceManager of the hierarchy.
    */
    override fun onAttachedToHierarchy(preferenceManager: PreferenceManager) {
        super.onAttachedToHierarchy(preferenceManager)
        summary = sharedPreferences.getString(key, null)
    }


    /**
     * Sets the callback to be invoked when this Preference is changed by the
     * user (but before the internal state has been updated).
     *
     * @param onPreferenceChangeListener The callback to be invoked.
     */
    override fun setOnPreferenceChangeListener(
        onPreferenceChangeListener: OnPreferenceChangeListener) {
        mOnChangeListener = onPreferenceChangeListener
    }
}

You can then use this like so:

<<your package name>.SummarisedEditTextPreference/>

Anthony Cannon
  • 1,245
  • 9
  • 20
  • 1
    '@JvmOverloads' for the constructor doesn't work in this case, the style of 'EditTextPreferences' will not be applied as you do not call the 'super' constructor this way. Try 'constructor(context: Context) : super(context) constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)' instead. – tobltobs Nov 21 '18 at 14:22
5

In androidx library, EditTextPreference has app:useSimpleSummaryProvider attribute. Using the attribute you won't need to extend any class or listen any changes on SharedPreferences. You can check the sample code at https://github.com/googlesamples/android-preferences/blob/master/app/src/main/res/xml/dialogs.xml

Eke Koseoglu
  • 59
  • 1
  • 1
  • 1
    Please don't post links to solutions. Use them to backup your solution only – Urosh T. Jan 06 '19 at 11:02
  • 1
    Amazing! no need for any change in code. The actual xml is `app:useSimpleSummaryProvider="true"` and it was added in [preference:1.1.0-alpha01](https://developer.android.com/jetpack/androidx/releases/preference#1.1.0-alpha01) – ronginat Jul 04 '19 at 16:48
3

There's some bugs in the example posted above so I thought I post a working solution (supports ListPreference and MultiSelectListPreference as well)

public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {

private SharedPreferences sharedPreferences;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    addPreferencesFromResource(R.xml.settings);
}

@Override
public void onResume() {
    super.onResume();

    sharedPreferences = getPreferenceManager().getSharedPreferences();
    sharedPreferences.registerOnSharedPreferenceChangeListener(this);

    PreferenceScreen preferenceScreen = getPreferenceScreen();
    for(int i = 0; i < preferenceScreen.getPreferenceCount(); i++) {
        setSummary(getPreferenceScreen().getPreference(i));
    }
}

@Override
public void onPause() {
    sharedPreferences.unregisterOnSharedPreferenceChangeListener(this);
    super.onPause();
}

@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
    Preference pref = getPreferenceScreen().findPreference(key);
    setSummary(pref);
}

private void setSummary(Preference pref) {
    if (pref instanceof EditTextPreference) {
        updateSummary((EditTextPreference) pref);
    } else if (pref instanceof ListPreference) {
        updateSummary((ListPreference) pref);
    } else if (pref instanceof MultiSelectListPreference) {
        updateSummary((MultiSelectListPreference) pref);
    }
}

private void updateSummary(MultiSelectListPreference pref) {
    pref.setSummary(Arrays.toString(pref.getValues().toArray()));
}

private void updateSummary(ListPreference pref) {
    pref.setSummary(pref.getValue());
}

private void updateSummary(EditTextPreference preference) {
    preference.setSummary(preference.getText());
}
}
1

Answer of @serv-inc worked for me. Somehow other answers worked only when the value changes.

But before it worked, I had to make a change as below:

@Override
public CharSequence getSummary() {
    return getText();
}

It shows the value when it is initially displayed, when value changes, as well as after resume.

Arundale Ramanathan
  • 1,781
  • 1
  • 18
  • 25
  • You had to change the getSummary() because @serv-inc answer had the android:summary="Actual value: %s" field set to be used for a String format. – Marshall Asch May 31 '17 at 15:39
1

Building uppon Brett Cherringtons answer, the implementation in Kotlin. There was a bug, namely that PreferenceCategories were not supported, which is fixed with an additional recursive loop in setSummary

class SettingsFragment : PreferenceFragment(), SharedPreferences.OnSharedPreferenceChangeListener {

    private lateinit var sharedPreferences: SharedPreferences

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        addPreferencesFromResource(R.xml.preferences)
    }

    override fun onResume() {
        super.onResume()

        sharedPreferences = preferenceManager.sharedPreferences
        sharedPreferences.registerOnSharedPreferenceChangeListener(this)

        val preferenceScreen = preferenceScreen
        for (i in 0 until preferenceScreen.preferenceCount) {
            setSummary(getPreferenceScreen().getPreference(i))
        }
    }

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

    override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
        val pref = preferenceScreen.findPreference(key)
        pref?.let { setSummary(it) }
    }

    private fun setSummary(pref: Preference) {
        if (pref is EditTextPreference) {
            updateSummary(pref)
        } else if (pref is ListPreference) {
            updateSummary(pref)
        } else if (pref is MultiSelectListPreference) {
            updateSummary(pref)
        } else if (pref is PreferenceCategory){
            // needs to loop through child preferences
            for (i in 0 until pref.preferenceCount) {
                setSummary(pref.getPreference(i))
            }
        }
    }

    private fun updateSummary(pref: MultiSelectListPreference) {
        pref.setSummary(Arrays.toString(pref.values.toTypedArray()))
    }

    private fun updateSummary(pref: ListPreference) {
        pref.summary = pref.value
    }

    private fun updateSummary(preference: EditTextPreference) {
        preference.summary = preference.text
    }
}
CitrusO2
  • 846
  • 10
  • 17
0

In addition to @Eke Koseoglu's answer.

If you use AndroidX preference library, you can set summaryProvider from Kotlin code below.

val editTextPreference = EditTextPreference(context)
editTextPreference.summaryProvider = EditTextPreference.SimpleSummaryProvider.getInstance()

According to documentation of EditTextPreference.SimpleSummaryProvider;

If no value has been set, the summary displayed will be 'Not set', otherwise the summary displayed will be the value set for this preference.

Burak Kal
  • 1
  • 1