Android Tutorial PreferenceActivity tutorial

This tutorial explains how to use the new PreferenceActivity library. This library allows you to create the "standard" settings screen.

The settings screen is hosted in its own activity. As this is an external activity its declaration should be manually added to the manifest file.
I will take this opportunity to give some tips about manual modification of the manifest file which is sometimes required.

Editing AndroidManifest.xml (general overview)
As of Basic4android v1.8 it is no longer required to manually maintain the manifest file. Instead the manifest editor allows you to add extra elements as needed.
See this link for more information: http://www.b4x.com/forum/showthread.php?p=78136
For PreferenceActivity you should add the following code to the manifest editor:
B4X:
AddApplicationText(<activity android:name="anywheresoftware.b4a.objects.preferenceactivity"/>)
Back to PreferenceActivity

preference_1.png


* This image was taken on a Samsung Galaxy Tab device. On other devices the screen will look a bit different based on their default style.

PreferenceActivity library includes two main objects: PreferenceScreen and PreferenceManager.
PreferenceScreen is responsible for building the settings UI. PreferenceManager allows you to read the settings and also modify them by code.
Both these objects should usually be declared in Sub Process_Globals.
The settings are saved in a file in the internal files folder. File handling is done automatically. Note that when you reinstall an application (without uninstalling it) the files are kept so the settings will also be kept.

Each preference entry is stored as a key/value pair. The key is a string (case sensitive) and the value can be either a string or a boolean value.
Each entry must have a unique key.

Building the UI
In order to build the UI we start with a PreferenceScreen object and add entries to this object directly or to PreferenceCategory which can hold other entries.
In the above screenshot you can see a PreferenceScreen with two categories holding other entries.
Note that a PreferenceScreen can also hold secondary PreferenceScreens. In this case when the user presses on the secondary entry a new screen will appear with its entries.
There are three types of preference entries:
- Checkbox
- EditText - Opens an input dialog when the user presses on it.
- List - Open a list dialog when the user presses on it, allowing the user to select a single item.
The code that creates the above UI is:
B4X:
Sub CreatePreferenceScreen
    screen.Initialize("Settings", "")
    'create two categories
    Dim cat1, cat2 As PreferenceCategory
    cat1.Initialize("Category 1")
    cat1.AddCheckBox("check1", "Checkbox1", "This is Checkbox1", True)
    cat1.AddCheckBox("check2", "Checkbox2", "This is Checkbox2", False)
    cat1.AddEditText("edit1", "EditText1", "This is EditText1", "Hello!")
 
    cat2.Initialize("Category 2")
    cat2.AddList("list1", "List1", "This is List1", "Black", _
        Array As String("Black", "Red", "Green", "Blue"))
     
    'add the categories to the main screen
    screen.AddPreferenceCategory(cat1)
    screen.AddPreferenceCategory(cat2)
End Sub
The first string in the Add methods is the entry key followed by the title, summary and default value.
The default value is used if the key does not yet exist.

To show the preferences we use this code:
B4X:
Sub btn_Click
    StartActivity(screen.CreateIntent)
End Sub
Reading the settings
Reading the settings is done with PreferenceManager.
To retrieve the value of a specific key you should use Manager.GetString or Manager.GetBoolean with this key.
You can get a Map with all the stored keys and values by calling Manager.GetAll
If you want to only handle updated settings then you can call Manager.GetUpdatedKeys. This will return a List with the keys that were updated since the last call to this method.
Usually you will want to handle settings updated in Activity_Resume. Activity_Resume will be called right after Activity_Create when you start your program and also when the user closes the preferences screen.
Whether you want to handle all keys or just the updated keys depends on your application.

Tip:
The default values set in the PreferenceScreen.Add calls have no effect till the user actually sees the screen. It is recommended to explicitly set the default values if they do not already exist.
A simple way to do it is with code similar to:
B4X:
Sub Activity_Create(FirstTime As Boolean)
    If FirstTime Then
        CreatePreferenceScreen
        If manager.GetAll.Size = 0 Then SetDefaults
    End If
