Dynamically creating Preference Screens on Android

On my latest project, I needed to add a ‘Filters’ screen for a REST request which would add some query params depending on what the user chose to filter.

The components on this screen would be also specified on an API response and thus they needed to be dynamically created, they couldn’t be loaded from an XML resource.

So I created a small parser for this ‘filter specification’ and tried to build a couple of Fragments with all those components using both native Views and a PreferenceScreen, this last one giving me quite the headache — yes, I know it’s not its intended behavior at all.

Yeah, that looks great…

As you can see, none of the Preferences were actually using the proper layouts. I’ll show you how to fix that.


Let’s get started

First of all, I started with a PreferenceFragmentCompat so I could reuse the PreferenceScreen if need be. To do that, you must import the Preference Compat Library into your build.gradle:

compile 'com.android.support:preference-v7:23.4.0'

You should probably change the version number to the latest one.

When you create the Fragment, it’s also needed to set a theme attribute on your styles.xml:

The preferenceTheme attribute is needed, otherwise the Fragment will fail to load. “@style/PreferenceThemeOverlay” is a Theme included in the Preference Compat Library and can be extended and customized with your own. Originally, it looks like this:

So, let’s get back to the PreferenceFragmentCompat:

This will be the base of the custom PreferenceFragmentCompat. Now, we need to add some Preferences, but as seen on the picture before, just adding them will cause them to load with no layout. The trick is to use a ContextThemeWrapper with will wrap the preferenceTheme we used before:

Now, we instance our Preferences using that ContextThemeWrapper and add it to the PreferenceScreen:

And the result:

Now, that’s definitely better

What about retrieving the values or clearing them?

Well, storing these temporary preferences along with all the other SharedPreferences on your app doesn’t exactly sound like a good idea, does it?

To fix this, you’d probably want to specify a temp SharedPreferences file which can be cleared or deleted later: