【问题标题】:Dialog problem: requestFeature() must be called before adding content对话框问题:添加内容前必须调用requestFeature()
【发布时间】:2025-12-31 09:05:08
【问题描述】:

我正在创建一个包含 EditText 的自定义对话框,以便我可以从用户那里获取文本数据:

final EditText newKey = (EditText) findViewById(R.id.dialog_result);
AlertDialog.Builder keyBuilder = new AlertDialog.Builder(StegDroid.this);
keyBuilder
.setCancelable(false)
.setPositiveButton("Try Again", new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dialog, int id) {
        Log.v("Dialog","New Key: "+newKey.getText().toString());
    }
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
       public void onClick(DialogInterface dialog, int id) {
            dialog.cancel();
       }
   });
AlertDialog dialog = keyBuilder.create();
dialog.setTitle("Decryption Failed");
dialog.setContentView(R.layout.decrypt_failed_dialog);
dialog.show();

但是我总是遇到这个异常:

01-11 18:49:00.507: ERROR/AndroidRuntime(3461): android.util.AndroidRuntimeException: requestFeature() must be called before adding content
01-11 18:49:00.507: ERROR/AndroidRuntime(3461):     at com.android.internal.policy.impl.PhoneWindow.requestFeature(PhoneWindow.java:181)
01-11 18:49:00.507: ERROR/AndroidRuntime(3461):     at com.android.internal.app.AlertController.installContent(AlertController.java:199)
01-11 18:49:00.507: ERROR/AndroidRuntime(3461):     at android.app.AlertDialog.onCreate(AlertDialog.java:251)

...

dialog.show() 的行。我应该怎么做才能摆脱这种情况?