End Sub

Sub SetDefaults
    'defaults are only set on the first run.
    manager.SetBoolean("check1", True)
    manager.SetBoolean("check2", False)
    manager.SetString("edit1", "Hello!")
    manager.SetString("list1", "Black")
End Sub
This way our code in Activity_Resume will work correctly whether it is the first time the program runs or after the user has closed the settings page.

The program is attached.
 

Attachments

  • PreferenceActivity.zip
    6.5 KB · Views: 1,081
Last edited:

joseluis

Active Member
Licensed User
Longtime User
How can I find out the name of the preferences screens activities? I want to apply styles to them in the manifest editor (notitlebar, fullscreen, etc), and I tried to use reflection lib to find that data, unsuccessfully.
 

sigster

Active Member
Licensed User
Longtime User
Can I get GetBoolean from the Checkbox when the program start to use in SQL.ExecQuery

Regards
Sigster
 

sigster

Active Member
Licensed User
Longtime User
Thanks

B4X:
   If manager.GetBoolean("check1") = True Then
   ToastMessageShow("Yes", False)
   Else
   ToastMessageShow("No", False)
   End If

Regards
Sigster
 

sigster

Active Member
Licensed User
Longtime User
You don't have radio button

so do you have Check1_CheckedChanged
so I can stop user select both check1 and 2

Regards
Sigster
 

kanaida

Active Member
Licensed User
Longtime User
Thanks. This is exactly what I was looking for :sign0142:

Now I can concentrate on the real parts of my app rather than the low level ui/db stuff. That stuff can wear you out quick :D
 

luke2012

Well-Known Member
Licensed User
Longtime User
App Crash calling CreatePreferenceScreen ()

My log is :

Starting: Intent { flg=0x20000 cmp=luke2012.android.pizzeria/anywheresoftware.b4a.objects.preferenceactivity (has extras) } from pid 17585
** Activity (main) Pause, UserClosed = false **
Shutting down VM
threadid=1: thread exiting with uncaught exception (group=0x40015568)
java.lang.RuntimeException: Unable to start activity ComponentInfo{luke2012.android.pizzeria/anywheresoftware.b4a.objects.preferenceactivity}: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1664)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1680)
at android.app.ActivityThread.access$1500(ActivityThread.java:117)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:130)
at android.app.ActivityThread.main(ActivityThread.java:3703)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at anywheresoftware.b4a.objects.preferenceactivity$PreferenceScreenWrapper.createPreference(preferenceactivity.java:169)
at anywheresoftware.b4a.objects.preferenceactivity.onCreate(preferenceactivity.java:41)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1628)
... 11 more
FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{luke2012.android.pizzeria/anywheresoftware.b4a.objects.preferenceactivity}: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1664)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1680)
at android.app.ActivityThread.access$1500(ActivityThread.java:117)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:130)
at android.app.ActivityThread.main(ActivityThread.java:3703)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at anywheresoftware.b4a.objects.preferenceactivity$PreferenceScreenWrapper.createPreference(preferenceactivity.java:169)
at anywheresoftware.b4a.objects.preferenceactivity.onCreate(preferenceactivity.java:41)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1628)
... 11 more
Force finishing activity luke2012.android.pizzeria/anywheresoftware.b4a.objects.preferenceactivity
Force finishing activity luke2012.android.pizzeria/.main
Activity pause timeout for HistoryRecord{40a81540 luke2012.android.pizzeria/anywheresoftware.b4a.objects.preferenceactivity}


Any suggestions ?

Thanks!
 

luke2012

Well-Known Member
Licensed User
Longtime User
I declared it in the Process_Global :

Dim screen As PreferenceScreen
 

CharlesIPTI

Active Member
Licensed User
Longtime User
Dont Hurt Me Im Just Asking :) smile smile

OK So its been like a year does this thing have events yet

:D :icon_clap: I'm just saying I like it I'm gonna use it but yea ....


