Was PreferenceFragment intentionally excluded from the compatibility package?
Solution 1
Discovering that PreferenceActivity contains deprecated methods (although these are used in the accompanying sample code)
The deprecated methods are deprecated as of Android 3.0. They are perfectly fine on all versions of Android, but the direction is to use PreferenceFragment
on Android 3.0 and higher.
Can anyone tell me whether this was intentional?
My guess is it's a question of engineering time, but that's just a guess.
If so, can I easily target a range of devices (i.e. < 3.0 and >=3.0) or will I have to jump through hoops?
I consider it to be done "easily". Have two separate PreferenceActivity
implementations, one using preference headers and PreferenceFragments
, the other using the original approach. Choose the right one at the point you need to (e.g., when the user clicks on the options menu item). Here is a sample project demonstrating this. Or, have a single PreferenceActivity
that handles both cases, as in this sample project.
If it wasn't intentionally excluded, can we expect a new release of the compatibility package?
You will find out when the rest of us find out, which is to say, if and when it ships.
Or is there another workaround that is safe to use?
See above.
Solution 2
The subtle implication of the answer from @CommonsWare is that - your app must choose between the compatibility API or the built-in fragment API (since SDK 11 or so). In fact that's what the "easily" recommendation has done. In other words, if you want to use PreferenceFragment your app needs to use the built-in fragment API and deal with the deprecated methods on PreferenceActivity. Conversely, if it's important that your app use the compat. API you will be faced with not having a PreferenceFragment class at all. Thus, targeting devices is not a problem, but the hoop-jumping happens when you have to choose one or the other API and thus submit your design to unforeseen workarounds. I need the compat. API so I'm going to create my own PreferenceFragment class and see how that works. In the worst case scenario I'll just create a normal (fragment) layout and bind the view components to the sharedprefs manually...ugh.
EDIT: After trying and looking at the code at http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/preference/PreferenceFragment.java?av=h -- creating my own PreferenceFragment isn't going to happen. It appears the liberal use of package-private in PreferenceManager instead of 'protected' is the main blocker. It really doesn't look like there's any security or really good motivation to have done that and it isn't great for unit-testing but oh well...less typing I guess...
EDIT v2: Actually it did happen and it worked. It was definitely a headache to make the code work with the Compatibility API JAR. I had to copy about 70% the com.android.preference package from the SDK to my app and then wrestle with typically mediocre-quality Java code in Android. I used v14 of the SDK. It would have been much easier for a Goog engineer to do what I did, contrary to what I've heard some lead Android engineers say about this topic.
BTW - did I say "targeting devices is not a problem"? It totally is...if you use com.android.preference you are not going to be able to swap out with the Compatibility API without major refactoring. Fun log!
Solution 3
Building upon CommonsWare's answer as well as Tenacious' observations, I have come up with a single descendant class solution capable of targeting all current Android API versions with minimal fuss and no code or resource duplication. Please see my answer to the related question over here: PreferenceActivity Android 4.0 and earlier
or on my blog: http://www.blackmoonit.com/2012/07/all_api_prefsactivity/
Tested on two tablets running 4.0.3 and 4.0.4 as well as a phone running 4.0.4 and 2.3.3 and also an emulator running 1.6.
Solution 4
See PreferenceFragment-Compat from Machinarius. It was easy to drop in with gradle and I forget that it's even there.
compile 'com.github.machinarius:preferencefragment:0.1.1'
Important Update: The latest revision of the v7 support library
now has a native PreferenceFragmentCompat.
Solution 5
On August 2015 Google released the new Preference Support Library v7.
Now you can use the PreferenceFragmentCompat with any Activity
or AppCompatActivity
public static class PrefsFragment extends PreferenceFragmentCompat {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.preferences);
}
}
You have to set preferenceTheme
in your theme:
<style name="AppTheme" parent="@style/Theme.AppCompat.Light">
...
<item name="preferenceTheme">@style/PreferenceThemeOverlay</item>
</style>
In this way you can customize the preferenceTheme
to style the layouts used for each preference type without affecting other parts of your Activity.
Related videos on Youtube
James
Updated on July 08, 2022Comments
-
James almost 2 years
I'm looking to write preferences that can be applied to both 3.0 and pre-3.0 devices. Discovering that
PreferenceActivity
contains deprecated methods (although these are used in the accompanying sample code), I looked atPreferenceFragement
and the compatibility package to solve my woes.It appears, though, that
PreferenceFragment
isn't in the compatibility package. Can anyone tell me whether this was intentional? If so, can I easily target a range of devices (i.e. < 3.0 and >=3.0) or will I have to jump through hoops? If it wasn't intentionally excluded, can we expect a new release of the compatibility package? Or is there another workaround that is safe to use?Cheers
James
-
ecv over 11 yearsThis is my approach to solving the problem: stackoverflow.com/questions/14076073/…
-
theblang over 9 yearsSomeone made a third party
PreferenceFragment
that you will forget is even there. See my answer. -
theblang over 9 yearsChris Banes addresses this in a comment on his blog. He said that the reason is,
"Because most of Preferences' implementation is hidden, therefore impossible to backport without lots of hackery."
-
theblang over 8 yearsSee my updated answer.
PreferenceFragmentCompat
was recently added to the support library.
-
-
James about 13 yearsCheers Mark. I'd seen that you'd made comments about this in a couple places (android google group and your blog) but wanted a definitive answer (as far as one can get given the circumstances).
-
CommonsWare about 13 years@James: Yeah, the rub will be in the preference XML definition, getting something that will work well as fragments and also concatenated together, since I'm not sure
<include>
works with preference XML. BTW, if you're a subscriber, the book update referencing this project was announced minutes ago. -
Tenacious about 12 yearsLet me be more direct. If all you care about is targeting Honeycomb and higher (which has how much market share?) then vote for the answer from @Commonsware! If you care about the majority of Android devices on the market today you should read through my response.
-
Karakuri almost 12 yearswould you be willing to share how you did this? I'm running into exactly the same problem, only my PreferenceActivity has to use Loaders and therefore I must use the compatibility library.
-
Justin Buser almost 12 yearsI'm sorry but I'm not really sure what point you're trying to make here. You don't answer anything at all, merely comment/guess/refer to irrelevant external links that have nothing to do with the problem. The question is whether or not the omission was intentional, without the compatibility version of PreferenceFragment there is no means of extending PreferenceActivity in the way you've described because if PreferenceFragment doesn't exist then neither do getSupportFragmentManager() or any of the other methods required to use fragments in the first place.
-
CommonsWare almost 12 years@JustinBuser: "The question is whether or not the omission was intentional" -- the only people who can answer that work for Google. You are welcome to get a job at Google to try to find out. "there is no means of extending PreferenceActivity in the way you've described" -- you are welcome to download the code that I linked to.
-
James over 11 years@JustinBuser For the record, Mark did answer my question. That's evident from me accepting his answer.
-
Richard Le Mesurier over 11 years@Tenacious I like your investigation - well done. However, I feel someone should set the record straight on your first comment there - Commonsware's code will work on pre & post HC devices - try it first before making comments like that. The thing you need to realise is the late binding used at runtime to support previous devices. The version check at runtime takes care of supporting both families of OS - this is a common Android pattern (not one I like - but one that is important for Android developers to learn & become familiar with)... So to future readers - don't dismiss either approach.
-
Someone Somewhere over 11 yearsI downloaded the latest "Support" package and still no PreferenceFragment ! #disappointed
-
neworld over 10 years@RichardLeMesurier but Commonsware's method is not proper if you need preferences inside DrawerLayout
-
android developer over 8 yearsI think you miss a function : onCreatePreferences
-
Grzegorz D. about 8 yearsThis saved my day! I wonder why isn't this visible in Android Studio's Project Structure...?? BTW you have a typo in your code. Should be "extends PreferenceFragmentCompat"