A型行为我正在观察WRT传递序列化的数据作为额外的意图是很奇怪的,我只是想澄清是否有什么东西我不会错过了。
所以,我试图做的事情是,在ActivtyA
我把LinkedList
实例为intent
我开始下一个活动创造- ActivityB
。
LinkedList<Item> items = (some operation);
Intent intent = new Intent(this, ActivityB.class);
intent.putExtra(AppConstants.KEY_ITEMS, items);
在onCreate
的ActivityB
,我试图找回LinkedList
额外如下-
LinkedList<Item> items = (LinkedList<Item>) getIntent()
.getSerializableExtra(AppConstants.KEY_ITEMS);
在运行此,我多次得到了ClassCastException
在ActivityB
,在上面就行了。 基本上,除了说我收到ArrayList
。 有一次,我改变了上面的代码,以获得一个ArrayList
替代,一切工作就好了。
现在,我不能只从现有的文档弄清楚是否通过序列化List实现时,这是Android上的预期行为。 或许,有一些根本性的错误瓦特/我在做什么。
谢谢。
我可以告诉你为什么会这样,但你不会喜欢它;-)
首先一点背景资料:
在一个附加 Intent
基本上是一个Android Bundle
这基本上是一个HashMap
的键/值对。 所以,当你做这样的事情
intent.putExtra(AppConstants.KEY_ITEMS, items);
Android的创建一个新的Bundle
的演员,并增加了一个映射条目的Bundle
,其中的关键是AppConstants.KEY_ITEMS
和值是一个项目 (这是您的LinkedList的对象)。
这是一切优秀和良好的,如果你是看演员束代码执行后,你会发现它包含一个LinkedList
。 现在到了有趣的部分...
当你调用startActivity()
与含有额外意图,Android的需要群众演员从地图键/值对转换成字节流。 基本上,它需要序列的捆绑 。 它需要做,因为它可能会在另一个进程开始的活动,为了做到这一点,需要进行序列化/反序列化被捆绑的对象,以便它可以在新的过程中重新创建它们。 它还需要做到这一点,因为Android的节省一些系统表的意图的内容,以便它可以重新生成意图是否需要更高版本。
为了序列的Bundle
成字节流,它通过在所述束中的地图,并得到每个键/值对。 然后,它需要每一个“值”(这是一些类型的对象),并试图确定它是什么样的对象,以便它可以以最有效的方式对其进行序列化。 要做到这一点,它会检查与已知对象类型的列表中的对象类型。 “已知对象类型”列表中包含的东西Integer
, Long
, String
, Map
, Bundle
可惜还List
。 因此,如果对象是一个List
(其中有许多不同种类,包括LinkedList
)将其序列并将其标记为类型的对象List
。
当Bundle
被反序列化,即:当你这样做:
LinkedList<Item> items = (LinkedList<Item>)
getIntent().getSerializableExtra(AppConstants.KEY_ITEMS);
它产生ArrayList
中的所有对象Bundle
式的List
。
是不是真的有什么,你可以做些什么来改变Android的这种行为。 至少现在你知道为什么它这样做。
只是让你知道:其实我写了一个小的测试程序来验证这种行为,我已经看过的源代码Parcel.writeValue(Object v)
这是从被调用的方法Bundle
时,它的地图转换成字节流。
重要提示:由于List
是一个接口,这意味着实现任何类List
,你放入Bundle
会出来作为一个ArrayList
。 这也是有趣的是, Map
也是“已知对象类型”,这意味着,无论什么样的名单Map
你把对象变成一个Bundle
(例如TreeMap
, SortedMap
,或实现任何类Map
界面),你总是会得到一个HashMap
出来。
通过回答@大卫瓦瑟是正确诊断问题的条款。 这篇文章是分享我如何处理它。
与任何的问题List
对象出来作为一个ArrayList
是不可怕的,因为你总是可以这样做
LinkedList<String> items = new LinkedList<>(
(List<String>) intent.getSerializableExtra(KEY));
这将反序列化的列表中的所有元素添加到新LinkedList
。
问题是差多了,当涉及到Map
,因为你可能已经尝试序列化LinkedHashMap
,现在已经失去了元素排序。
幸运的是,解决这个(相对)无痛的方式:定义自己的序列化包装类。 您可以为特定类型的做,或做一般:
public class Wrapper <T extends Serializable> implements Serializable {
private T wrapped;
public Wrapper(T wrapped) {
this.wrapped = wrapped;
}
public T get() {
return wrapped;
}
}
然后你可以使用这个隐藏你的List
, Map
或其他数据类型从Android的类型检查:
intent.putExtra(KEY, new Wrapper<>(items));
然后:
items = ((Wrapper<LinkedList<String>>) intent.getSerializableExtra(KEY)).get();
如果您正在使用ICEPICK库,并且有这个问题,你可以使用泰德圈的技术与定制的捆绑,以避免处理代码中的包装情况。
public class LinkedHashmapBundler implements Bundler<LinkedHashMap> {
@Override
public void put(String s, LinkedHashMap val, Bundle bundle) {
bundle.putSerializable(s, new Wrapper<>(val));
}
@SuppressWarnings("unchecked")
@Override
public LinkedHashMap get(String s, Bundle bundle) {
return ((Wrapper<LinkedHashMap>) bundle.getSerializable(s)).get();
}
}
// Use it like this
@State(LinkedHashmapBundler.class) LinkedHasMap map
文章来源: LinkedList put into Intent extra gets recast to ArrayList when retrieving in next activity