ani*_*van 26 android android-intent
我正在观察wrt传递可序列化数据作为intent extra的行为是非常奇怪的,我只想澄清是否有一些我不会错过的东西.
所以我试图做的是在ActivtyA
我LinkedList
为intent
我开始下一个活动而创建一个实例- ActivityB
.
LinkedList<Item> items = (some operation);
Intent intent = new Intent(this, ActivityB.class);
intent.putExtra(AppConstants.KEY_ITEMS, items);
Run Code Online (Sandbox Code Playgroud)
在onCreate
中ActivityB
,我试图获取LinkedList
额外如下-
LinkedList<Item> items = (LinkedList<Item>) getIntent()
.getSerializableExtra(AppConstants.KEY_ITEMS);
Run Code Online (Sandbox Code Playgroud)
在运行这个时,我ClassCastException
在ActivityB
上面的一行中反复进入.基本上,例外说我收到了ArrayList
.一旦我改变了上面的代码来接收一个代码ArrayList
,一切都运行得很好.
现在我不能从现有文档中找出这是否是Android传递可序列化List实现时的预期行为.或者,或许,我正在做的事情存在根本性的错误.
谢谢.
Dav*_*ser 49
我可以告诉你为什么会这样,但你不会喜欢它;-)
首先是一些背景信息:
一个Intent
基本上是Android的附加功能,Bundle
它基本上是HashMap
键/值对.所以,当你做类似的事情
intent.putExtra(AppConstants.KEY_ITEMS, items);
Run Code Online (Sandbox Code Playgroud)
Android Bundle
为附加组件创建一个新的,并Bundle
在键所在的位置添加一个映射条目,AppConstants.KEY_ITEMS
值为items(这是您的LinkedList对象).
这一切都很好,如果你在代码执行后查看extras包,你会发现它包含一个LinkedList
.现在来了有趣的部分......
当您startActivity()
使用包含额外内容的Intent进行调用时,Android需要将附加内容从键/值对映射转换为字节流.基本上它需要序列化Bundle.它需要这样做,因为它可以在另一个进程中启动活动,为了做到这一点,它需要序列化/反序列化Bundle中的对象,以便它可以在新进程中重新创建它们.它还需要执行此操作,因为Android会在某些系统表中保存Intent的内容,以便在以后需要时可以重新生成Intent.
为了将字符串Bundle
流序列化,它遍历包中的映射并获取每个键/值对.然后它获取每个"值"(这是某种对象)并尝试确定它是什么类型的对象,以便它可以以最有效的方式序列化它.为此,它根据已知对象类型列表检查对象类型."已知对象类型"列表包含喜欢的东西Integer
,Long
,String
,Map
,Bundle
可惜也List
.因此,如果对象是List
(其中包含许多不同种类LinkedList
),则将其序列化并将其标记为类型对象List
.
当Bundle
反序列化时,即:当你这样做时:
LinkedList<Item> items = (LinkedList<Item>)
getIntent().getSerializableExtra(AppConstants.KEY_ITEMS);
Run Code Online (Sandbox Code Playgroud)
它为类型ArrayList
中的所有对象生成一个.Bundle
List
你无法改变Android的这种行为.至少现在你知道为什么会这样做.
只是这样你才知道:我实际上写了一个小的测试程序来验证这种行为,我已经查看了源代码,Parcel.writeValue(Object v)
该代码是从Bundle
将地图转换为字节流时调用的方法.
重要说明:因为List
是一个接口,这意味着任何实现List
你所放入的类的类Bundle
都会以ArrayList
.这也是有趣的是,Map
也这意味着,不管是什么样的"已知对象类型"列表中Map
的对象,你投入Bundle
(例如TreeMap
,SortedMap
或实现的任何类Map
接口),你总是会得到一个HashMap
出它.
@David Wasser的答案在诊断问题方面是正确的。这篇文章是分享我是如何处理的。
任何List
对象作为 an 出现的问题ArrayList
并不可怕,因为你总是可以做类似的事情
LinkedList<String> items = new LinkedList<>(
(List<String>) intent.getSerializableExtra(KEY));
Run Code Online (Sandbox Code Playgroud)
这会将反序列化列表的所有元素添加到新的LinkedList
.
当涉及到 时Map
,问题会更糟,因为您可能已经尝试序列化 aLinkedHashMap
并且现在丢失了元素排序。
幸运的是,有一种(相对)轻松的方法可以解决这个问题:定义您自己的可序列化包装类。您可以针对特定类型执行此操作,也可以进行一般操作:
public class Wrapper <T extends Serializable> implements Serializable {
private T wrapped;
public Wrapper(T wrapped) {
this.wrapped = wrapped;
}
public T get() {
return wrapped;
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以用它来隐藏自己List
,Map
或其他数据来自Android的类型检查类型:
intent.putExtra(KEY, new Wrapper<>(items));
Run Code Online (Sandbox Code Playgroud)
然后:
items = ((Wrapper<LinkedList<String>>) intent.getSerializableExtra(KEY)).get();
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
5934 次 |
最近记录: |