LinkedList的投入额外的意向得到重铸在接下来的活动中检索时,ArrayList的(Linke

2019-06-18 01:09发布

A型行为我正在观察WRT传递序列化的数据作为额外的意图是很奇怪的,我只是想澄清是否有什么东西我不会错过了。

所以,我试图做的事情是,在ActivtyA我把LinkedList实例为intent我开始下一个活动创造- ActivityB

LinkedList<Item> items = (some operation);
Intent intent = new Intent(this, ActivityB.class);
intent.putExtra(AppConstants.KEY_ITEMS, items);

onCreateActivityB ,我试图找回LinkedList额外如下-

LinkedList<Item> items = (LinkedList<Item>) getIntent()
                             .getSerializableExtra(AppConstants.KEY_ITEMS);

在运行此,我多次得到了ClassCastExceptionActivityB ,在上面就行了。 基本上,除了说我收到ArrayList 。 有一次,我改变了上面的代码,以获得一个ArrayList替代,一切工作就好了。

现在,我不能只从现有的文档弄清楚是否通过序列化List实现时,这是Android上的预期行为。 或许,有一些根本性的错误瓦特/我在做什么。

谢谢。

Answer 1:

我可以告诉你为什么会这样,但你不会喜欢它;-)

首先一点背景资料:

在一个附加 Intent基本上是一个Android Bundle这基本上是一个HashMap的键/值对。 所以,当你做这样的事情

intent.putExtra(AppConstants.KEY_ITEMS, items);

Android的创建一个新的Bundle的演员,并增加了一个映射条目的Bundle ,其中的关键是AppConstants.KEY_ITEMS和值是一个项目 (这是您的LinkedList的对象)。

这是一切优秀和良好的,如果你是看演员束代码执行后,你会发现它包含一个LinkedList 。 现在到了有趣的部分...

当你调用startActivity()与含有额外意图,Android的需要群众演员从地图键/值对转换成字节流。 基本上,它需要序列的捆绑 。 它需要做,因为它可能会在另一个进程开始的活动,为了做到这一点,需要进行序列化/反序列化被捆绑的对象,以便它可以在新的过程中重新创建它们。 它还需要做到这一点,因为Android的节省一些系统表的意图的内容,以便它可以重新生成意图是否需要更高版本。

为了序列的Bundle成字节流,它通过在所述束中的地图,并得到每个键/值对。 然后,它需要每一个“值”(这是一些类型的对象),并试图确定它是什么样的对象,以便它可以以最有效的方式对其进行序列化。 要做到这一点,它会检查与已知对象类型的列表中的对象类型。 “已知对象类型”列表中包含的东西IntegerLongStringMapBundle可惜还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 (例如TreeMapSortedMap ,或实现任何类Map界面),你总是会得到一个HashMap出来。



Answer 2:

通过回答@大卫瓦瑟是正确诊断问题的条款。 这篇文章是分享我如何处理它。

与任何的问题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;
    }
}

然后你可以使用这个隐藏你的ListMap或其他数据类型从Android的类型检查:

intent.putExtra(KEY, new Wrapper<>(items));

然后:

items = ((Wrapper<LinkedList<String>>) intent.getSerializableExtra(KEY)).get();


Answer 3:

如果您正在使用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