2010-07-11 123 views
13

我有一個List<CustomObject>(其中CustomObject來自外部庫 - 我無法對其進行更改)。我想保存在onSaveInstanceState(Bundle),但我似乎無法做到這一點。下面是我試過的選項:將自定義對象數組保存爲實例狀態

outState.putSerializable(KEY, (ArrayList<CustomObject>) myList); // because myList is instantiated as an ArrayList 
outState.putSerializable(KEY, myList.toArray()); 

兩個選項工作在手機上切換方向時(是的,onSaveInstanceState的切換方向時,叫 - 我在logcat中選中)。但是,當前活動嘗試啓動另一個活動(使用startActivity(Intent))時,Android會暫停當前活動並再次調用onSaveInstanceState()。這一次,它失敗了,出於某種原因,我不知道。可怕的是onSaveInstanceState()成功執行。堆棧跟蹤打印不指向任何我的代碼:

E/AndroidRuntime(23898): java.lang.RuntimeException: Parcel: unable to marshal value [email protected] 
E/AndroidRuntime(23898): at android.os.Parcel.writeValue(Parcel.java:1087) 
E/AndroidRuntime(23898): at android.os.Parcel.writeArray(Parcel.java:519) 
E/AndroidRuntime(23898): at android.os.Parcel.writeValue(Parcel.java:1072) 
E/AndroidRuntime(23898): at android.os.Parcel.writeMapInternal(Parcel.java:469) 
E/AndroidRuntime(23898): at android.os.Bundle.writeToParcel(Bundle.java:1445) 
E/AndroidRuntime(23898): at android.os.Parcel.writeBundle(Parcel.java:483) 
E/AndroidRuntime(23898): at android.app.ActivityManagerProxy.activityPaused(ActivityManagerNative.java:1427) 
E/AndroidRuntime(23898): at android.app.ActivityThread.handlePauseActivity(ActivityThread.java:3106) 
E/AndroidRuntime(23898): at android.app.ActivityThread.access$2400(ActivityThread.java:119) 
E/AndroidRuntime(23898): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1870) 
E/AndroidRuntime(23898): at android.os.Handler.dispatchMessage(Handler.java:99) 
E/AndroidRuntime(23898): at android.os.Looper.loop(Looper.java:123) 
E/AndroidRuntime(23898): at android.app.ActivityThread.main(ActivityThread.java:4363) 
E/AndroidRuntime(23898): at java.lang.reflect.Method.invokeNative(Native Method) 
E/AndroidRuntime(23898): at java.lang.reflect.Method.invoke(Method.java:521) 
E/AndroidRuntime(23898): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860) 
E/AndroidRuntime(23898): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618) 
E/AndroidRuntime(23898): at dalvik.system.NativeStart.main(Native Method) 

有什麼辦法來存儲自定義的情況下狀態的對象?

回答

6

讓您CustomObject實施Parcelable及用途:

outState.putParcelable(KEY, myList); 
onSaveInstanceState(outState); 

同時檢查this教程。

編輯 CommonsWare後評論:

如果您CustomObject沒有實現SerializableParcelable我會嘗試它包裹自己的對象中,並添加:

  • private void readObject(ObjectInputStream aStream) throws IOException, ClassNotFoundException { /*Your deserialization */ }
  • private void writeObject(ObjectOutputStream aStream) throws IOException { /*Your serialization */}
+3

菲利克斯表示,他不能修改'CustomObject'。 – CommonsWare 2010-07-11 13:30:25

+0

@CommonsWare:謝謝。我沒有注意到這一點。 – Macarse 2010-07-11 13:38:22

+0

我將此標記爲已接受,因爲這是我*將*去的路線。但是,我與圖書館的作者進行了交談,他們將會實施它。 – Felix 2010-07-11 20:20:03

5

您的List<CustomObject>是否由服務持有,並通過本地綁定模式讓您的活動可以訪問您的服務。

您不僅不必擔心在實例狀態下保留它,而且您可以更好地控制內存中這些對象的生存期。實例狀態生存期由Android控制; Service持有對象的時間由您控制。特別是如果CustomObject可能很大,或者列表可能很長,我寧願你有更大的控制RAM的消耗時間。

+0

你的意思是有一個始終不停的「服務」? – Macarse 2010-07-11 13:44:58

+0

只有1+活動在運行時纔會停止。一旦沒有更多的連接,它將關閉。你也可以使用一個自定義的'Application'對象,如果你願意的話 - 你失去了控制權,但沒有一個「服務」說謊。 – CommonsWare 2010-07-11 13:48:57

+0

@CommonsWare:我猜他想'Serialize'來保存它以備後用。如果手機重新啓動,使用該方法他將失去信息。 – Macarse 2010-07-11 14:04:46

1

如果這主要是爲了處理方位變化,Activity#onRetainNonConfigurationInstance()可以做你想做的嗎?

活動可以使用此API將廣泛的狀態從舊的活動實例傳播到新的活動實例,從加載的位圖到網絡連接,以均勻主動運行線程。請注意,您不應該傳播任何可能根據配置而改變的數據,包括從資源(例如字符串,佈局或drawable)加載的任何數據。

如果您試圖通過配置更改持久保存數據,此API無濟於事。

+0

+1,我知道'onRetainNonConfigurationInstance()',但不,這不是主要用於方向更改 – Felix 2010-07-11 20:22:03

-2

爲什麼不把對象保存到SD卡?你可以看到如何使用這個在我的博客>>http://androidworkz.com/2010/07/06/source-code-imageview-flipper-sd-card-scanner/

public void saveArray(String filename, String[] output_field) { 
     try { 
      FileOutputStream fos = new FileOutputStream(filename); 
      GZIPOutputStream gzos = new GZIPOutputStream(fos); 
      ObjectOutputStream out = new ObjectOutputStream(gzos); 
      out.writeObject(output_field); 
      out.flush(); 
      out.close(); 
     } 
     catch (IOException e) { 
      e.getStackTrace(); 
     } 
     } 

    public String[] loadArray(String filename) { 
      try { 
      FileInputStream fis = new FileInputStream(filename); 
      GZIPInputStream gzis = new GZIPInputStream(fis); 
      ObjectInputStream in = new ObjectInputStream(gzis); 
      String[] read_field = (String[])in.readObject(); 
      in.close(); 
      return read_field; 
      } 
      catch (Exception e) { 
       e.getStackTrace(); 
      } 
      return null; 
     } 
+1

因爲...我的對象是自定義的,不能被序列化以便存儲在SD卡上? – Felix 2010-07-13 11:43:53

+1

放鬆一下,一個downvote不是世界的盡頭。 – jjnguy 2010-07-20 18:28:01

0

據我所知,SavedInstanceState是爲了節約活動的UI配置(如標準的Android UI組件,如文本字段的例子,自動保存)。

如果要在不同的活動重新啓動之間保存自定義對象(這不適用於通過單擊後退按鈕由用戶啓動的活動完成,但它確實適用於例如方向更改)。使用下面的代碼保留的對象:

// maintain a reference to the EchoServer object when the activity is recreated 
@Override 
public Object onRetainNonConfigurationInstance() { 
    return <<your object of choice>>; 
} 

而且在OnCreate(束savedInstanceState)方法,然後你可以檢索對象:

// if there is a saved instance state, restore the state 
    if (savedInstanceState != null) { 
     <<yourObject>> = (<<your object's class) getLastNonConfigurationInstance(); 
+2

從API 13開始,onRetainNonConfigurationInstance方法已棄用。http://developer.android.com/reference/android/app/Activity.html#onRetainNonConfigurationInstance%28%29 – javahead76 2012-11-06 13:26:26