2014-10-09 59 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