开发者

How to fill ListPreference dynamically when onPreferenceClick is triggered?

I have a preference activity that has a language as ListPreference which displays the available language list. I can fill the list when onCreate is called, but I want to fill the list when the user clicks on it.

this is the java code :

public class SettingsActivity extends PreferenceActivity implements OnPreferenceClickListener {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        try {
            addPreferencesFromResource(R.xml.settings);
        } catch (Exception e) {

        }

    }

    @Override
    public boolean onPreferenceClick(Preference preference) {

        if((preference instanceof ListPreference) && (preference.getKey().equals("language"))){
            ListPreference lp = (ListPreference)preference;
            CharSequence[] entries = { "English", "French" };
            CharSequence[] entryValues = {"1" , "2"};
            lp.setEntries(entries);
            lp.setDefaultValue("1");
            lp.setEntryValues(entryValues);
            return true;
        }
        return false;

    }
}

and this is the settings.xml (preference) :

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
  xmlns:android="http://schemas.android.com/apk/res/android">
    <PreferenceCategory android:title="General Settings">
        <CheckBoxPreference android:key="enabled"  android:titl开发者_如何学Ce="Application Status" android:summary="Enable or disable the application" />
         <ListPreference 
         android:key="language" 
         android:title="Language"
         android:dialogTitle="Application language" 
         android:summary="Select the Application language"
         />
    </PreferenceCategory>
</PreferenceScreen>

I searched but found no result! An exception occurs every time I click on that list.


You are getting the exception because your ListPreference object is not initialized - you either need to set entries and entryValues attributes in your XML or do it programatically in onCreate().

If if you need to change the items in the list dynamically after the initial ListPreference object has been initialized then you will need to attach the OnPreferenceClickListener directly to the ListPreference object. Use the key you have specified in the XML to get a handle to the preference.

Since the code to populate the entries and entryValues arrays will have to be run both in onCreate() and in onPreferenceClick, it makes sense to extract it to a separate method - setListPreferenceData() in order to avoid duplication.

public class SettingsActivity extends PreferenceActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        try {
            addPreferencesFromResource(R.xml.settings);
        } catch (Exception e) {

        }

        final ListPreference listPreference = (ListPreference) findPreference("language");

        // THIS IS REQUIRED IF YOU DON'T HAVE 'entries' and 'entryValues' in your XML
        setListPreferenceData(listPreference);

        listPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
            @Override
            public boolean onPreferenceClick(Preference preference) {

                setListPreferenceData(listPreference);
                return false;
            }
        });
    }

    protected static void setListPreferenceData(ListPreference lp) {
            CharSequence[] entries = { "English", "French" };
            CharSequence[] entryValues = {"1" , "2"};
            lp.setEntries(entries);
            lp.setDefaultValue("1");
            lp.setEntryValues(entryValues);
    }
}

Here is another example from google's DeskClock app:


Using PreferenceFragment & JAVA set key rather than PreferenceActivity & XML as shown in https://stackoverflow.com/a/13828912/1815624, which this answer is based on:

If what you want is to be able to change the items in the list dynamically after the initial ListPreference object has been initialized then you will need to attach the OnPreferenceClickListener directly to the ListPreference object. Use the key you have specified in the JAVA source (as CUSTOM_LIST) to get a handle to the preference.

Since the code to populate the entries and entryValues arrays will have to run both in onCreate() and in onPreferenceClick, it makes sense to extract it to a separate method - setListPreferenceData() in order to avoid duplication.

/**
 * This fragment shows data and sync preferences only. It is used when the
 * activity is showing a two-pane settings UI.
 */
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class myCustomPreferenceFragment extends PreferenceFragment {

    final private String CUSTOM_LIST= "custom_list";

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

        PreferenceCategory targetCategory = (PreferenceCategory) findPreference("CUSTOM_FRAG");

        final ListPreference lp = setListPreferenceData((ListPreference) findPreference(CUSTOM_LIST), getActivity());

        lp.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
            @Override
            public boolean onPreferenceClick(Preference preference) {

                setListPreferenceData(lp, getActivity());
                return false;
            }
        });
        setHasOptionsMenu(true);
        targetCategory.addPreference(lp);

        bindPreferenceSummaryToValue(targetCategory);
        bindPreferenceSummaryToValue(lp);
    }

    protected ListPreference setListPreferenceData(ListPreference lp, Activity mActivity) {
        CharSequence[] entries = { "One", "Two", "Three" };
        CharSequence[] entryValues = { "1", "2", "3" };
        if(lp == null)
            lp = new ListPreference(mActivity);
        lp.setEntries(entries);
        lp.setDefaultValue("1");
        lp.setEntryValues(entryValues);
        lp.setTitle("Number Of blahs");
        lp.setSummary(lp.getEntry());
        lp.setDialogTitle("Number of Blah objects");
        lp.setKey(CUSTOM_LIST);
        return lp;
    }

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

