Android的共享preferences null键,数值和集合&LT;&GT; - 个别案例 [英] android SharedPreferences null keys, values and sets<?> - corner cases
问题描述
得到了广泛的测试共享preferences
框架。虽然大多数的作品作为一个希望我碰到一些情况下,我不知道什么是他们背后的推理运行。我给一些测试所有这些都通过 - 他们共同设立是:
上下文CTX;
共享preferences preFS;
编辑编;
保护无效设置()抛出异常{
super.setUp();
CTX =的getContext();
preFS = preferenceManager.getDefaultShared preferences(CTX);
ED = prefs.edit();
}
保护无效tearDown的()抛出异常{
如果(ED!= NULL)ed.clear()提交()。
super.tearDown();
}
现在怪异的要点:
-
当我把一个空值,我要问它有一个空的默认把它找回来的 - 如果默认为非null我得到这个默认了。 即使默认为不同类型从一个我放在的的。适用于
字符串
和设置&LT;字符串&GT;
(但我可以得到一个布尔值为例):公共无效testNullString(){ ed.putString(string_key,NULL); // putString()和putStringSet()只 ed.commit(); assertTrue(prefs.contains(string_key)); 的assertEquals(空,prefs.getString(string_key,NULL)); //如果我指定一个非空默认我得到这个默认回,不为空 的assertEquals(字符串,prefs.getString(string_key,串)); // *即使我问一个布尔值* 的assertEquals(真,prefs.getBoolean(string_key,真)); }
-
我可以很容易地把一个
设置&LT;整数GT;
的preFS里面:@燮pressWarnings(未登记) @TargetApi(Build.VERSION_ codeS.HONEYCOMB) 公共无效testNullStringSetsRaw(){ 如果(Build.VERSION.SDK_INT&GT; = Build.VERSION_ codeS.HONEYCOMB){ @燮pressWarnings(rawtypes) 决胜盘integerHashSet =新的HashSet(); integerHashSet.add(1); ed.putStringSet(set_key,integerHashSet); ed.commit(); 决胜盘&LT;字符串&GT; defValues =新的HashSet&LT;字符串&GT;(); defValues.add(字符串); 设置&LT;字符串&GT; S = prefs.getStringSet(set_key,defValues); 最后弦乐味精=设定的我把+ integerHashSet +和我下了车:+ S; Log.e(TAG,味精); //相同 - [1] assertTrue(味精,integerHashSet.equals(S)); assertTrue(s.contains(1)); //! } }
-
什么是处理null键?他们似乎是完全合法的键:
公共无效testNullKeyNonNullString(){ 最后弦乐NULL_KEY = NULL; ed.putString(NULL_KEY,串); ed.commit(); assertTrue(包含null键,prefs.contains(NULL_KEY)); 的assertEquals(检索值给空默认,串, prefs.getString(NULL_KEY,NULL)); 的assertEquals(检索值给予默认,串, prefs.getString(NULL_KEY,串+嗒嗒)); 尝试 { // 没有成交 ! prefs.getBoolean(NULL_KEY,真正的); 失败(预期CCE); }赶上(ClassCastException异常E){} }
但我已经看到我的日志之类的东西:
org.xmlpull.v1.XmlPullParserException:地图值,而name属性:布尔
- 见<一href="http://stackoverflow.com/questions/5368442/android-getshared$p$pferences-error-map-value-without-name-attribute-boolean">android getShared preferences错误:地图值,而name属性:布尔了讨论。我不知道这是关系到空
键。 修改:这是所关乎再生器:公共类XmlExceptionTest扩展AndroidTestCase { / **运行了两次 - 在第二次运行抛出异常* / 公共无效testXmlException(){ 上下文CTX =的getContext(); 共享preferences preFS = preferenceManager .getDefaultShared preferences(CTX); //这里异常抛出(第18行) //显然它清除preFS为下面的条件为假 如果(prefs.contains(run_once)){//假 Log.w(XmlExceptionTest 包含null键+ prefs.contains(空)); } 编辑E = prefs.edit(); e.putBoolean(run_once,真).commit(); 。e.putString(NULL,我把与空密钥刺)提交(); assertTrue(包含空值,prefs.contains(空)); preferenceManager.getDefaultShared preferences(CTX); // 例外 //没有抛出在这里 - 为什么? - 显然有一个静态工厂 //返回它已经构建的实例 // e.clear()提交()。 //这消除了异常 } }
异常:
W / ApplicationContext的():getShared preferences W / ApplicationContext中():org.xmlpull.v1.XmlPullParserException:没有name属性地图值:字符串 W / ApplicationContext中():在com.android.internal.util.XmlUtils.readThisMapXml(XmlUtils.java:521) W / ApplicationContext中():在com.android.internal.util.XmlUtils.readThisValueXml(XmlUtils.java:733) W / ApplicationContext中():在com.android.internal.util.XmlUtils.readValueXml(XmlUtils.java:667) W / ApplicationContext中():在com.android.internal.util.XmlUtils.readMapXml(XmlUtils.java:470) W / ApplicationContext中():在android.app.ContextImpl.getShared preferences(ContextImpl.java:361) W / ApplicationContext中():在安卓preference preferenceManager.getDefaultShared preferences(preferenceManager.java:348)。 W / ApplicationContext中():在gr.uoa.di.android.helpers.test.XmlExceptionTest.testXmlException(XmlExceptionTest.java:18) W / ApplicationContext中():在java.lang.reflect.Method.invokeNative(本机方法) W / ApplicationContext中():在java.lang.reflect.Method.invoke(Method.java:521) W / ApplicationContext中():在junit.framework.TestCase.runTest(TestCase.java:154) W / ApplicationContext中():在junit.framework.TestCase.runBare(TestCase.java:127) W / ApplicationContext中():在junit.framework.TestResult $ 1.protect(TestResult.java:106) W / ApplicationContext中():在junit.framework.TestResult.runProtected(TestResult.java:124) W / ApplicationContext中():在junit.framework.TestResult.run(TestResult.java:109) W / ApplicationContext中():在junit.framework.TestCase.run(TestCase.java:118) W / ApplicationContext中():在android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:169) W / ApplicationContext中():在android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:154) W / ApplicationContext中():在android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:520) W / ApplicationContext中():在android.app.Instrumentation $ InstrumentationThread.run(Instrumentation.java:1447)
和明显的的preferences的时候,抛出异常清零的(坏的坏人坏事)
所以,我的问题是:确实是行为,我的状态是(或我错过了一些愚蠢的)?这是什么背后的动机(尤其是空值行为)?难道记录,并保证保持如此 - 或者可能改变?是第2点的监督?
-
这是<一href="http://androidxref.com/4.0.3_r1/xref/frameworks/base/core/java/android/app/Shared$p$pferencesImpl.java#206"相对=nofollow>在code
-
这就是我不理解泛型:
<一个href="http://books.google.gr/books?id=ka2VUBqHiWkC&pg=PA144&lpg=PA144&source=bl&ots=yYKmRmr5Q3&sig=HESfg8Y3UaprOvN7GyF1XYN-DW8&hl=en&sa=X&ei=0Pe6UunkBMavygPz64CAAw&redir_esc=y#v=onepage&q&f=false"相对=nofollow>您可以 很容易地把一个字符串转换为
的HashSet&LT;整数GT;
通过使用原始类型的HashSet
-
在这里发布一个问题: HTTP:/ /$c$c.google.com/p/android/issues/detail?id=63463 (开始的讨论在谷歌集团与通常NOOP结果)。事实上,作为2014年1月7日发行标记为未来的版本:)
Been extensively testing the SharedPreferences
framework. While most works as one would expect I run across some cases where I wonder what's the reasoning behind them. I give some tests all of which pass - their common set up is :
Context ctx;
SharedPreferences prefs;
Editor ed;
protected void setUp() throws Exception {
super.setUp();
ctx = getContext();
prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
ed = prefs.edit();
}
protected void tearDown() throws Exception {
if (ed != null) ed.clear().commit();
super.tearDown();
}
Now the weird points :
When I put a null value in, I have to ask for it with a null default to get it back - if the default is non null I get this default back. Even if the default is of a different type from the one I put in. Applies to
String
andSet<String>
(but I can get back a boolean for instance) :public void testNullString() { ed.putString("string_key", null); // putString() and putStringSet() only ed.commit(); assertTrue(prefs.contains("string_key")); assertEquals(null, prefs.getString("string_key", null)); // if I specify a non null default I get this default back, not null assertEquals("a string", prefs.getString("string_key", "a string")); // *even if I ask for a boolean* assertEquals(true, prefs.getBoolean("string_key", true)); }
I can easily put a
Set<Integer>
inside the prefs :@SuppressWarnings("unchecked") @TargetApi(Build.VERSION_CODES.HONEYCOMB) public void testNullStringSetsRaw() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { @SuppressWarnings("rawtypes") final Set integerHashSet = new HashSet(); integerHashSet.add(1); ed.putStringSet("set_key", integerHashSet); ed.commit(); final Set<String> defValues = new HashSet<String>(); defValues.add("a string"); Set<String> s = prefs.getStringSet("set_key", defValues); final String msg = "The set I put in: " + integerHashSet + " and what I got out :" + s; Log.e(TAG, msg); // the same - [1] assertTrue(msg, integerHashSet.equals(s)); assertTrue(s.contains(1)); // ! } }
What's the deal with null keys ? They seem to be perfectly legal keys:
public void testNullKeyNonNullString() { final String NULL_KEY = null; ed.putString(NULL_KEY, "a string"); ed.commit(); assertTrue("Contains null key", prefs.contains(NULL_KEY)); assertEquals("Retrieve the value giving null default", "a string", prefs.getString(NULL_KEY, null)); assertEquals("Retrieve the value giving default", "a string", prefs.getString(NULL_KEY, "a string" + "blah")); try { // no deal ! prefs.getBoolean(NULL_KEY, true); fail("Expected CCE"); } catch (ClassCastException e) {} }
but I have seen in my logs things like :
org.xmlpull.v1.XmlPullParserException: Map value without name attribute: boolean
- see android getSharedPreferences error: Map value without name attribute: boolean for a discussion. I wonder if this is related tonull
keys. EDIT : it is related- 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)
and apparently the preferences are cleared when the exception is thrown (bad bad bad)
So my questions are : is indeed the behavior as I state it (or have I missed something silly) ? What is the motivation behind it (especially the null values behavior) ? Is it documented and guaranteed to stay so - or may change ? Is point 2 an oversight ?
It's in the code
It's me not understanding generics:
You can easily put a String into a
HashSet<Integer>
by using the raw typeHashSet
Posted an issue here: http://code.google.com/p/android/issues/detail?id=63463 (after starting a discussion in google groups with the usual noop results). Actually as of 2014.01.07 the issue is marked Future Release :)
这篇关于Android的共享preferences null键,数值和集合&LT;&GT; - 个别案例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!