2014-10-09 63 views
4

我有CustomDialog類延伸DialogFragment.我覆蓋onCreateDialog方法,以獲得我想要的自定義對話框。Android聽衆序列化

@Override 
public Dialog onCreateDialog(Bundle savedInstanceState) { 
    dialog = new Dialog(activity, styleId); 
    view = activity.getLayoutInflater().inflate(layoutId, null); 
    dialog.setContentView(view); 
    if (listener != null) { 
     listener.onViewInit(view, this); 
    } 
    return dialog; 

} 

這是自定義對話框創建代碼。在查看充氣後,我調用OnViewInitListener類型的偵聽器方法listener.onViewInit(view, this),它是接口並擴展了Serializable,將自定義代碼綁定到視圖(查看文本,偵聽器等),以便旋轉時我想要失去按鈕按下邏輯。

@Override 
public void onSaveInstanceState(Bundle bundle) { 
    bundle.putInt("layoutId", layoutId); 
    bundle.putInt("styleId", styleId); 
    bundle.putSerializable("listener", listener); 
    super.onSaveInstanceState(bundle); 

} 

public RsCustomDialog setOnListenerAssignment(OnViewInitListener listener) { 
    this.listener = listener; 
    return this; 
} 

當我實現了從活動OnViewInitListener,在方向改變的東西如預期: onCreateDialog被稱爲每次片段重新創建,和療法都沒有包裹的錯誤,但是當我按應用歷史按鈕(最右邊) android buttons

我得到這個錯誤:

10-09 11:09:38.256: E/AndroidRuntime(24153): FATAL EXCEPTION: main 
10-09 11:09:38.256: E/AndroidRuntime(24153): java.lang.RuntimeException: Parcelable encountered IOException writing serializable object (name = base.RsCustomDialog$OnClickListener) 
10-09 11:09:38.256: E/AndroidRuntime(24153): at android.os.Parcel.writeSerializable(Parcel.java:1279) 
10-09 11:09:38.256: E/AndroidRuntime(24153): at android.os.Parcel.writeValue(Parcel.java:1233) 
10-09 11:09:38.256: E/AndroidRuntime(24153): at android.os.Parcel.writeMapInternal(Parcel.java:591) 
10-09 11:09:38.256: E/AndroidRuntime(24153): at android.os.Bundle.writeToParcel(Bundle.java:1627) 
10-09 11:09:38.256: E/AndroidRuntime(24153): at android.os.Parcel.writeBundle(Parcel.java:605) 
10-09 11:09:38.256: E/AndroidRuntime(24153): at android.support.v4.app.FragmentState.writeToParcel(Fragment.java:133) 

我想這是因爲,當我實現OnViewInitListener從我的活動中,java隱式地將活動變量放在已實現的對象中,並且Parcel無法處理活動parcelation。

任何人都可以建議如何處理這個問題,或建議更好的解決方案。

回答

0

嗯,我解決了它!我所做的是我實現Parcable如下:

public abstract class OnClickListener implements DialogInterface.OnClickListener, Parcelable { 


@Override 
public abstract void onClick(DialogInterface dialog, int which); 

@Override 
public void writeToParcel(Parcel dest, int flags) { 

} 

@Override 
public int describeContents() { 
    return 0; 
} 

} 

所以我ConfirmDialog代碼保持不變:

@Override 
public Dialog onCreateDialog(Bundle savedInstanceState) { 
    return new AlertDialog.Builder(getActivity()).setTitle(title).setMessage(text).setPositiveButton(R.string.yes, onYes).setNegativeButton(R.string.no, onNo).create(); 

} 



@Override 
public void onSaveInstanceState(Bundle bundle) { 
    super.onSaveInstanceState(bundle); 
    bundle.putParcelable("onYes", onYes); 
    bundle.putParcelable("onNo", onNo); 
} 

唯一的限制是不使用自動變量不在onClickParcelable方法。 這裏是我的顯示這個對話框的例子:

 showConfirmDialog(getString(R.string.sure_want_to_exit), new base.dialog.OnClickListener() { 

     @Override 
     public void onClick(DialogInterface dialog, int which) { 
      ((NewProtocol) getCurrentActivity()).exit = true;    
      getCurrentActivity().finish(); 

     } 


    }, null); 

getCurrentActivity()是返回當前活動活動靜態方法。

+4

給包裹寫什麼都沒有收穫。這不是堅持或反序列化任何事情。當實例狀態恢復時,您需要從活動中設置偵聽器。不要堅持一無所有。這個答案比崩潰要糟糕得多,因爲它會在達到內存限制的邊緣情況下悄悄地破壞工作監聽器。這可能會導致巨大的錯誤在生產中被忽視。 – colintheshots 2017-05-09 03:05:45

+0

爲什麼它甚至可以工作?實際上,它也可以在沒有明確堅持onSaveInstanceState的情況下工作。 'getArguments()。getParcelable(「listener」)'總是返回傳遞給Bundle的同一個對象,而不管手機方向改變了多少次。 – 2017-11-20 22:17:36

1

您的OnViewInitListener應該是靜態的,可序列化的,並且具有所有可序列化的字段。如果你從它引用Activity,那麼你做錯了。爲了解決這個問題,你可以:

  1. 引用活動被創建時填充的靜態WeakReference變量中存儲的活動實例。
  2. 使用廣播接收器
  3. 當使用新的和正確的上下文恢復片段時,重新註冊監聽器。
+0

您好,感謝回覆!我可以告訴我已經從列表中檢查了1和3:1)我引用了來自靜態活動引用的變量,即BaseActivity中的變量。 3)我不想重新註冊聽衆,我的目標是註冊一次,然後忘掉它。在配置更改它應該會自動恢復監聽器。但是我總是在'CustomDialog'類中使用適當的上下文。 2-我不知道你的意思,它可以提供什麼幫助? – 2014-10-09 08:47:33

3

您不能序列化和恢復偵聽器。

序列化(包括使用Parcelable)保存的對象實例的狀態和反序列化該狀態到一個新的對象實例。

監聽器沒有狀態 - 這就是您的Parcelable實現不保存或恢復任何內容的原因。 listener變量是對對象實例(已知實現偵聽器接口的實例)的引用。如果創建了該對象的新實例(例如:由於旋轉或由於內存不足而終止進程),它不會幫助對話嘗試將指針恢復到以前的實例。前一個實例不再存在,並且在調用onSaveInstanceState時新創建的(正確的)實例不存在。

兩種可能的備選方案:

  • 如果監聽旨在是該對話被附接到活動,則可以在DialogFragment的onAttach方法被恢復
  • 如果不是,則活性可在創建(或重新創建)時設置Fragment偵聽器。爲了得到一個自動恢復片段實例的引用,可以使用getFragmentManager().findFragmentById(id)getFragmentManager().findFragmentByTag(tag)
+0

雖然第二個選項有點棘手,但如果重新創建了活動,它將會丟失任何存儲的偵聽器......除非它使用靜態變量存儲或存儲在應用程序中,但這不是好的做法... – Ixx 2017-05-19 09:57:34

+0

@lxx我同意,靜態變量不是一個好主意 - 不能想到應用程序實例也有意義的情況,但這並不意味着它不存在。我關於第二種選擇的想法是創建一個新的偵聽器實例或設置一個從FragmentManager檢索的片段實例作爲偵聽器。 – 2017-05-19 13:32:09

-1

您可以的onResume寫的東西和的onStop你聽者註銷中的onStop方法是什麼,登記的onResume方法

+0

這看起來比評論更多。 – LethalProgrammer 2017-06-10 09:18:16