-1

我工作的一個Android的項目,我想自定義類MainActivityModel傳遞到FragmentMainActivityPlaceholderFragmentAndroid何時序列化對象?

我已MainActivityModel序列化:

public class MainActivityModel implements Serializable{ 

    public int current = 0; 
    public int pageCount = 0; 

    public boolean pristine = true; 

    // Stores the fetched dataMap 
    public ArrayList<HashMap<String, String>> arrayList; 

    public MainActivityModel() { 
     this.arrayList = new ArrayList<>(); 
    } 

    public String getCategory() { 
     return Util.categories[current]; 
    } 

    public CharSequence getmTitle() { 
     return Util.toTitleCase(
       Util.mapCategoryPretty(Util.categories[current])); 
    } 
} 

,我把它傳遞給Fragment這樣的:

public static MainActivityPlaceholderFragment newInstance(MainActivityModel mainActivityModel) { 
    MainActivityPlaceholderFragment fragment = new MainActivityPlaceholderFragment(); 
    Bundle args = new Bundle(); 
    args.putSerializable(ARG_DATA_MODEL, mainActivityModel); 
    fragment.setArguments(args); 
    Log.v(LOG_TAG, "Created: " + mainActivityModel.getmTitle()); 
    return fragment; 
} 

我訪問這樣的:

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    mainActivityModel = (MainActivityModel) getArguments().getSerializable(ARG_DATA_MODEL); 
    mMainActivityPlaceholderFragmentView = new MainActivityPlaceholderFragmentView(this, mainActivityModel); 

    mCallbacks.onPlaceholderFragmentCreated(mainActivityModel.current); 
} 

我最初認爲(在閱讀我在下面提到的答案後),,該序列化將數據轉換爲字節並在需要時將其恢復。。所以我的對象會被複制。這是好的,如果我只想訪問數據。但我也想從片段中修改實際模型(在MainActivity中引用)。

爲了進行實驗,我在片段中將pristine設置爲false,並將其記錄在MainActivity中,這確實是錯誤的。

但如果序列化是傳遞的價值,怎麼會這樣呢?

我讀過:

  1. What is object serialization?
  2. R: Pass by reference
  3. what is Serializable in Java
  4. What is serialization in Java?
+0

無論它是否可序列化都沒關係...... bundle無法處理引用的點......它總是序列化/反序列化(parcel/unparcel)......只是想一下這種情況:Activity with一些意圖去背景,甚至殺死你回到它......爲什麼它回到了意圖?它不是引用...系統只是將它保存到包裹並在需要時重新創建 – Selvin

+0

這是我的問題。如果它正在複製對象,那麼這些更改如何反映回MainActivity?這些更改應該僅限於片段。 – prakharsingh95

+0

@ prakharsingh95通過複製對象你明白什麼? –

回答

3

Serializable對象的引用仍然是對象引用,它與傳遞List對象或Foo對象沒有任何區別。令人困惑的部分是如果其中發生序列化。

android.app.Fragment.setArguments(Bundle)文檔:

這裏提供的參數將整個片段保留破壞和創造。

有兩種方法來實現這一目標:

  • Bundle只存儲原始字節,序列化/反序列化,每get/put操作。
  • 允許Bundle保存活動對象,並要求它在需要銷燬/重新創建片段時序列化/反序列化所有內容。

顯然,第一個選項是非常低效get/put操作遠比活動/片段生命週期的變化更加頻繁。因此,Android只會在需要的生命週期更改時序列化/反序列化

這會導致您的用例出現「怪異」行爲。你認爲你的Serializable對象是序列化的立即Bundle,而Bundle只是持有對你的對象的引用。由於newInstanceonCreate呼叫之間的碎片沒有被破壞,因此您會看到完全相同的Bundle,它們持有完全相同的參考。

當然,你應該不依賴在這些引用保持不變。任何時候,當你的應用程序被要求保持其狀態時(例如,當進入後臺,旋轉屏幕或者當系統需要釋放RAM時),這些對象被序列化並且引用消失。這些對象將從序列化數據中重新創建,但它們將具有不同的引用。

+1

對不起,我不得不...... **不依賴**在這裏是最重要的...我敢肯定它是某種最優化...並且可能不適用於某些API級別的「原始」片段 – Selvin

+0

好吧,Android可以做到這一點,爲什麼不能使用dooid只是讓我在包中存儲引用。我的對象的生命週期與父活動的生命週期相同。 – prakharsingh95

+0

正如此處所述(http://stackoverflow.com/a/14917265/3887393),無法將一個無法編組的對象存儲在一個包中 – prakharsingh95

0

在Java中所有的對象都是通過引用傳遞,只有原始類型(int ,float,long ...)是按值傳遞的。

我並不知道如何序列化的作品,但如果其轉換爲字節]這不是一個原始類型所以這就是爲什麼它是工作。

如果你寫一個Serializable類的文件,並將其作爲ASCII你會看到一種遞歸的toString(),其次是什麼也許可以是數據字節。

希望這會有所幫助。

0

序列化創建對象的深層副本,這意味着如果您序列化然後反序列化包含其他對象的對象,您將獲得新的獨立對象(帶有新引用),所有內容的副本,絕對沒有引用您仍然存在的對象堆在一起。因此,如果您修改剛剛反序列化的對象,則只會修改這些對象,而不是您可能在堆上進行的任何以前的引用。

如果你想reconciliate你剛纔反序列化與存儲的對象的引用,你必須編寫它。

+0

「如果你想協調引用,你剛剛用你的對象在內存中反序列化,你必須編寫它。」是。我很擔心,因爲我沒有這樣做,它仍然在工作。我想明白爲什麼。我還添加了如何在對問題的評論中驗證此行爲。 – prakharsingh95

+0

這可能是因爲java字符串行爲。字符串具有避免欺騙的特定分配系統。有一個內部的字符串池,如果你創建一個新的字符串對象,它會查看池,如果你的新字符串已經存在。如果存在,您將獲得對現有字符串的引用。由於字符串是不可變的,這不是問題。 –