XML layout:

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

    </PreferenceCategory>
</PreferenceScreen>


I solved the problem my extending the ListPreference. It was very simple.

public class DListPref extends ListPreference
{
    public interface LoadingListener
    {
        void setData(ListPreference lp);
    }

    LoadingListener TheLL;

    public void setLoadingListener(LoadingListener l)
    {
        TheLL = l;
    }

    @Override
    protected void onPrepareDialogBuilder(AlertDialog.Builder builder)
    {
        if(TheLL!=null)
        {
            TheLL.setData(this);
        }
        super.onPrepareDialogBuilder(builder);
    }

    //Do not mind the rest of this class, as they are auto-generated boilerplate code.
    public DListPref(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
    {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    public DListPref(Context context, AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);
    }

    public DListPref(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }

    public DListPref(Context context)
    {
        super(context);
    }
}

And then I just changed the name to my class in the XML.

<my.company.DListPref
    android:defaultValue="-1"
    android:key="damn"
    android:title="vegetables"/>

And then I simply did this at the onCreate.

        DListPref lp = (DListPref) findPreference("damn");

        lp.setLoadingListener(new DListPref.LoadingListener()
        {
            @Override
            public void setData(ListPreference lp)
            {
                lp.setEntries(new String[]{"doge", "wow"});
                lp.setEntryValues(new String[] {"1", "2"});
                lp.setDefaultValue("1");
            }
        });

Worked right away. Actually, I never expected it would be done so easily.


This is what I had to do to make mine work

    public static class MyPreferenceFragment extends PreferenceFragment
{
    @Override
    public void onCreate(final Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.pref_general);
        PreferenceCategory targetCategory = (PreferenceCategory) findPreference("CUSTOM_FRAG");

        //final Preference pref;
        //pref = findPreference("example_list1");
        final ListPreference lp = setListPreferenceDataSocieties((ListPreference) findPreference("custom1"), getActivity());
        final ListPreference lp2 = setListPreferenceDataRoutes((ListPreference) findPreference("custom2"), getActivity());
        final ListPreference lp3 = setListPreferenceDataCoolers((ListPreference) findPreference("custom3"), getActivity());



        setHasOptionsMenu(true);
        targetCategory.addPreference(lp);
        targetCategory.addPreference(lp2);
        targetCategory.addPreference(lp3);

        bindPreferenceSummaryToValue(targetCategory);
        bindPreferenceSummaryToValue(lp);
        bindPreferenceSummaryToValue(lp2);
        bindPreferenceSummaryToValue(lp3);
    }

    protected ListPreference setListPreferenceDataSocieties(ListPreference lp, Activity mActivity) {
        CharSequence[] entries = { "One", "Two", "Three" };
        CharSequence[] entryValues = { "1", "2", "3" };
        if(lp == null)
            lp = new ListPreference(mActivity);
        lp.setEntries(entries);
        lp.setDefaultValue("1");
        lp.setEntryValues(entryValues);
        lp.setTitle("Origin Society");
        lp.setSummary(lp.getEntry());
        lp.setDialogTitle("Registered Societies");
        lp.setKey("society_list");
        return lp;
    }


    protected ListPreference setListPreferenceDataRoutes(ListPreference lp, Activity mActivity) {
        CharSequence[] entries = { "One", "Two", "Three" };
        CharSequence[] entryValues = { "1", "2", "3" };
        if(lp == null)
            lp = new ListPreference(mActivity);
        lp.setEntries(entries);
        lp.setDefaultValue("1");
        lp.setEntryValues(entryValues);
        lp.setTitle("Designated Route");
        lp.setSummary(lp.getEntry());
        lp.setDialogTitle("Available Routes");
        lp.setKey("route_list");
        return lp;
    }
    protected ListPreference setListPreferenceDataCoolers(ListPreference lp, Activity mActivity) {
        CharSequence[] entries = { "One", "Two", "Three" };
        CharSequence[] entryValues = { "1", "2", "3" };
        if(lp == null)
            lp = new ListPreference(mActivity);
        lp.setEntries(entries);
        lp.setDefaultValue("1");
        lp.setEntryValues(entryValues);
        lp.setTitle("Destination Cooler");
        lp.setSummary(lp.getEntry());
        lp.setDialogTitle("Available Coolers");
        lp.setKey("cooler_list");
        return lp;
    }

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

}


boolean first_run = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    MyPreferenceFragment frag =  new MyPreferenceFragment();
    getFragmentManager().beginTransaction().replace(android.R.id.content, frag).commit();

}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