我有CustomDialog
类扩展DialogFragment.
我覆盖onCreateDialog
方法,以获得我想要的自定义对话框。
@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;
}
这是自定义对话框创建代码。在视图膨胀之后,我调用类型为listener.onViewInit(view, this)
的侦听器方法OnViewInitListener
,它是接口并扩展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;
}
当我在Activity中实现OnViewInitListener
时,对于方向更改,事情按预期工作:
每次重新创建片段时都会调用onCreateDialog
,并且没有包裹错误,但是当我按下应用程序历史记录按钮时(在最右边)
我收到此错误:
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无法处理活动分解。
任何人都可以建议如何处理这个问题,或建议更好的解决方案。
答案 0 :(得分:6)
您无法序列化和恢复监听器。
序列化(包括使用Parcelable)保存对象实例的状态,反序列化将该状态放入新的对象实例中。
听众没有状态 - 这就是为什么您的Parcelable实施不会保存或恢复任何内容的原因。 listener变量是对对象实例的引用(已知实现侦听器接口的对象实例)。如果创建了该对象的新实例(例如:由于旋转或由于内存不足导致进程被终止),则对话框尝试将指针还原到上一个实例时没有任何帮助。先前的实例不再存在,并且在调用onSaveInstanceState
时新创建的(正确的)实例不存在。
两种可能的替代方案:
getFragmentManager().findFragmentById(id)
或getFragmentManager().findFragmentByTag(tag)
答案 1 :(得分:1)
你的OnViewInitListener应该是静态的和可序列化的,并且里面有所有可序列化的字段。如果您从中引用Activity,那么您就错了。要解决这个问题,您可以:
答案 2 :(得分:0)
你可以在onResume和onStop上写一些你在onStop方法中取消注册的内容,在onResume方法中注册
答案 3 :(得分:-1)
好吧,我解决了!我所做的是我实施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);
}
唯一的限制是不要在Parcelable
方法中使用非onClick
的自动变量。
这是我显示此对话框的示例:
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()
是返回当前活动活动的静态方法。