18

我正在迁移当前使用的对话框,Activity.showDialog(DIALOG_ID);以使用 android 参考DialogFragment中讨论的系统。

在我的开发过程中,使用回调将某些事件传递回打开对话框的活动/片段时出现了一个问题:

这是一个简单对话框的一些示例代码:

public class DialogTest extends DialogFragment {

public interface DialogTestListener {
    public void onDialogPositiveClick(DialogFragment dialog);
}

// Use this instance of the interface to deliver action events
static DialogTestListener mListener;

public static DialogTest newInstance(Activity activity, int titleId, int messageId) {
    udateListener(activity);
    DialogTest frag = new DialogTest();
    Bundle args = new Bundle();
    args.putInt("titleId", titleId);
    args.putInt("messageId", messageId);
    frag.setArguments(args);
    return frag;
}

public static void udateListener(Activity activity) {
    try {
        // Instantiate the NoticeDialogListener so we can send events with it
        mListener = (DialogTestListener) activity;
    } catch (ClassCastException e) {
        // The activity doesn't implement the interface, throw exception
        throw new ClassCastException(activity.toString() + " must implement DialogTestListener");
    }
}


@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    int titleId = getArguments().getInt("titleId");
    int messageId = getArguments().getInt("messageId");

    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    // dialog title
    builder.setTitle(titleId);
    // dialog message
    builder.setMessage(messageId);

    // dialog negative button
    builder.setNegativeButton("No", new OnClickListener() {
               public void onClick(DialogInterface dialog, int id) {}});
    // dialog positive button
    builder.setPositiveButton("Yes", new OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
            mListener.onDialogPositiveClick(DialogTest.this);
        }});

    // create the Dialog object and return it
    return builder.create();
}}

这是一些调用它的活动代码:

public class SomeActivity extends FragmentActivity implements DialogTestListener {
private EditText mUserName;
@Override
public void onCreate(Bundle savedInstanceState) {
    // setup ui
    super.onCreate(savedInstanceState);
    setContentView(R.layout.ui_user_edit);
    // name input
    mUserName = (EditText) findViewById(R.id.userEdit_editTextName);
}

@Override
public void onDialogPositiveClick(DialogFragment dialog) {
    Log.d(TAG, this.toString());
    mUserName.setText(mUserName.getText() + "1");
}

private void showDialog() {
    DialogTest test = DialogTest.newInstance(SomeActivity.this, R.string.someTitleText, R.string.someMessageText);
    test.show(getSupportFragmentManager(), "testDialog");
}}

代码几乎就是您看到的参考。问题是,一旦您进行方向更改,当显示一个对话框时,它就会停止按预期工作-->由于活动生命周期,活动和对话框都被重建,对话框现在没有正确的参考新的重建活动。

我在我的活动 onResume 方法中添加了以下代码:

    @Override
protected void onResume() {
    super.onResume();
    DialogTest.udateListener(this);
}

这样做,我得到了预期的行为,当方向改变发生时,对话框将事件发送回新的重建活动。

我的问题是:在方向更改期间处理由 FragmentActivity 打开的 DialogFragment 之间的回调的“最佳实践”是什么?

最好的祝福

4

5 回答 5

15

有更好的解决方案,而不是使用静态方法和变量,因为它只适用于对话的一个实例。最好将回调存储为非静态成员

private DialogTestListener mListener;
public void setListener (DialogTestListener listener){
  mListener = listener;
}

然后你应该像这样使用 TAG 显示你的对话框mDialogFragment.show(getSupportFragmentManager(), DIALOG_TAG);

然后在onResume您的活动方法中,您可以重置您的听众

protected void onResume() {
   super.onResume();
   mDialogFragment = (CMFilterDialogFrg) getSupportFragmentManager().findFragmentByTag(DIALOG_TAG);
   if(mDialogFragment  != null){
       mDialogFragment.setListener(yourListener)
   }
}
于 2014-11-20T17:07:24.163 回答
9

是的,这是我自己一直陷入的常见陷阱。首先让我说,您的呼入解决方案DialogTest.udateListener()似乎onResume()完全适合我。

另一种方法是使用 aResultReceiver可以序列化为 a Parcelable

public class DialogTest extends DialogFragment {

public static DialogTest newInstance(ResultReceiver receiver, int titleId, int messageId) {
    DialogTest frag = new DialogTest();
    Bundle args = new Bundle();
    args.putParcelable("receiver", receiver);
    args.putInt("titleId", titleId);
    args.putInt("messageId", messageId);
    frag.setArguments(args);
    return frag;
}

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    int titleId = getArguments().getInt("titleId");
    int messageId = getArguments().getInt("messageId");
    ResultReceiver receiver = getArguments().getParcelable("receiver");

    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    // dialog title
    builder.setTitle(titleId);
    // dialog message
    builder.setMessage(messageId);

    // dialog negative button
    builder.setNegativeButton("No", new OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
            receiver.sendResult(Activity.RESULT_CANCEL, null);
        }});
    // dialog positive button
    builder.setPositiveButton("Yes", new OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
            receiver.sendResult(Activity.RESULT_OK, null);
        }});

    // create the Dialog object and return it
    return builder.create();
}}

然后您可以像这样处理 Receiver 中的所有内容:

protected void onReceiveResult(int resultCode, Bundle resultData) {
    if (getActivity() != null){
        // Handle result
    }
}

查看ResultReceiver 无法忍受屏幕旋转以获取更多详细信息。所以最后你可能仍然需要ResultReceiver用你的Activity. 唯一的区别是您ActivityDialogFragment.

于 2012-10-18T13:38:19.967 回答
4

虽然 André 的解决方案有效,但更好的解决方案是onAttach()Fragment.

private DialogTestListener mListener;

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    mListener = (DialogTestListener) activity;
}

使用此解决方案,您将不再需要传递ActivitynewInstance()你只需要确保Activity拥有你的Fragment是一个DialogTestListener. 您也不需要像在ResultReceiver解决方案中那样保存状态。

于 2014-09-22T21:28:39.577 回答
1

首先,调用setTargetFragmentfromFragmentParent到 start dialogFragmentdialogFragment用于getTargetFragment回调片段和返回数据。所有数据结果将onactivityresultFragmentParent

请点击此链接: 从 DialogFragment 接收结果

于 2014-03-05T07:46:00.477 回答
-7

另一种方法是您可以停止重新创建活动。您必须告诉 Android 您将自己处理方向更改,并且 android 不会重新创建您的活动。您需要将此活动添加到清单文件中:

android:configChanges="keyboardHidden|orientation"

如果不是这样,那么您可以按照 Google 的建议使用标准onSaveInstanceState()来保存您的状态并恢复使用。savedInstanceState

这是谷歌的官方指南:http: //developer.android.com/guide/components/activities.html#Lifecycle

如果你还没有,请通过它。它将真正帮助您进行 android 开发。

于 2012-10-10T15:54:23.400 回答