屏幕旋转后恢复对话框

Restoring a dialog after screen rotation

在屏幕旋转(纵向到横向或反之亦然)期间,我遇到了一个比尝试恢复 activity 中的错误对话框更重要的小问题。错误发生时对话框确实正确呈现,但在屏幕旋转时对话框未正确恢复。而是整个画面变得昏暗,什么都看不见。这是相关代码:

private void showErrorDialog() {
    // assume hasErrorDialog is true at this point
    AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(SomeActivity.this);
    LayoutInflater inflater = SomeActivity.this.getLayoutInflater();
    View dialogView = inflater.inflate(R.layout.dialog_alert, null);
    dialogBuilder.setView(dialogView);
    TextView msgText = (TextView) dialogView.findViewById(R.id.alertMessageText);
    msgText.setText("something went wrong");
    Button okButton = (Button) dialogView.findViewById(R.id.alertOkButton);
    okButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View arg0) {
            alertDialog.dismiss();
            hasErrorDialog = false;
        }
    });

    alertDialog = dialogBuilder.create();
    alertDialog.show();
    RelativeLayout rl = (RelativeLayout) findViewById(R.id.someActivity);
    int width = rl.getWidth();
    alertDialog.getWindow().setLayout((int) (0.9 * width), ViewGroup.LayoutParams.WRAP_CONTENT);
}

加载 activity 之后调用上述方法时,发生了错误,对话框加载并正常运行。所以上面的代码在正常情况下调用是完全有效的。

但是,我添加了使用保存的实例状态的逻辑来尝试 "remember" 实际上应该有一个错误对话框。旋转时,我尝试在检查此实例状态后再次调用上述方法:

protected void onSaveInstanceState(Bundle bundle) {
    super.onSaveInstanceState(bundle);

    bundle.putBoolean("HASERRORDIALOG", hasErrorDialog);
}

然后在 onCreate() 中我尝试检查此状态,如果存在,再次调用 showErrorDialog()

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.some_activity);

    if (savedInstanceState != null) {
        hasErrorDialog = savedInstanceState.getBoolean("HASERRORDIALOG");

        if (hasErrorDialog) {
            // this does not load the dialog correctly
            showErrorDialog();
        }
    }
}

我在 Stack Overflow 上阅读的大多数 questions/answers 通过建议使用 DialogFragment 来解决这个问题。虽然我愿意朝这个方向发展,但我想知道我当前的代码是否没有补救措施。

运行 @MikeM 的精彩评论,我意识到问题是我的 activity 的 RelativeLayout 尚未在 onCreate() 方法中完全创建,因此它的宽度不是我所期望的(可能为零)。

作为解决方法,我使用 getDisplayMetrics() 访问实际设备宽度,它在生命周期中调用 onCreate 时仍然存在:

alertDialog = dialogBuilder.create();
alertDialog.show();
int width = (int)(getResources().getDisplayMetrics().widthPixels*0.90);
alertDialog.getWindow().setLayout(width, ViewGroup.LayoutParams.WRAP_CONTENT);

这里要吸取的教训是,当对话框基于布局中的某些内容时,有一个潜在的警告。在这种情况下,在设备旋转后尝试在 onCreate 中恢复该对话框会失败,但这是一种可能的解决方法。