0

I have a 2 preferences in my Settings: 1- PreferenceCategory 2-PreferenceX When I press PreferenceX, I add new preferences at runtime into PreferenceCategory. But when I rotate the device or kill my application then reopen it again: I can't find all the new preferences that I have at runtime. I tried to use saveHierarchyState & restoreHierarchyState for the given preferenceCategory but still can't make it work.

Here is a sample for my code:

my preferences.xml file:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android">

    <PreferenceCategory
        android:key="myCat"
        android:title="Example list"
        android:summary="This list is empty by default" />

    <Preference
        android:key="button"
        android:title="Example button"
        android:summary="When clicked this adds an item to the list" />

</PreferenceScreen>

Here is my MainActivity code:

package com.example.testpreferences;

import android.os.Bundle;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceActivity;
import android.preference.PreferenceGroup;

public class MainActivity extends PreferenceActivity {

    private int counter=0;
    private PreferenceGroup  pg;
    /** Called when the activity is first created. */
    @SuppressWarnings("deprecation")
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);

       pg = (PreferenceGroup) getPreferenceScreen().findPreference("myCat");

        getPreferenceScreen().findPreference("button").setOnPreferenceClickListener(new OnPreferenceClickListener() {

            @Override
            public boolean onPreferenceClick(Preference a_preference) {


                Preference preference = new Preference(getApplicationContext());
                preference.setTitle("Item" + counter);
                preference.setKey("key"+counter);
                counter++;
                pg.addPreference(preference);

                return true;
            }
        });
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        pg.saveHierarchyState(outState);
    }

    @Override
    protected void onRestoreInstanceState(Bundle state) {
        if (null != state) {
            pg.restoreHierarchyState(state);

        }else
            super.onRestoreInstanceState(state);
    }
}

Try to rotate the device and you will the wrong behavior that I am describing. How can I keep the new preferences that are added during runtime to be shown upon screen rotation?

Wael Showair
  • 3,092
  • 2
  • 22
  • 29

1 Answers1

1

Rotate causes Activity restart.

When device is rotated, this happens.
onPause -> onCreate(with old savedInstanceState) ... -> onPause -> onCreate(newer savedInstanceState)

It means 2 activity reboot cycles (with differtent savedInstanceState) for 1 rotate.
(I've tried this code)

private int bootCounter = 0;

onCreate(...) { // watch savedInstanceState
    if (null != savedInstanceState) {
        bootCounter = savedInstanceState.getInt("bootCounter");
        bootCounter++;
    }
}

onSaveInstanceState(...) {
    ...
    outState.putInt("bootCounter", bootCounter);
}

maybe same problems:
Home key press behaviour
I haven't tested but there are some hints around #14, #17:
Issue26658:Activity stack confused when launching app from browser
long one, but many hints:
savedInstanceState always null


Alternation. (Use SharedPreferences to save preferences)

public class MainActivity extends PreferenceActivity
{
    private int counter = 0;
    private PreferenceGroup pg;

    /** Called when the activity is first created. */
    @SuppressWarnings("deprecation")
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        Load();

        getPreferenceScreen().findPreference("button").setOnPreferenceClickListener(new OnPreferenceClickListener()
        {
            @Override
            public boolean onPreferenceClick(Preference a_preference)
            {
                // Preference preference = new Preference(getApplicationContext());
                Preference preference = new Preference(MainActivity.this);
                preference.setTitle("Item" + counter);
                preference.setKey("key" + counter);
                counter++;
                pg.addPreference(preference);

                return true;
            }
        });
    }

    private void Save()
    {
        SharedPreferences sharedPreferences;
        Editor editor;
        Preference preference;
        int keyCount;

        if (null != pg)
        {
            sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
            if (null != sharedPreferences)
            {
                editor = sharedPreferences.edit();
                keyCount = pg.getPreferenceCount();
                // editor.putInt("keyCount", keyCount);
                // editor.putInt("counter", counter);
                for (int i = 0; i < keyCount; i++)
                {
                    preference = pg.getPreference(i);
                    editor.putString(preference.getKey(), preference.getTitle().toString());
                }
                // Save to file
                // *** commit() will block caller thread ***
                editor.commit();
            }
        }
    }

    @SuppressWarnings("deprecation")
    private void Load()
    {
        SharedPreferences sharedPreferences;
        Preference preference;
        Map<String, ?> data;

        addPreferencesFromResource(R.xml.preferences);
        pg = (PreferenceGroup) getPreferenceScreen().findPreference("myCat");
        counter = 0;
        sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
        if (null != sharedPreferences)
        {
            // load from SharedPreferences
            data = sharedPreferences.getAll();

            // this doesn't keep original order
            for (Entry<String, ?> kv : data.entrySet())
            {
                if (String.class != kv.getValue().getClass())
                {
                    continue;
                }
                // fixed: getApplicationContext() causes style bug. (*1)
                // preference = new Preference(getApplicationContext());
                preference = new Preference(MainActivity.this);
                preference.setTitle(new String((String) kv.getValue()));
                preference.setKey(new String(kv.getKey()));
                preference.setEnabled(true);
                counter++;
                pg.addPreference(preference);
            }
            // counter = sharedPreferences.getInt("counter", counter);
            onContentChanged();
        }
    }

    //@Override
    //protected void onSaveInstanceState(Bundle outState)
    //{
    //    super.onSaveInstanceState(outState);
    //}

    @Override
    protected void onPause()
    {
        super.onPause();
        Save();
    }

}

(*1): fixed.
If getApplicationContext() is used to create Preference, items will be loaded but styles (or state) are incorrect. (If loaded item is touched, correct text is shown.)

Community
  • 1
  • 1
Toris
  • 2,348
  • 13
  • 16
  • Thanks for your answer, I have added onPause code to the above code but it did not work, when I rotate the device, I am still missing the new added preferences. Moreover, according to my first code, the method onSaveInstanceState was invoked normally upon resarting the activity – Wael Showair Feb 21 '14 at 23:49
  • Thanks for your update I took your suggested alternative solution and it works fine with me. For the bug style that you mentioned, I managed to fix it by changing the context that is used while restoring in mehtod Load to be preference = new Preference(this); Please edit your answer accordingly so that I can check it as correct answer and I think there is no need for the first part in your answer since it is very confusing – Wael Showair Feb 23 '14 at 14:36