Question

So I am learning about SharedPreferences within Android.

I thought I would quickly try and mock up something simple. When the user selects a particular option from a list of options (3 options in this case) - the layout file will change accordingly. However, it always assumes the default value supplied, hence never changes the layout when another option is selected - so when another option is selected, it is recorded fine, but the layout doesn't change, this leads me to believe that there is perhaps a problem occurring when getting the preferences in the first place, I was wondering if someone could take a quick look and spot something obvious, or not so obvious with their experience/wisdom - here is the code:

MainActivity.java:

package com.example.preferenceslayout;

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends Activity
    implements OnSharedPreferenceChangeListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        loadPreferences();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    public boolean onOptionsItemSelected(MenuItem item) {
        switch(item.getItemId()) {
        case R.id.preferences:
            startActivity(new Intent(getApplicationContext(),
                     AppPreferences.class));
            break;
        }
        return false;
    }

    public void loadPreferences() {
        SharedPreferences prefs = getApplicationContext().
            getSharedPreferences("mode", MODE_PRIVATE);
        int layoutPref = prefs.getInt("mode", 10);
        switch(layoutPref) {
        case 10:
            setContentView(R.layout.activity_main);
            break;
        case 20:
            setContentView(R.layout.second_layout);
            break;
        case 30:
            setContentView(R.layout.third_layout);
            break;
        }
        prefs.registerOnSharedPreferenceChangeListener(MainActivity.this);
    }

    @Override
    public void onSharedPreferenceChanged(SharedPreferences arg0, String arg1) {
        loadPreferences();      
    }
}

preference.xml:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
    <ListPreference
        android:key="mode"
        android:title="@string/mode"
        android:defaultValue="1"
        android:summary="@string/summary"
        android:entries="@array/listArray"
        android:entryValues="@array/listValues" />
</PreferenceScreen>

AppPreferences.xml:

package com.example.preferenceslayout;

import android.os.Bundle;
import android.preference.PreferenceActivity;

public class AppPreferences extends PreferenceActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preference);
    }
}

main.xml:

<menu xmlns:android="http://schemas.android.com/apk/res/android" >
    <item
        android:id="@+id/action_settings"
        android:orderInCategory="100"
        android:showAsAction="never"
        android:title="@string/action_settings"/>
    <item
        android:id="@+id/preferences"
        android:title="Preferences" />
</menu>

PreferencesLayoutManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.preferenceslayout"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.preferenceslayout.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name="com.example.preferenceslayout.AppPreferences">
            <intent-filter>
                <action android:name=".AppPreferences" />
            </intent-filter>
        </activity>
    </application>
</manifest>

array.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="listArray">
        <item>10</item>
        <item>20</item>
        <item>30</item>
    </string-array>
    <string-array name="listValues">
        <item>1</item>
        <item>2</item>
    </string-array>
</resources>
Was it helpful?

Solution

You never write to your preferences. You need a prefs.putInt("mode", some_int); somewhere. Also your listener serves no purpose whatsoever - drop it.

You are writing to the default shared preferences cause preferences screens write there. The "mode" is just the key - there is one key in the default shared preferences and one in your preference file (named "mode_something.xml") - but you write the one (automatically via the preferences screen) and you read the other (which is never set)

OTHER TIPS

I didn't look too deep into your code, but after a quick overview the following catched my attention:

you are setting this in your ListPreference in your preference.xml

android:entries="@array/listArray"
android:entryValues="@array/listValues" 

but in your array.xml you have 3 items in your entries string-array and just 2 items in your listValues string-array

<string-array name="listArray">
    <item>10</item>
    <item>20</item>
    <item>30</item>
</string-array>
<string-array name="listValues">
    <item>1</item>
    <item>2</item>
</string-array>

You should add a third item to your listValues string-array

BTW: you should consider renaming "listArray" so that it is more clear that it holds the Entries of your list. So maybe call it "listEntries". (remember to also change reference to android:entries="@array/listEntries" then) In general the entries are what the user actually sees, the values is what android uses. So for example your string array could look something like:

<string-array name="listEntries">
    <item>one apple</item>
    <item>two apples</item>
    <item>three apples</item>
</string-array>
<string-array name="listValues">
    <item>1</item>
    <item>2</item>
    <item>3</item>
</string-array>

onSharedPreferenceChanged will be called every time you change your preferences, so don't instantiate a new SharedPreferences object each time you change a preference, what you have to do is:

First, make SharedPreferences a class attribute, so you can access to a preference everywhere in your Activity:

private SharedPreferences prefs;

Now, inside onCreate() call:

prefs=PreferenceManager.getDefaultSharedPreferences(this);
prefs.registerOnSharedPreferenceChangeListener(this);

And finally, your loadPreferences() method should look like this:

public void loadPreferences() {

    int layoutPref = prefs.getInt("mode", 10);
    switch(layoutPref) {
    case 10:
        setContentView(R.layout.activity_main);
        break;
    case 20:
        setContentView(R.layout.second_layout);
        break;
    case 30:
        setContentView(R.layout.third_layout);
        break;
    }

}

Hope it helps you!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top