所以我试图做的事情是,在ActivtyA中,我将一个LinkedList实例放入我为开始下一个活动而创建的意图 – ActivityB。
LinkedList<Item> items = (some operation); Intent intent = new Intent(this, ActivityB.class); intent.putExtra(AppConstants.KEY_ITEMS, items);
在ActivityB的onCreate中,我尝试如下检索LinkedList extra:
LinkedList<Item> items = (LinkedList<Item>) getIntent() .getSerializableExtra(AppConstants.KEY_ITEMS);
在运行这个时,我反复在ActivityB中得到一个ClassCastException,在上面的行。基本上,异常说我正在接收一个ArrayList。一旦我改变了上面的代码来接收一个ArrayList,一切都很好。
现在我不能从现有的文档中找出,无论这是传递可序列化列表实现时Android上的预期行为。或者也许,我在做什么有根本的错误。
谢谢。
我可以告诉你为什么会发生这种情况,但你不会喜欢它;-)首先有一点背景信息:
Intent中的附加功能基本上是一个Android Bundle,它基本上是一个键/值对的HashMap。所以当你做某事时
intent.putExtra(AppConstants.KEY_ITEMS, items);
Android为附加组件创建一个新的Bundle,并向Bundle添加一个映射条目,其中的关键是AppConstants.KEY_ITEMS,该值是items(它是您的LinkedList对象)。
这一切都很好,好的,如果你在代码执行后查看extras包,你会发现它包含一个LinkedList。现在有趣的部分…
当您使用额外的Intent调用startActivity()时,Android需要将附加组件从键/值对的映射转换为字节流。基本上它需要序列化捆绑。它需要这样做,因为它可能在另一个进程中启动活动,为了做到这一点,它需要对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);
它为List中的Bundle中的所有对象生成一个ArrayList。
改变Android的这种行为,你没有什么可以做的。至少现在你知道为什么这样做。
只是为了让你知道:我实际上写了一个小的测试程序来验证这个行为,我已经看过Parcel.writeValue(Object v)的源代码,这是从Bundle将它映射到一个字节时被调用的方法流。
重要提示:由于List是一个接口,这意味着任何实现List的类都将作为ArrayList出来。还有一点很有趣的是,Map也在“已知对象类型”的列表中,这意味着无论您放入Bundle的Map对象(例如TreeMap,SortedMap或实现Map界面的任何类),您都可以总是会得到一个HashMap。