Wheres the News section of this forum for new up coming stuff ??

Are we getting user classes any time soon..like within my project's deadline date maybe ??
 

mitsusdev

Member
Licensed User
Longtime User
Manager.GetBoolean with the key of the checkbox will return its state.

Hi,
i run PreferenceActivity into my app. It work fine for Android 2.3.x, but on ICS it CRASH when i try to call:

B4X:
StartActivity(screen.CreateIntent)

Below IDE logs:

B4X:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.acotel.myhealth/anywheresoftware.b4a.objects.preferenceactivity}: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Boolean


   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1956)
   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
   at android.app.ActivityThread.access$600(ActivityThread.java:123)
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
   at android.os.Handler.dispatchMessage(Handler.java:99)
   at android.os.Looper.loop(Looper.java:137)
   at android.app.ActivityThread.main(ActivityThread.java:4424)
   at java.lang.reflect.Method.invokeNative(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:511)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
   at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Boolean


   at android.app.SharedPreferencesImpl.getBoolean(SharedPreferencesImpl.java:242)
   at android.preference.Preference.getPersistedBoolean(Preference.java:1627)
   at android.preference.TwoStatePreference.onSetInitialValue(TwoStatePreference.java:184)
   at android.preference.Preference.dispatchSetInitialValue(Preference.java:1312)
   at android.preference.Preference.onAttachedToHierarchy(Preference.java:1124)
   at android.preference.PreferenceGroup.addPreference(PreferenceGroup.java:156)
   at anywheresoftware.b4a.objects.preferenceactivity$PreferenceScreenWrapper.createPreference(preferenceactivity.java:227)
   at anywheresoftware.b4a.objects.preferenceactivity$PreferenceCategoryWrapper.createPreference(preferenceactivity.java:453)
   at anywheresoftware.b4a.objects.preferenceactivity$PreferenceScreenWrapper.createPreference(preferenceactivity.java:224)
   at anywheresoftware.b4a.objects.preferenceactivity.onCreate(preferenceactivity.java:65)
   at android.app.Activity.performCreate(Activity.java:4465)
   at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049)
   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1920)
   ... 11 more

Where are my errors?

THX
 

mitsusdev

Member
Licensed User
Longtime User
Have you changed the type of one of the fields? This error happens because the saved value is of type String and you are not trying to treat it as boolean.

You can manually uninstall the app to delete the current settings file.

Hi,
below mi CreatePreferenceScreen Code:
B4X:
Sub CreatePreferenceScreen
   screen.Initialize("Impostazioni", "")
   Dim intentCat, cat1, cat2 As AHPreferenceCategory
   Dim intentScreen As AHPreferenceScreen
   
   intentCat.Initialize("Notifiche")
   intentCat.AddCheckBox("intentenable", "Abilita notifiche", "Notifiche abilitate", "Notifiche disabilitate", True, "")
   intentScreen.Initialize("Avanzate", "Preferenze notifiche")
   intentScreen.AddRingtone("ring1", "Avviso acustico", "Suoneria notifiche", "", "", intentScreen.RT_NOTIFICATION)
   
   intentScreen.AddCheckBox("chktts", "Abilita Text To Speech", "Text To Speech abilitato", "Text To Speech disabilitato", False, "")
   
'    Open Webbrowser using PhoneIntents
   Dim pi As PhoneIntents
   intentScreen.AddIntent("Maggiori informazioni", "Vai al sito web www.xxxxx.com", pi.OpenBrowser("http://www.xxxx.com"), "")

'    Add the screen with the intents calls to the category
   intentCat.AddPreferenceScreen(intentScreen, "intentenable")
      
   'add the categories to the main screen
   screen.AddPreferenceCategory(intentCat)
   
End Sub
 

mitsusdev

Member
Licensed User
Longtime User
Have you tried to manually uninstall your app and then run it?

Yes. i've tryed, but it crash more...it work only if i comment the line:

B4X:
......
' intentCat.AddPreferenceScreen(intentScreen, "intentenable")
 
Top