在Android中将对象引用保存到Bundle

6
是否有可能在Bundle中保存一个对象的引用?
不是整个对象,而只是引用?
例如,Bundle类有获取对象的方法,但我找不到put或set方法。
我需要这个功能,因为在一个活动中,我创建了一个定时器类的实例,然后启动计时器:myTimer.start() 如果我必须重启该活动,则希望将计时器恢复到先前的值。

尝试 - 打包 -- 把 iBinder -- 放入 iBinder 中您的 obj - Artem
4个回答

6

希望您做不到这一点。您只能在bundle中存储原始数据类型。如Marcin Orlowski所提到的,“存储”整个对象可以通过实现Parcelable接口来实现。我所说的“存储”是指存储对象状态。实现此接口可帮助您在不反复将其所有属性放入Bundle对象的情况下,在不同的代码部分中持久化您的对象状态。

当活动进入暂停状态时,所有由您的活动使用的对象迟早都会被垃圾收集器删除,因此存储对它们的引用是愚蠢的。


所以,每次他们旋转设备我都需要重新创建每个对象吗? - Radioleao
实际上是的。因为在设备旋转期间,您的活动会被重新创建。 每个Activity和其他类都有一个名为onSaveInstanceState的方法,因此您可以在其中保存对象的状态,然后在onCreate方法中重新创建它们。如果您已经在onSaveInstance方法中保存了活动状态,则onCreate方法的Bundle参数不应为null。 但是,有一种方法可以避免在方向更改期间重新创建Activity-覆盖onConfigurationChanged方法并不允许调用其超级方法。看看这个:http://tinyurl.com/l3rooo7 - bpawlowski
我的答案太长了,所以我无法附加到适当的线程链接,这是链接:https://dev59.com/5l_Va4cB1Zd3GeqPQiVQ#8814650 - bpawlowski
非常感谢,太棒了!我明白最好的方法是刷新屏幕并处理它,但此时此刻我可以避免这个问题并继续学习。 - Radioleao
2
@Garet,为什么这很傻?对象也可以从其他地方引用(例如Application类),因此不一定在活动暂停时需要进行GC处理。 - AtomHeartFather
实际上,从BaseBundle类的源代码可以看出,Serializable / Parcelable对象与任何其他类型的对象一样保存为内部映射中的引用。然后整个bundle可能会(但不保证)在旋转时被打包成一个Parcel。但是在我的情况下并非如此。在旋转时,savedInstanceState没有被打包,因此对于新片段仍然保持不变,从而导致我在bundle中存储的复杂对象泄漏。即使它们是可打包的!真的很讨厌。 - WindRider

2

另一种方法是将POJO转换为JSON,然后使用GSON库将其转换为字符串,并将其作为字符串保存在bundle中。然后从bundle中以字符串形式检索它,并使用相同的GSON库将其转换回对象。以下是示例代码。

将JSON转换为字符串并将其保存在bundle中

JsonElement json = new JsonElement();
String result = gson.toJson(json);
bunlde.putString("key",result);

将Bundle中的字符串转换为对象

 JsonElement json = gson.fromJson(bundle.getString("key"), JsonElement.class);

2
官方文档建议在“配置更改”期间使用片段来存储引用(不,我不认为这意味着你需要将你的活动重构为一个片段,而是使用片段作为存储介质(需要澄清)):

http://developer.android.com/guide/topics/resources/runtime-changes.html#RetainingAnObject


在配置更改期间保留对象
如果重新启动您的活动需要恢复大量数据集、重新建立网络连接或执行其他密集操作,则由于配置更改而进行完全重启可能会导致用户体验缓慢。此外,系统使用 onSaveInstanceState() 回调保存的 Bundle 并不适用于携带大型对象(如位图),其中的数据必须进行序列化和反序列化,这可能会消耗大量内存并使配置更改变慢,因此可能无法完全恢复您的活动状态。在这种情况下,您可以通过在由于配置更改而重新启动时保留片段来减轻重新初始化活动的负担。这个片段可以包含对要保留的有状态对象的引用。
当 Android 系统由于配置更改关闭您的活动时,您标记为保留的活动片段不会被销毁。您可以将这些片段添加到您的活动中以保留有状态对象。
要在运行时配置更改期间在片段中保留有状态对象:
扩展 Fragment 类并声明对您的有状态对象的引用。创建片段时调用 setRetainInstance(boolean)。将片段添加到您的活动中。在重新启动活动时使用 FragmentManager 检索片段。例如,定义您的片段如下:
public class RetainedFragment extends Fragment {

    // data object we want to retain
    private MyDataObject data;

    // this method is only called once for this fragment
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // retain this fragment
        setRetainInstance(true);
    }

    public void setData(MyDataObject data) {
        this.data = data;
    }

    public MyDataObject getData() {
        return data;
    }
}

注意:虽然您可以存储任何对象,但永远不要传递与 Activity 相关联的对象,例如 Drawable、Adapter、View 或任何其他与 Context 相关联的对象。如果这样做,它将泄漏原始活动实例的所有视图和资源。(泄漏资源意味着您的应用程序保持对它们的控制,它们无法被垃圾回收,因此可能会丢失大量内存。)

2
你不能直接传递对象本身,只能传递有限的数据类型,可以通过查看文档中的方法列表(looking at method lists in the docs)来了解。如果想要传递单个原始数据类型以外的数据,则需要实现 Parcelable 接口(或使用类似 Parceler 的帮助程序)。完成这些操作后,就可以通过 Bundle 传递对象数据(但仍无法传递对象本身)。

2
那并没有真正回答问题,问题是关于存储对象的引用而不是对象本身。 - AtomHeartFather
Parcelable 用于存储对象,就像 Serializable 一样,但需要自己实现“编组”。它与 Java 如何管理对象无关。你已经解释了如何存储一个对象,而不是对它的引用,这正是问题所在。 - AtomHeartFather
如果你们中有任何人花费一点时间查看文档,那么为什么会清楚就很明显了。 - Marcin Orlowski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接