我正在迁移我的对话框,目前正在使用Activity.showDialog(DIALOG_ID);
,以使用android reference中讨论的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之间的回调的“最佳实践”是什么?
祝你好运
答案 0 :(得分:12)
有更好的解决方案,而不是使用静态方法和变量,因为它只适用于对话框的一个实例。最好将回调存储为非静态成员
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)
}
}
答案 1 :(得分:7)
是的,这是一个常见的陷阱我自己一直在堕落。首先,请允许我说,您在DialogTest.udateListener()
中调用onResume()
的解决方案似乎完全适合我。
另一种方法是使用可以序列化为ResultReceiver
的{{1}}:
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();
}}
查看ResultReceiver doesn't survire to screen rotation了解详情。因此,最后您可能仍需要使用protected void onReceiveResult(int resultCode, Bundle resultData) {
if (getActivity() != null){
// Handle result
}
}
重新连接ResultReceiver
。唯一的区别是您将Activity
与Activity
分开。
答案 2 :(得分:3)
虽然André的解决方案有效,但更好的解决方案是在Fragment
private DialogTestListener mListener;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mListener = (DialogTestListener) activity;
}
期间获取更新的活动。
Activity
使用此解决方案,您无需再传递newInstance()
中的Activity
。您只需确保拥有Fragment
的{{1}}为DialogTestListener
。您也不需要像ResultReceiver
解决方案那样保存状态。
答案 3 :(得分:1)
首先,从setTargetFragment
致电FragmentParent
以启动dialogFragment
。在dialogFragment
中使用getTargetFragment
来回调片段并返回数据。所有数据结果都将在onactivityresult
的{{1}}
答案 4 :(得分:-6)
另一种方法是您可以停止重新创建活动。您必须告诉Android您将自己处理方向更改并且android将不会重新创建您的活动。您需要将此活动添加到清单文件中:
android:configChanges="keyboardHidden|orientation"
如果不是这样,那么您可以使用标准onSaveInstanceState()
来保存您的状态,并使用Google推荐的savedInstanceState
进行恢复。
这是Google的官方指南: http://developer.android.com/guide/components/activities.html#Lifecycle
如果你还没有,请通过它。它将真正帮助你进行android开发。