【问题讨论】:

    标签: android dialog


    【解决方案1】:

    您需要在创建对话框之前设置自定义视图。如果您使用AlertDialog 为您提供的默认正负按钮,您还需要使用setView(View) 而不是setContentView()

    final EditText newKey = (EditText) findViewById(R.id.dialog_result);
    AlertDialog.Builder keyBuilder = new AlertDialog.Builder(StegDroid.this);
    keyBuilder
    .setCancelable(false)
    .setPositiveButton("Try Again", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
            Log.v("Dialog","New Key: "+newKey.getText().toString());
        }
    })
    .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int id) {
                dialog.cancel();
           }
       });
    keyBuilder.setTitle("Decryption Failed");
    keyBuilder.setView(getLayoutInflater().inflate(R.layout.decrypt_failed_dialog, null));
    AlertDialog dialog = keyBuilder.create();
    dialog.show();
    

    【讨论】:

    • 最好添加注释,以便其他人无需比较代码即可轻松找出不同之处。
    • 你是对的,伙计...我现在没有时间。您介意编辑答案以使其更准确吗?
    • 谢谢!你用“......你需要使用 setView(View) 而不是 setContentView()......”来拯救我的一天 :)
    • @Cristian 这样使用时,不显示正负按钮。有什么想法吗?
    【解决方案2】:

    还要确保您没有返回已显示的对话框。例如,ProgressDialog 有一个方便的静态方法show(),它接受一些参数并返回一个ProgressDialog。事实证明,您不能使用该方法并返回结果 ProgressDialog,因为当操作系统尝试显示它(并且它已经显示)时,它会抛出同样的异常。

    也要注意:在 Android 模拟器上会遇到上述行为,但它实际上并没有引发异常,并且在运行 2.2 的 Droid Incredible 上运行良好。

    【讨论】:

      【解决方案3】:

      大约一年前我遇到了这个问题,并使用奇怪的代码修复了它。同样,我正在开发的应用程序有一个片段应该在手机上正常显示,但在平板电脑上的对话中。我是这样解决的:

      public class MyDialogFragment extends DialogFragment {
          private View mLayout;
          private ViewGroup mContainer;
      
          @Nullable
          @Override
          public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
              mContainer = container;
              if (getShowsDialog()) {
                  // one could return null here, or be nice and call super()
                  return super.onCreateView(inflater, container, savedInstanceState);
              }
              return getLayout(inflater, container);
          }
      
          private View getLayout(LayoutInflater inflater, ViewGroup container) {
              mLayout = inflater.inflate(R.layout.my_layout, container, false);
              return mLayout;
          }
      
          @Override
          public Dialog onCreateDialog(Bundle savedInstanceState) {
              return new AlertDialog.Builder(getContext())
                      .setPositiveButton(R.string.ok, null)
                      .setNegativeButton(R.string.cancel, null)
                      .setNeutralButton(R.string.filter_clear_selection, null)
                      .setView(getLayout(LayoutInflater.from(getContext()), mContainer))
                      .create()
                  ;
          }
      }
      

      这使我可以将我的片段添加为任何普通片段(在布局中),但也可以将其显示为自动运行的对话框。

      【讨论】:

        【解决方案4】:

        对于那些在使用DialogFragment 时特别遇到此问题的人。

        就我而言,这是因为我错误地扩展了 DialogFragment 类。我在onCreateView() 上返回了一个视图,并且还在onCreateDialog() 上返回了一个自定义对话框。文档指出:

        您可能有一个 UI 设计,您希望其中的一部分 UI 在某些情况下显示为对话框,但显示为全屏或 在其他人中嵌入片段(可能取决于设备是否 是大屏还是小屏)。 DialogFragment 类提供 你这种灵活性,因为它仍然可以作为一个可嵌入的 片段。

        但是,您不能使用 AlertDialog.Builder 或其他 Dialog 对象来 在这种情况下构建对话框。如果您希望 DialogFragment 是 可嵌入的,您必须在布局中定义对话框的 UI,然后加载 onCreateView() 回调中的布局。

        通过不在onCreateDialog() 上创建任何东西(仅返回超类实现)解决了问题。

        【讨论】:

          【解决方案5】:

          我的应用中有一个警报对话框,它曾经在 android API 23 上给我这个 android 运行时异常。

          原来这个问题与导入有关。我在导入中将android.app.AlertDialog 更改为androidx.appcompat.app.AlertDialog,问题就解决了。

          这适用于使用 AndroidX Artifacts 的项目。如果您不使用 AndroidX,请考虑使用支持版本 android.support.v7.app.AlertDialog

          【讨论】:

            【解决方案6】:

            我遇到了类似的问题。但是我的对话框是为 IME 显示的。当我切换到 Dialog 而不是 AlertDialog 并省略 create 时,该程序为我工作。

            【讨论】:

              【解决方案7】:

              如果您尝试在 onCreate() 之前使用 findViewById() 访问任何视图项,也会发生这种情况。在我的情况下,我就是这样做的:

               private class ShareViaDialog extends Dialog  {
               private ImageView mainSmallIcon = findViewById(R.id.mainSmallIcon);    //this is wrong
                @Override
                      protected void onCreate(Bundle savedInstanceState) {
                          requestWindowFeature(Window.FEATURE_NO_TITLE);
                          super.onCreate(savedInstanceState);
              }}
              

              所以避免这个错误的正确方法是:

               private class ShareViaDialog extends Dialog  {
                   private ImageView mainSmallIcon;
                    @Override
                          protected void onCreate(Bundle savedInstanceState) {
                              requestWindowFeature(Window.FEATURE_NO_TITLE);
                              super.onCreate(savedInstanceState);
              mainSmallIcon = findViewById(R.id.mainSmallIcon); //should be here
                  }}
              

              【讨论】:

                【解决方案8】:

                我在使用 DialogFragment 时也收到此错误消息。

                当我在onCreateDialog(Bundle savedInstanceState) 中更改了我返回的对话框时,我的问题得到了解决

                来自

                android.appAlertDialog

                androidx.appcompat.app.AlertDialog

                (或者如果你还没有迁移到 AndroidX,那么android.support.v7.app.AlertDialog

                【讨论】:

                  【解决方案9】:

                  解决这个问题的具体方法:

                  requestFeature(int)Window 的一个方法。你必须导入这个类 (android.view.Window)。

                  你必须得到AlertDialog.Builder对象的Window。然后拨打requestFeature(int)。入参为Window常量。

                  keyBuilder.getWindow().requestFeature(Window.FEATURE_ACTION_BAR);

                  【讨论】: