Android监听器序列化

Gio*_*ili 4 android dialog fragment parcel

我有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;

}
Run Code Online (Sandbox Code Playgroud)

这是自定义对话框创建代码.在视图膨胀之后,我调用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;
}
Run Code Online (Sandbox Code Playgroud)

当我OnViewInitListener从Activity 实现时,在方向更改时,事情按预期工作: onCreateDialog每次重新创建片段时都会调用,并且没有包裹错误,但是当我按下应用程序历史记录按钮时(在最右边) android按钮

我收到此错误:

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)
Run Code Online (Sandbox Code Playgroud)

我想这是因为,当我OnViewInitListener从我的活动中实现时,java隐式地将活动变量放在已实现的对象中,而Parcel无法处理Activity parcelation.

任何人都可以建议如何处理这个问题,或建议一个更好的解决方案.

Sta*_*iel 6

您无法序列化和还原侦听器.

序列化(包括使用Parcelable)保存对象实例的状态,反序列化将该状态放入新的对象实例中.

监听器没有状态 - 这就是您的Parcelable实现不保存或恢复任何内容的原因.listener变量是对对象实例的引用(已知实现侦听器接口的对象实例).如果创建了该对象的新实例(例如:由于旋转或由于内存不足导致进程被终止),则对话框尝试将指针还原到上一个实例时没有帮助.先前的实例不再存在,并且在onSaveInstanceState调用时,新创建的(正确的)实例不存在.

两种可能的选择:

  • 如果要将侦听器作为附加对话框的Activity,那么可以在DialogFragment的onAttach方法中恢复该侦听器
  • 如果没有,则Activity可以在创建(或重新创建)时设置Fragment侦听器.要获得对自动恢复的Fragment实例的引用,可以使用getFragmentManager().findFragmentById(id)或getFragmentManager().findFragmentByTag(tag)


Gio*_*ili -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;
    }
}
Run Code Online (Sandbox Code Playgroud)

所以我的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);
}
Run Code Online (Sandbox Code Playgroud)

唯一的限制是不要使用不在方法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);
Run Code Online (Sandbox Code Playgroud)

getCurrentActivity()是返回当前活动活动的静态方法。

  • 不向包裹写入任何内容对我们没有任何好处。这根本不是持久化或反序列化任何东西。当实例状态恢复时,您需要从活动中设置侦听器。不要保留指向任何内容的指针。这个答案比崩溃更糟糕,因为在达到内存限制的边缘情况下,它会默默地破坏正在工作的侦听器。这可能会导致生产中出现未被注意到的巨大错误。 (9认同)