在下一个活动中检索时,放入 Intent extra 的 LinkedList 会重新转换为 ArrayList [英] LinkedList put into Intent extra gets recast to ArrayList when retrieving in next activity

查看:16
本文介绍了在下一个活动中检索时,放入 Intent extra 的 LinkedList 会重新转换为 ArrayList的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我观察到的将可序列化数据作为 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);

ActivityBonCreate 中,我尝试检索 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:

ExtrasIntent 基本上是一个 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 中的映射并获取每个键/值对.然后它获取每个值"(它是某种对象)并尝试确定它是什么类型的对象,以便它可以以最有效的方式序列化它.为此,它会根据已知对象类型 列表检查对象类型.已知对象类型"列表包含诸如 IntegerLongStringMap 之类的内容捆绑,不幸的是还有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(例如 TreeMapSortedMap 或任何实现 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