簡體   English   中英

保存和還原對象引用

[英]Saving and restoring object references

我知道我可以通過可序列化和可打包的方式保存和恢復對象狀態,但是如果這些對象相互引用了怎么辦? 他們的關系會恢復嗎?

例如,如果我的活動有對象A和對象B,並且

對象A對對象B的引用
對象B對對象A的引用

在還原對象A時,它將重新創建對象B的實例。
在還原對象B時,它將重新創建對象A的實例。

因此,該關系不再有效。 他們不再互相引用。

我如何保持這種關系,而不必持久化並將它們鏈接到SQLite數據庫中?

Parcelable接口的“常規”實現會將其所有字段寫入地塊,包括其他對象(它們本身會將其字段寫入地塊)。 因此,通常,當您保存然后恢復實例狀態時,所有對象關系都將就位。

在需要保存/恢復的對象之間的循環引用的特殊情況下,您仍然可以使用Parcelable但您必須自定義寫入/讀取邏輯以解決循環引用。

考慮以下最小活動,該活動定義一個Parcelable類,並嘗試保存/恢復該類的兩個實例,每個實例互相引用:

 public class MainActivity extends AppCompatActivity { private static final String KEY_FIRST = "MainActivity.KEY_FIRST"; private static final String KEY_SECOND = "MainActivity.KEY_SECOND"; private MyParcelable first; private MyParcelable second; @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putParcelable(KEY_FIRST, first); outState.putParcelable(KEY_SECOND, second); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (savedInstanceState != null) { first = savedInstanceState.getParcelable(KEY_FIRST); second = savedInstanceState.getParcelable(KEY_SECOND); } else { first = new MyParcelable("first name"); second = new MyParcelable("second name"); first.companion = second; second.companion = first; } } private static class MyParcelable implements Parcelable { public static final Creator<MyParcelable> CREATOR = new Creator<MyParcelable>() { @Override public MyParcelable createFromParcel(Parcel in) { return new MyParcelable(in); } @Override public MyParcelable[] newArray(int size) { return new MyParcelable[size]; } }; private String name; private MyParcelable companion; public MyParcelable(String name) { this.name = name; this.companion = null; } private MyParcelable(Parcel in) { this.name = in.readString(); this.companion = in.readParcelable(MyParcelable.class.getClassLoader()); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(name); dest.writeParcelable(companion, flags); } @Override public int describeContents() { return 0; } } } 

如果運行此活動並旋轉手機,則會發現兩個MyParcelable對象已成功保存和還原,包括它們彼此之間的引用。 但是 ,如果將應用程序StackOverflowError后台,則會出現StackOverflowError

 01-09 00:21:35.100 17941 17941 D Error : ERR: exClass=java.lang.StackOverflowError 01-09 00:21:35.101 17941 17941 D Error : ERR: exMsg=stack size 8MB 01-09 00:21:35.101 17941 17941 D Error : ERR: file=AbstractStringBuilder.java 01-09 00:21:35.101 17941 17941 D Error : ERR: class=java.lang.AbstractStringBuilder 01-09 00:21:35.101 17941 17941 D Error : ERR: method=expandCapacity line=130 01-09 00:21:35.148 17941 17952 W art : Suspending all threads took: 23.362ms 01-09 00:21:35.164 17941 17941 D Error : ERR: stack=java.lang.StackOverflowError: stack size 8MB 

這是很合理的。 outState.putParcelable(KEY_FIRST, first)將調用writeToParcel() ,該方法將執行dest.writeParcelable(companion, flags) ,該方法將writeToParcel()調用writeToParcel() ,依此類推。

解決方案是使用我們第一次構造對象時所使用的相同模式來構造我們的保存和恢復:不要序列化(讀取:寫入包裹)“伴侶”對象,並手動將它們重新連接在一起恢復它們之后:

 public class MainActivity extends AppCompatActivity { private static final String KEY_FIRST = "MainActivity.KEY_FIRST"; private static final String KEY_SECOND = "MainActivity.KEY_SECOND"; private MyParcelable first; private MyParcelable second; @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putParcelable(KEY_FIRST, first); outState.putParcelable(KEY_SECOND, second); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (savedInstanceState != null) { first = savedInstanceState.getParcelable(KEY_FIRST); second = savedInstanceState.getParcelable(KEY_SECOND); } else { first = new MyParcelable("first name"); second = new MyParcelable("second name"); } first.companion = second; second.companion = first; } private static class MyParcelable implements Parcelable { public static final Creator<MyParcelable> CREATOR = new Creator<MyParcelable>() { @Override public MyParcelable createFromParcel(Parcel in) { return new MyParcelable(in); } @Override public MyParcelable[] newArray(int size) { return new MyParcelable[size]; } }; private String name; private MyParcelable companion; public MyParcelable(String name) { this.name = name; this.companion = null; } private MyParcelable(Parcel in) { this.name = in.readString(); this.companion = null; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(name); // do not parcel the companion object } @Override public int describeContents() { return 0; } } } 

請注意,如果您在此類的兩個實例之間沒有循環引用,則此解決方案可能會引起問題。 畢竟,包裹某物的正常行為是將其所有結構都寫入包裹中。 在這里,我們有意省略某些東西以解決特殊情況。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM