Android 如何在从片段打开的自定义对话框上保留侦听器?
我遇到了一点障碍。我有一个非常类似于以下描述的场景: 建议的解决方案对作者来说效果很好,因为他的对话框是从活动中调用的。我的情况与此完全相同,但我的自定义对话框是从片段而不是从活动中调用的。(IE活动->片段->对话框) 我实现了相同的解决方案(在调用片段的onResume中设置侦听器),但在这种情况下不起作用 似乎正在发生的是,当屏幕旋转时,Android会杀死对话框和片段。然后按该顺序重新创建它们。因此,当在自定义对话框上调用onCreateDialog时,还需要重新创建包含的片段,因此监听器可以为正按钮和负按钮设置空值 有人知道怎么解决这个问题吗Android 如何在从片段打开的自定义对话框上保留侦听器?,android,android-fragments,android-lifecycle,android-dialogfragment,Android,Android Fragments,Android Lifecycle,Android Dialogfragment,我遇到了一点障碍。我有一个非常类似于以下描述的场景: 建议的解决方案对作者来说效果很好,因为他的对话框是从活动中调用的。我的情况与此完全相同,但我的自定义对话框是从片段而不是从活动中调用的。(IE活动->片段->对话框) 我实现了相同的解决方案(在调用片段的onResume中设置侦听器),但在这种情况下不起作用 似乎正在发生的是,当屏幕旋转时,Android会杀死对话框和片段。然后按该顺序重新创建它们。因此,当在自定义对话框上调用onCreateDialog时,还需要重新创建包含的片段,因此监听
public class RecipeDetailEditFragment extends SherlockFragment implements DialogInterface.OnClickListener {
private EditStepFragmentDialog stepDialog;
private Recipe newRecipe; //main data object implements parcelable
...
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
stepDialog = EditStepFragmentDialog.newInstance(newRecipe);
//I've also tried passing 'this' into the newInstance constructor and
//setting the listener there, but that doesn't work either
}
public void onResume() {
stepDialog.setListener(this);
super.onResume();
}
...
}
public class EditStepFragmentDialog extends DialogFragment {
private DialogInterface.OnClickListener ocl;
private static final String ARG_RECIPE = "recipe";
private Recipe recipe;
public EditStepFragmentDialog() {}
public static EditStepFragmentDialog newInstance(Recipe rec) { //(Recipe rec, DialogInterface.OnClickListener oc) as mentioned doesn't work.
EditStepFragmentDialog dia = new EditStepFragmentDialog();
Bundle args = new Bundle();
args.putParcelable(ARG_RECIPE, rec);
//dia.setListener(oc);
return dia;
}
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder adb = new AlertDialog.Builder(getActivity());
if (getArguments().containsKey(ARG_RECIPE)) {
recipe = (Recipe) getArguments().getParcelable(ARG_RECIPE);
}
...
adb.setPositiveButton("Done", ocl);
adb.setNegativeButton("Cancel", ocl);
...
return adb.create();
}
public void setListener(DialogInterface.OnClickListener cl) {
ocl = cl;
}
}
向您的活动报告并创建对话会是一场灾难吗 我只是查看了我的代码,看看我在做什么,因为我没有遇到这个问题。我对它的看法是这样的:
- MyActivity
|
---- MapsFragmet (for example)
|
---- DirectionsModule (simple class that is handed Context)
|
---- PointsOfInterestModule (simple class that is handed Context)
stepDialog = EditStepFragmentDialog.newInstance(getActivity(), newRecipe);
因此,在这种构造中,活动使用片段纯粹是为了显示地图,但可以将其用于方向或兴趣点,具体取决于调用的模块
现在,当模块遇到问题或需要用户交互时,它会向MyActivity报告,例如,MyActivity会显示一个DialogFragment
我想给出一个更好的答案,因为我不明白为什么您不能从另一个片段中调用DialogFragment并期望一个好的行为
以防万一,您是否在片段上设置了setRetainInstance(true)
编辑:
好的,我刚刚回顾了您新提交的代码,以下是我的新想法:
扩展对话框的参数以获取上下文,这样您就可以这样调用它:
- MyActivity
|
---- MapsFragmet (for example)
|
---- DirectionsModule (simple class that is handed Context)
|
---- PointsOfInterestModule (simple class that is handed Context)
stepDialog = EditStepFragmentDialog.newInstance(getActivity(), newRecipe);
接下来,在对话框中使用添加的上下文而不是getActivity():
AlertDialog.Builder adb = new AlertDialog.Builder(context);
我怀疑(对此不确定)SherlockFragment算作活动实例,因此当您在对话框中调用getActivity()时,它与您的片段相关联。我浏览了讨论链接上的所有选项,没有一个解决方案对我有效。在进一步谷歌搜索之后,我还尝试了一些其他选项,比如get/setTargetFragment和FragmentManager.put/getFragment。这些对我也不起作用。然后我又看了一眼: 他们明确表示“两个片段永远不应该直接交流”。我认为这是一个事实证明是正确的案例 我最终实现了此处提供的建议回调机制,并最终实现了以下内容: 在DialogFragment中:
public interface OnEditStepDialogListener {
public void onEditStepDialogPositive(int pos, String description);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mCallback = (OnEditStepDialogListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnEditStepDialogListener");
}
}
在托管活动中:
public class MyActivity extends SherlockFragmentActivity implements EditStepFragmentDialog.OnEditStepDialogListener {
...
@Override
public void onEditStepDialogPositive(int pos, String desc) {
FragmentManager fm = getSupportFragmentManager();
RecipeDetailEditFragment ef = (RecipeDetailEditFragment)fm.findFragmentByTag(RecipeDetailEditFragment.TAG);
ef.applyStepEdit(pos, desc);
}
在触发FragmentDialog的Fragment中:
public static final String TAG = "tag1";
public void applyStepEdit(int pos, String description) {
...
}
这非常有效,如果打开后方向更改和编辑完成,它实际上会触发我需要在调用片段中运行的最终函数,而不是崩溃或不执行任何操作(空侦听器)。您必须发布代码这不会是一场灾难,但我更喜欢一种解决方案,它允许一个片段对它自己触发的对话做出响应。如果没有其他人有更好的选择,我会认为这是最好的答案。我在片段上尝试过setRetainInstance,但似乎没有任何帮助。只是做了一次新的编辑(是否会自动通知您这一点?)。我很确定这与Listener问题的原因相同…对话框在片段之前被重新创建,因此,当它第一次运行onCreateDialog时,内部上下文对象还没有被设置…好的,现在我想我找到了一个解决方案:你需要向下滚动一点才能找到答案。你所指答案的海报是谁?在问这个问题之前,我看了这篇文章,从我能告诉你的大部分答案来看,重点是如何让你的保留实例包正常工作。侦听器是不可打包的,所以我的场景中没有考虑到这一点。很好,您找到了一个解决方案!只要一个小注释,就可以扩展片段,在创建时使用另一个参数,即OnEditStepDialogListener来处理回调,以防您不喜欢处理活动类中的每个回调。