As I was following an old tutorial (Créez des applications pour Android -> openclassroom) I got stuck on this deprecated method addPreferencesFromResource(int id)
from the PreferenceActivity class.
So my question is :
What is the new way of creating Preferences in Android ?
In Android apps, there are often settings pages that contain different options the user can tweak. The PreferenceFragment and PreferenceFragmentCompat contains a hierarchy of preference objects displayed on screen in a list. These preferences will automatically save to SharedPreferences as the user interacts with them.
PreferencesActivity is a way to easily create preference screens such as those in Android itself, just look under Settings . These can be used inside applications to easily save preferences to SharedPreferences and then easily access these from within your app. See this page for more information on PreferenceActivity.
In your XML you have to declare the root element as android:id="@android:id/widget_frame , and then declare TextView as android:title and android:summary . You can then declare other elements you want to appear in the layout.
I found this post (What to use instead of “addPreferencesFromResource” in a PreferenceActivity?) that help me understand that you have to go through a PreferenceFragment
in order to do it.
In the following explanation I use your.package.
just to show that you have to put the package name. Everybody has its own package so please replace it with your package.
lets begin :
Create your PreferenceFragment class
MyPreferenceFragment
public class MyPreferenceFragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.fragment_preference); } }
Then the associated xml resource
fragment_preference.xml (in the folder res/xml of your project)
<?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceCategory android:title="FOO"> <CheckBoxPreference android:key="checkBoxPref" android:title="check it out" android:summary="click this little box"/> </PreferenceCategory> </PreferenceScreen>
That's all for the Fragment
part.
Create the PreferenceActivity class
MyPreferenceActivity
public class MyPreferenceActivity extends PreferenceActivity { @Override public void onBuildHeaders(List<Header> target) { loadHeadersFromResource(R.xml.headers_preference, target); } @Override protected boolean isValidFragment(String fragmentName) { return MyPreferenceFragment.class.getName().equals(fragmentName); } }
Do not forget to override isValidFragment(String fragmentName)
method as you will get punched in the face by your application ! ;) More seriously I have no idea why you need to do this but it is needed. If someone has an explanation about this I'd gladly read it :)
Thanks to kirtan403 I now know why it is needed : it has to be set because of an (android framework fragment injection).
As you can see in the onBuildHeaders(List<Header> target)
we load another xml file that contain the headers of the preference. In short, headers are the left part of the preference and the fragment are the right part (for tablet). For a phone you will first have the headers and when you click on an item the corresponding fragment will be put on top of the headers list.
Read this article (Multi-pane development in Android with Fragments - Tutorial) the images explain themselves.
Then the associated xml resource
headers_preference.xml (in the folder res/xml of your project)
<?xml version="1.0" encoding="utf-8"?> <preference-headers xmlns:android="http://schemas.android.com/apk/res/android"> <header android:fragment="your.package.MyPreferenceFragment" android:title="Goto: Preference fragment" android:summary="An example of some preferences." /> </preference-headers>
As you may have noticed in the header section you have :
android:fragment="your.package.MyPreferenceFragment"
This will act as a Link to the fragment you want to show. On Tablet it will load on the right part and on the phone it will load on top of the current view.
Now what you should do is to add your Activity to the AndroidManifest.xml
file.
Inside the application
section add these lines :
<activity android:name="your.package.MyPreferenceActivity" android:label="Preferences"> </activity>
You will probably tell me :
"Oh darling you forgot to put android:launchMode="singleTask" in your actvity"
But DO NOT PUT THIS as you will never load your fragment on phone. This error was solved by a great man ! This is the link to his blog (Android header preferences on small screen/phone).
Finally you need to add the ability to show this Preference !! To do so you will need 3 things :
The Menu
menu.xml (in the folder res/menu of your project)
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/preferences" android:title="Preferences" /> </menu>
Loading this Menu in your Main activity (not the PreferenceActivity) under the method onCreateOptionsMenu(Menu menu)
@Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu, menu); return true; }
Starting the MyPreferenceActivity
Activity when you click on that button.
For that you will need to override the onOptionsItemSelected(MenuItem item)
method in your Main activity.
@Override public boolean onOptionsItemSelected(MenuItem item) { switch(item.getItemId()) { case R.id.preferences: { Intent intent = new Intent(); intent.setClassName(this, "your.package.MyPreferenceActivity"); startActivity(intent); return true; } } return super.onOptionsItemSelected(item); }
Et voila les amis !
I haven't tested this code. I took it and modified it from my own code so I may have not well copy pasted things. If you encounter errors tell me, I'll try to figure out the problem and fix this.
I hope this post will help some people out there :D
Cheers !
I liked the solution from this post: http://alvinalexander.com/android/android-tutorial-preferencescreen-preferenceactivity-preferencefragment
.. because it seems the most compact for someone that just needs something very basic up and running quickly. It has only one .java file and two small xml files.
Activity Config REMINDERS
After adding the 3 files to your project, Don't forget to
A) Add the Prefs Activity to Manifest file
B) Add some way to launch the Prefs Activity .. e.g., a Button or Menu item
Add the following files to your project. Use the order they are listed in to avoid compile errors.
Add /res/values/array.xml
<resources> <string-array name="listArray"> <item>Ace</item> <item>Club</item> </string-array> <string-array name="listValues"> <item>Ace</item> <item>Club</item> </string-array> </resources>
Add /res/xml/preferences.xml
<?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <EditTextPreference android:title="Your Name" android:key="username" android:summary="Please provide your username"></EditTextPreference> <CheckBoxPreference android:title="Application Updates" android:defaultValue="false" android:summary="This option if selected will allow the application to check for latest versions." android:key="applicationUpdates" /> <ListPreference android:title="Download Details" android:summary="Select the kind of data that you would like to download" android:key="downloadType" android:defaultValue="Ace" android:entries="@array/listArray" android:entryValues="@array/listValues" /> </PreferenceScreen>
Add the Activity code
public class AppPreferenceActivity extends PreferenceActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getFragmentManager().beginTransaction().replace(android.R.id.content, new MyPreferenceFragment()).commit(); checkValues(); } public static class MyPreferenceFragment extends PreferenceFragment { @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferences); } } private void checkValues() { SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); String strUserName = sharedPrefs.getString("username", "NA"); boolean bAppUpdates = sharedPrefs.getBoolean("applicationUpdates",false); String downloadType = sharedPrefs.getString("downloadType","1"); String msg = "Cur Values: "; msg += "\n userName = " + strUserName; msg += "\n bAppUpdates = " + bAppUpdates; msg += "\n downloadType = " + downloadType; Toaster.shortDebug(msg); } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With