如何用ViewModel传递AlertDialog Fragment的结果?
问题:替代废弃API的简易DialogFragment结果回调方式
我有一个自定义DialogFragment,原本通过Intent和父组件通信,但用到的onActivityResult、getTargetFragment等方法已经废弃。我知道有新方法可以替代,但只是要获取Yes/No的结果,犯不上大费周章!有没有更简单的实现方式?我尝试用ViewModel但没成功!
我尝试的ViewModel代码
AlertDialogViewModel.java
import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.ViewModel; public class AlertDialogViewModel extends ViewModel { private final MutableLiveData<Boolean> mAlertDialogResult = new MutableLiveData(); public LiveData<Boolean> getAlertDialogResult() { return mAlertDialogResult; } public void setAlertDialogResult(boolean mResult) { mAlertDialogResult.setValue(mResult); } }
MyAlertDialog.java
public class MyAlertDialog extends DialogFragment { AlertDialogViewModel mViewModel; @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { return new MaterialAlertDialogBuilder(requireContext()) .setTitle(Title) .setMessage(MESSAGE) .setPositiveButton("YES", (d, b) -> onResult(true)) .setNegativeButton("NO", (d, b) -> onResult(false)) .create(); } private void onResult(boolean result) { mViewModel.setAlertDialogResult(result); } public static void showResult(Fragment fragment) { MyAlertDialog dialog = new MyAlertDialog(); dialog.show(fragment.getParentFragmentManager(), null); } }
调用代码
MyAlertDialog.showResult(this); AlertDialogViewModel model = new ViewModelProvider(this).get(AlertDialogViewModel.class); model.getAlertDialogResult().observe(this, result-> { Toast.makeText(this, ""+result, Toast.LENGTH_SHORT).show(); });
问题分析
你的ViewModel方案失效的原因有两个:
- ViewModel未初始化:DialogFragment里的
mViewModel没有赋值,调用setAlertDialogResult时会直接空指针。 - ViewModel作用域不共享:如果在DialogFragment里单独初始化ViewModel,默认会创建属于自己的实例,和宿主Fragment/Activity的ViewModel不是同一个,导致宿主观察不到结果。
两种简易解决方案
方案一:修复ViewModel共享逻辑
修改MyAlertDialog,让它使用宿主的ViewModelStoreOwner:
public class MyAlertDialog extends DialogFragment { private AlertDialogViewModel mViewModel; @Override public void onAttach(@NonNull Context context) { super.onAttach(context); // 使用宿主的ViewModelStoreOwner,保证和宿主共享同一个ViewModel实例 mViewModel = new ViewModelProvider(requireParentFragment()).get(AlertDialogViewModel.class); // 如果是和Activity共享,就用: // mViewModel = new ViewModelProvider(requireActivity()).get(AlertDialogViewModel.class); } @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { return new MaterialAlertDialogBuilder(requireContext()) .setTitle("标题") .setMessage("提示内容") .setPositiveButton("YES", (d, b) -> { mViewModel.setAlertDialogResult(true); dismiss(); }) .setNegativeButton("NO", (d, b) -> { mViewModel.setAlertDialogResult(false); dismiss(); }) .create(); } public static void showResult(Fragment fragment) { MyAlertDialog dialog = new MyAlertDialog(); dialog.show(fragment.getParentFragmentManager(), "MyAlertDialog"); } }
调用逻辑不变,现在宿主就能正确观察到结果了。
方案二:更轻量的接口回调
如果只是需要Yes/No的简单结果,接口回调比ViewModel更直接,完全不需要额外依赖:
- 定义回调接口:
public interface AlertDialogCallback { void onDialogResult(boolean isPositive); }
- 修改MyAlertDialog:
public class MyAlertDialog extends DialogFragment { private AlertDialogCallback mCallback; // 绑定回调,确保宿主实现了接口 @Override public void onAttach(@NonNull Context context) { super.onAttach(context); try { mCallback = (AlertDialogCallback) requireParentFragment(); // 如果是和Activity绑定,就用: // mCallback = (AlertDialogCallback) requireActivity(); } catch (ClassCastException e) { throw new ClassCastException("宿主必须实现AlertDialogCallback接口"); } } @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { return new MaterialAlertDialogBuilder(requireContext()) .setTitle("标题") .setMessage("提示内容") .setPositiveButton("YES", (d, b) -> { mCallback.onDialogResult(true); dismiss(); }) .setNegativeButton("NO", (d, b) -> { mCallback.onDialogResult(false); dismiss(); }) .create(); } public static void showResult(Fragment fragment) { MyAlertDialog dialog = new MyAlertDialog(); dialog.show(fragment.getParentFragmentManager(), "MyAlertDialog"); } }
- 宿主实现接口并调用:
public class HostFragment extends Fragment implements AlertDialogCallback { // ... 其他代码 private void showDialog() { MyAlertDialog.showResult(this); } @Override public void onDialogResult(boolean isPositive) { Toast.makeText(getContext(), isPositive ? "YES" : "NO", Toast.LENGTH_SHORT).show(); } }
这个方案代码更少,逻辑更直观,完全满足你“简单获取Yes/No结果”的需求。
内容的提问来源于stack exchange,提问作者user21193451
相关产品推荐
相关产品推荐

