I quickly peeked into the source code and well, this is the way how it is 
programmed. When an exception occurs while the preferences data file gets 
read, SharedPreferences sets internally an empty map so you start from 
scratch. I even dug a bit deeper. The XML serializer just ignores NULL keys 
and creates XML output that cannot be properly read anymore through the map 
deserialization method which seems to expect an existing key value.

As for why it has been programmed like that... I think the reasoning may be 
that preferences are not deemed to be of so much importance that it should 
make the app crash in case of failure. This error state is silently 
discarded and you start over with the defaults. I think that's a reasonable 
approach since any app should be able to start over with empty preferences.

In this particular case you may have discovered a tiny bug you may want to 
report. But to be honest, using null keys is a pretty unusual thing to do.

On Wednesday, October 30, 2013 5:48:12 AM UTC-5, Palmer Eldritch wrote:
>
> The preferences are apparently *cleared *when one tries to load them when 
> there is a null key which is bad ! Reproducer :
>
>     public class XmlExceptionTest extends AndroidTestCase {
>         /** Run it twice - on the second run the exception is thrown */
>         public void testXmlException() {
>             Context ctx = getContext();
>             SharedPreferences prefs = PreferenceManager
>                 .getDefaultSharedPreferences(ctx); // exception thrown 
> here (line 18)
>             // and apparently it clears the prefs as the condition below 
> is false
>             if (prefs.contains("run_once")) { // false
>                 Log.w("XmlExceptionTest",
>                     "contains null key :" + prefs.contains(null));
>             }
>             Editor e = prefs.edit();
>             e.putBoolean("run_once", true).commit();
>             e.putString(null, "I put a sting with null key").commit();
>             assertTrue("Contains null", prefs.contains(null));
>             PreferenceManager.getDefaultSharedPreferences(ctx); // 
> exception
>             // NOT thrown here  - why ? - apparently there is a static 
> factory
>             // returning the instance it already constructed
>             // e.clear().commit(); // this eliminates the exception
>         }
>     }
>     
> exception :
>
>     W/ApplicationContext(): getSharedPreferences
>     W/ApplicationContext(): org.xmlpull.v1.XmlPullParserException: Map 
> value without name attribute: string
>     W/ApplicationContext():     at 
> com.android.internal.util.XmlUtils.readThisMapXml(XmlUtils.java:521)
>     W/ApplicationContext():     at 
> com.android.internal.util.XmlUtils.readThisValueXml(XmlUtils.java:733)
>     W/ApplicationContext():     at 
> com.android.internal.util.XmlUtils.readValueXml(XmlUtils.java:667)
>     W/ApplicationContext():     at 
> com.android.internal.util.XmlUtils.readMapXml(XmlUtils.java:470)
>     W/ApplicationContext():     at 
> android.app.ContextImpl.getSharedPreferences(ContextImpl.java:361)
>     W/ApplicationContext():     at 
> android.preference.PreferenceManager.getDefaultSharedPreferences(PreferenceManager.java:348)
>     W/ApplicationContext():     at 
> gr.uoa.di.android.helpers.test.XmlExceptionTest.testXmlException(XmlExceptionTest.java:18)
>     W/ApplicationContext():     at 
> java.lang.reflect.Method.invokeNative(Native Method)
>     W/ApplicationContext():     at 
> java.lang.reflect.Method.invoke(Method.java:521)
>     W/ApplicationContext():     at 
> junit.framework.TestCase.runTest(TestCase.java:154)
>     W/ApplicationContext():     at 
> junit.framework.TestCase.runBare(TestCase.java:127)
>     W/ApplicationContext():     at 
> junit.framework.TestResult$1.protect(TestResult.java:106)
>     W/ApplicationContext():     at 
> junit.framework.TestResult.runProtected(TestResult.java:124)
>     W/ApplicationContext():     at 
> junit.framework.TestResult.run(TestResult.java:109)
>     W/ApplicationContext():     at 
> junit.framework.TestCase.run(TestCase.java:118)
>     W/ApplicationContext():     at 
> android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:169)
>     W/ApplicationContext():     at 
> android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:154)
>     W/ApplicationContext():     at 
> android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:520)
>     W/ApplicationContext():     at 
> android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1447)
>
> Posted in SO 
> here<http://stackoverflow.com/questions/19610569/android-sharedpreferences-null-keys-values-and-sets-corner-cases>and
>  in the relevant thread 
> here <http://stackoverflow.com/a/19621603/281545> - but still no answers
>
> Any ideas ?
>

-- 
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Android Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to