在下一个活动中检索时,放入 Intent extra 的 LinkedList 会重新转换为 ArrayList [英] LinkedList put into Intent extra gets recast to ArrayList when retrieving in next activity
问题描述
我观察到的将可序列化数据作为 Intent extra 传递的行为很奇怪,我只是想澄清一下是否有我没有遗漏的东西.
A behaviour i'm observing w.r.t passing serializable data as intent extra is quite strange, and I just wanted to clarify whether there's something I'm not missing out on.
所以我试图做的事情是在 ActivtyA
中,我将一个 LinkedList
实例放入我创建的 intent
以开始下一个活动 - ActivityB
.
So the thing I was trying to do is that in ActivtyA
I put a LinkedList
instance into the intent
I created for starting the next activity - ActivityB
.
LinkedList<Item> items = (some operation);
Intent intent = new Intent(this, ActivityB.class);
intent.putExtra(AppConstants.KEY_ITEMS, items);
在 ActivityB
的 onCreate
中,我尝试检索 LinkedList
额外如下 -
In the onCreate
of ActivityB
, I tried to retrieve the LinkedList
extra as follows -
LinkedList<Item> items = (LinkedList<Item>) getIntent()
.getSerializableExtra(AppConstants.KEY_ITEMS);
在运行它时,我在 ActivityB
中反复得到一个 ClassCastException
,在上面的行.基本上,异常表示我正在接收一个 ArrayList
.一旦我更改了上面的代码以接收 ArrayList
,一切都很好.
On running this, I repeatedly got a ClassCastException
in ActivityB
, at the line above. Basically, the exception said that I was receiving an ArrayList
. Once I changed the code above to receive an ArrayList
instead, everything worked just fine.
现在我不能仅仅从现有文档中确定这是否是传递可序列化 List 实现时 Android 上的预期行为.或者,我所做的事情存在根本性的错误.
Now I can't just figure out from the existing documentation whether this is the expected behaviour on Android when passing serializable List implementations. Or perhaps, there's something fundamentally wrong w/ what I'm doing.
谢谢.
推荐答案
我可以告诉你为什么会这样,但你不会喜欢它 ;-)
I can tell you why this is happening, but you aren't going to like it ;-)
首先介绍一下背景信息:
First a bit of background information:
Extras 在 Intent
基本上是一个 Android Bundle
,它基本上是一个键/值对的 HashMap
.所以当你做类似的事情
Extras in an Intent
are basically an Android Bundle
which is basically a HashMap
of key/value pairs. So when you do something like
intent.putExtra(AppConstants.KEY_ITEMS, items);
Android 为 extras 创建一个新的 Bundle
并向 Bundle
添加一个映射条目,其中键是 AppConstants.KEY_ITEMS
和值是 items(这是您的 LinkedList 对象).
Android creates a new Bundle
for the extras and adds a map entry to the Bundle
where the key is AppConstants.KEY_ITEMS
and the value is items (which is your LinkedList object).
这一切都很好,如果您在代码执行后查看 extras 包,您会发现它包含一个 LinkedList
.现在是有趣的部分...
This is all fine and good, and if you were to look at the extras bundle after your code executes you will find that it contains a LinkedList
. Now comes the interesting part...
当您使用包含 extras 的 Intent 调用 startActivity()
时,Android 需要将 extras 从键/值对映射转换为字节流.基本上它需要序列化Bundle.它需要这样做,因为它可能会在另一个进程中启动活动,为此它需要序列化/反序列化 Bundle 中的对象,以便它可以在新进程中重新创建它们.它也需要这样做,因为Android将Intent的内容保存在一些系统表中,以便以后需要时可以重新生成Intent.
When you call startActivity()
with the extras-containing Intent, Android needs to convert the extras from a map of key/value pairs into a byte stream. Basically it needs to serialize the Bundle. It needs to do that because it may start the activity in another process and in order to do that it needs to serialize/deserialize the objects in the Bundle so that it can recreate them in the new process. It also needs to do this because Android saves the contents of the Intent in some system tables so that it can regenerate the Intent if it needs to later.
为了将 Bundle
序列化为字节流,它会遍历 bundle 中的映射并获取每个键/值对.然后它获取每个值"(它是某种对象)并尝试确定它是什么类型的对象,以便它可以以最有效的方式序列化它.为此,它会根据已知对象类型 列表检查对象类型.已知对象类型"列表包含诸如 Integer
、Long
、String
、Map
、 之类的内容捆绑
,不幸的是还有List
.因此,如果对象是 List
(其中有许多不同的种类,包括 LinkedList
),它会将其序列化并将其标记为 List类型的对象代码>.
In order to serialize the Bundle
into a byte stream, it goes through the map in the bundle and gets each key/value pair. Then it takes each "value" (which is some kind of object) and tries to determine what kind of object it is so that it can serialize it in the most efficient way. To do this, it checks the object type against a list of known object types. The list of "known object types" contains things like Integer
, Long
, String
, Map
, Bundle
and unfortunately also List
. So if the object is a List
(of which there are many different kinds, including LinkedList
) it serializes it and marks it as an object of type List
.
当 Bundle
被反序列化时,即:当你这样做时:
When the Bundle
is deserialized, ie: when you do this:
LinkedList<Item> items = (LinkedList<Item>)
getIntent().getSerializableExtra(AppConstants.KEY_ITEMS);
它为List
类型的Bundle
中的所有对象生成一个ArrayList
.
it produces an ArrayList
for all objects in the Bundle
of type List
.
您实际上无法改变 Android 的这种行为.至少现在你知道它为什么这样做了.
There isn't really anything you can do to change this behaviour of Android. At least now you know why it does this.
只是为了让您知道:我实际上编写了一个小型测试程序来验证此行为,并且我查看了 Parcel.writeValue(Object v)
的源代码,这是被调用的方法来自 Bundle
当它把地图转换成字节流时.
Just so that you know: I actually wrote a small test program to verify this behaviour and I have looked at the source code for Parcel.writeValue(Object v)
which is the method that gets called from Bundle
when it converts the map into a byte stream.
重要提示:由于 List
是一个接口,这意味着任何实现 List
的类都可以放入 Bundle
将作为 ArrayList
出现.同样有趣的是,Map
也在已知对象类型"列表中,这意味着无论您将哪种 Map
对象放入 Bundle
(例如 TreeMap
、SortedMap
或任何实现 Map
接口的类),您将始终获得一个 HashMap
把它弄出来.
Important Note: Since List
is an interface this means that any class that implements List
that you put into a Bundle
will come out as an ArrayList
.
It is also interesting that Map
is also in the list of "known object types" which means that no matter what kind of Map
object you put into a Bundle
(for example TreeMap
, SortedMap
, or any class that implements the Map
interface), you will always get a HashMap
out of it.
这篇关于在下一个活动中检索时,放入 Intent extra 的 LinkedList 会重新转换为 ArrayList的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!