在安卓系统中防止屏幕旋转导致对话框消失

102

我正在尝试防止使用Alert builder构建的对话框在Activity重新启动时被取消。

如果我重载onConfigurationChanged方法,我可以成功地做到这一点,并将布局重置为正确的方向,但我会失去edittext的粘性文本功能。因此,在解决对话框问题时,我创建了这个edittext问题。

如果我保存edittext中的字符串,并在onCofiguration更改中重新分配它们,它们仍然似乎默认为旋转前输入的初始值。即使我强制无效也不会更新它们。

我真的需要解决对话框问题或edittext问题。

感谢您的帮助。


1
你如何保存/恢复编辑的EditText的内容?你能展示一些代码吗? - Peter Knego
我找到了问题所在,我在重置布局后忘记通过ID再次获取视图了。 - draksia
13个回答

0

如果没有任何帮助,而你需要一个可行的解决方案,你可以选择保险起见,每次打开对话框时将其基本信息保存到活动 ViewModel 中(并在关闭对话框时从此列表中删除)。这些基本信息可以是对话框类型和一些 ID(你需要打开此对话框的信息)。这个 ViewModel 在 Activity 生命周期的更改期间不会被销毁。假设用户打开一个对话框来留下对餐厅的评价。那么对话框类型将是 LeaveReferenceDialog,ID 将是餐厅 ID。当打开此对话框时,你将此信息保存在一个对象中,你可以称之为 DialogInfo,并将此对象添加到 Activity 的 ViewModel 中。这些信息将允许你在 onResume() 被调用时重新打开对话框:

// On resume in Activity
    override fun onResume() {
            super.onResume()
    
            // Restore dialogs that were open before activity went to background
            restoreDialogs()
        }

调用哪个函数:

    fun restoreDialogs() {
    mainActivityViewModel.setIsRestoringDialogs(true) // lock list in view model

    for (dialogInfo in mainActivityViewModel.openDialogs)
        openDialog(dialogInfo)

    mainActivityViewModel.setIsRestoringDialogs(false) // open lock
}

当ViewModel中的IsRestoringDialogs设置为true时,对话框信息将不会被添加到视图模型的列表中,这很重要,因为我们现在正在恢复已经在列表中的对话框。否则,在使用该列表时更改它会导致异常。因此:
// Create new dialog
        override fun openLeaveReferenceDialog(restaurantId: String) {
            var dialog = LeaveReferenceDialog()
            // Add id to dialog in bundle
            val bundle = Bundle()
            bundle.putString(Constants.RESTAURANT_ID, restaurantId)
            dialog.arguments = bundle
            dialog.show(supportFragmentManager, "")
        
            // Add dialog info to list of open dialogs
            addOpenDialogInfo(DialogInfo(LEAVE_REFERENCE_DIALOG, restaurantId))
    }

然后在关闭对话框时删除对话框信息:

// Dismiss dialog
override fun dismissLeaveReferenceDialog(Dialog dialog, id: String) {
   if (dialog?.isAdded()){
      dialog.dismiss()
      mainActivityViewModel.removeOpenDialog(LEAVE_REFERENCE_DIALOG, id)
   }
}

在Activity的ViewModel中:
fun addOpenDialogInfo(dialogInfo: DialogInfo){
    if (!isRestoringDialogs){
       val dialogWasInList = removeOpenDialog(dialogInfo.type, dialogInfo.id)
       openDialogs.add(dialogInfo)
     }
}


fun removeOpenDialog(type: Int, id: String) {
    if (!isRestoringDialogs)
       for (dialogInfo in openDialogs) 
         if (dialogInfo.type == type && dialogInfo.id == id) 
            openDialogs.remove(dialogInfo)
}

实际上,您重新打开了之前打开的所有对话框,顺序相同。但是它们如何保留其信息呢?每个对话框都有自己的 ViewModel,在活动生命周期期间也不会被销毁。因此,当您打开对话框时,您将获取 ViewModel,并像往常一样使用该对话框的 ViewModel 初始化 UI。

-1

是的,我同意使用@Brais Gabin提供的DialogFragment解决方案,只是想建议对他给出的解决方案进行一些更改。

在定义扩展DialogFragment的自定义类时,我们需要一些接口来管理最终由调用对话框的活动或片段处理的操作。但是,在onAttach(Context context)方法中设置这些侦听器接口有时可能会导致ClassCastException,从而导致应用程序崩溃。

因此,为了避免此异常,我们可以创建一个方法来设置侦听器接口,并在创建对话框片段对象后仅调用它。 以下是一个示例代码,可以帮助您更好地理解-

AlertRetryDialog.class

    public class AlertRetryDialog extends DialogFragment {

       public interface Listener{
         void onRetry();
         }

    Listener listener;

     public void setListener(Listener listener)
       {
       this.listener=listener;
       }

    @NonNull
    @Override
    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
    AlertDialog.Builder builder=new AlertDialog.Builder(getActivity());
    builder.setMessage("Please Check Your Network Connection").setPositiveButton("Retry", new 
    DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
             //Screen rotation will cause the listener to be null
            //Always do a null check of your interface listener before calling its method
            if(listener!=null&&listener instanceof HomeFragment)
            listener.onRetry();
        }
       }).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            dialog.dismiss();
         }
     });
     return builder.create();
    }

   }

在 Activity 或 Fragment 中调用 -

                   AlertRetryDialog alertRetryDialog = new AlertRetryDialog();
                    alertRetryDialog.setListener(HomeFragment.this);
                    alertRetryDialog.show(getFragmentManager(), "tag");

在你的Activity或Fragment中实现你的监听器接口的方法-

              public class YourActivity or YourFragment implements AlertRetryDialog.Listener{ 
                
                  //here's my listener interface's method
                    @Override
                    public void onRetry()
                    {
                     //your code for action
                      }
                
                 }

在调用任何监听器接口的方法之前,请始终确保对其进行空值检查,以防止出现NullPointerException(屏幕旋转会导致监听器接口为空)。

如果您发现此答案有帮助,请告诉我。谢谢。


-3

只需使用

ConfigurationChanges = Android.Content.PM.ConfigChanges.Orientation | Android.Content.PM.ConfigChanges.ScreenSize

应用程序将知道如何处理旋转和屏幕尺寸。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接