Java 当自定义alertdialog具有打开的微调器时,处理方向更改的正确方法是什么?

Java 当自定义alertdialog具有打开的微调器时,处理方向更改的正确方法是什么?,java,android,Java,Android,在我的应用程序中,我有一个自定义AlertDialog(由系统使用showDialog()处理),其中包含一个带有2个选项卡的tabhost。其中一个选项卡中有一个微调器。只要微调器未打开(显示微调器对话框),我就可以毫无问题地旋转屏幕。如果旋转期间微调器打开,我会得到以下结果: FATAL EXCEPTION: main java.lang.IllegalArgumentException: View not attached to window manager at android.

在我的应用程序中,我有一个自定义AlertDialog(由系统使用showDialog()处理),其中包含一个带有2个选项卡的tabhost。其中一个选项卡中有一个微调器。只要微调器未打开(显示微调器对话框),我就可以毫无问题地旋转屏幕。如果旋转期间微调器打开,我会得到以下结果:

FATAL EXCEPTION: main
java.lang.IllegalArgumentException: View not attached to window manager
    at android.view.WindowManagerImpl.findViewLocked(WindowManagerImpl.java:355)
    at android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:200)
    at android.view.Window$LocalWindowManager.removeView(Window.java:432)
    at android.app.Dialog.dismissDialog(Dialog.java:278)
    at android.app.Dialog.access$000(Dialog.java:71)
    at android.app.Dialog$1.run(Dialog.java:111)
    at android.app.Dialog.dismiss(Dialog.java:268)
    at android.widget.Spinner.onDetachedFromWindow(Spinner.java:89)
    at android.view.View.dispatchDetachedFromWindow(View.java:6173)
    at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:1164)
    at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:1162)
    at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:1162)
    at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:1162)
    at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:1162)
    at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:1162)
    at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:1162)
    at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:1162)
    at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:1162)
    at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:1162)
    at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:1162)
    at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:1162)
    at android.view.ViewRoot.dispatchDetachedFromWindow(ViewRoot.java:1746)
    at android.view.ViewRoot.doDie(ViewRoot.java:2757)
    at android.view.ViewRoot.handleMessage(ViewRoot.java:1995)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:130)
    at android.app.ActivityThread.main(ActivityThread.java:3683)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
    at dalvik.system.NativeStart.main(Native Method)
所以

1-是否可以在
onPause()
期间以编程方式关闭微调器

2-我是否应该使用不同的方法

3-如果没有合适的解决方案,我如何捕获这个特殊的异常?(我知道这是一个糟糕的做法,但崩溃需要停止,而且由于活动在被破坏后会正确地自我重建,所以无论如何都没关系

…为了所有神圣的东西,请不要建议我在我的活动声明中添加
android:configChanges=“orientation”
。这让我惊讶的是,它经常被接受为正式解决所有的定向问题

编辑其他信息

以下是我的对话框创建代码供参考:

static final int ID_DIALOG_CHOOSER = 1;
int pref_location;
private Dialog dialog;

...

protected Dialog onCreateDialog(int id)
{
    switch(id)
    {
    case ID_DIALOG_CHOOSER:
        dialog = show(ID_DIALOG_CHOOSER);
        break;
    }
    return dialog;
}

...

showDialog(DialogView.ID_DIALOG_CHOOSER);

...

Dialog show(final int dialogType) 
{
    if (dialogType == ID_DIALOG_CHOOSER)
    {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);

        // inflate tabhost layout
        View tabHostLayout = (View) inflater.inflate(R.layout.tabhost_layout, null);
        FrameLayout tabContent = (FrameLayout) tabHostLayout.findViewById(android.R.id.tabcontent);

        // inflate tab content layouts and add to tabhost layout
        LinearLayout tab1 = (LinearLayout) inflater.inflate(R.layout.dialog_tab1, null);
        tabContent.addView(tab1);
        LinearLayout tab2 = (LinearLayout) inflater.inflate(R.layout.dialog_tab2, null);
        tabContent.addView(tab2);

        // tab setup
        TabHost tabHost = (TabHost) tabHostLayout.findViewById(R.id.TabHost_Dialog_Tabs);
        tabHost.setup();

        TabHost.TabSpec tab_1 = tabHost.newTabSpec("Category 1");
        tab_1.setContent(R.id.LinearLayout_Dialog_Tab1_Content);
        tab_1.setIndicator(this.getResources().getString(R.string.dialog_tab1), this.getResources().getDrawable(R.drawable.tabhost_icon_selector));
        tabHost.addTab(tab_1);

        TabHost.TabSpec tab_2 = tabHost.newTabSpec("Category 2");
        tab_2.setContent(R.id.LinearLayout_Dialog_Tab2_Content);
        tab_2.setIndicator(this.getResources().getString(R.string.dialog_tab2), this.getResources().getDrawable(R.drawable.tabhost_icon_selector));
        tabHost.addTab(tab_2);

        // spinner setup
        final Spinner spinner_location = (Spinner) tab1.findViewById(R.id.Spinner_Dialog_Location);
        String[] locationArrayVals = null;
        ArrayAdapter<CharSequence> adapter_location = null;
        locationArrayVals = this.getResources().getStringArray(R.array.location_array_vals);
        adapter_location = ArrayAdapter.createFromResource(this, R.array.location_array_listdisplay, android.R.layout.simple_spinner_item);
        adapter_location.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinner_location.setAdapter(adapter_location);

        // ok button
        Button button_ok = (Button) tab1.findViewById(R.id.Button_Dialog_OK);
        button_ok.setOnClickListener(new View.OnClickListener() 
        {
            public void onClick(View view) 
            {
                pref_location = spinner_location.getSelectedItemPosition();
                dialog.dismiss();
            }
        });

        // create dialog
        builder.setTitle("Location")
        .setView(tabHost)
        .setCancelable(true);
        dialog = builder.create();
    }
    return dialog;
}

就像我说的,一个解决方法。仍在研究解决方案。:/

好的,我想我已经发现了您的问题:
对话框。discouse();


您正在做一件非常奇怪的事情—您正在通过“活动”创建对话框,但对其说“关闭”而不是“活动”来关闭它—这是两种不同的方法,您不能混合使用。您应该选择一种方法:dialog.show和dialog.dislose或activity.showDialog()和activity.dismissDialog()我也遇到过类似的崩溃。我通过在显示对话框时禁用方向更改来解决问题

@Override
public void onDismiss(DialogInterface dialog) {
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}

@Override
public void onShow(DialogInterface dialog) {
    int loadedOrientation = getResources().getConfiguration().orientation;
    int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
    if (loadedOrientation == Configuration.ORIENTATION_LANDSCAPE) {
        requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
    } else if (loadedOrientation == Configuration.ORIENTATION_PORTRAIT) {
        requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
    }
    setRequestedOrientation(requestedOrientation);
}

注意:事实上,我发现没有可靠的方法来解决这个问题。

我找到了一个更好的解决方案。用一个外观和行为都像微调器的按钮来替换微调器其实并不难(幸运的是,崩溃除外)


您是否尝试过此方法:showDialog(DIALOG\u暂停\u ID);在DIALOG教程中提到:是-我的对话框由“活动”管理。可以提供用于显示和取消对话框的代码吗?如果您说您使用DIALOG.dismise(),那么您使用的不是activity.showDialog(DIALOG\u NAME)方法,而是DIALOG.show()。我很抱歉-我在使用dialog.Disclose进行其他操作,因此忽略该部分。我已编辑了我的问题,以包含对话框创建代码。(我省略了另一个选项卡的代码,因为它只是文本)作为记录,这在一年后仍然是一个问题,即使有“新的和改进的”通过DialogFragment显示对话框的方法。我最终使用了您捕获异常的解决方法。这是有意义的,但当我将代码更改为使用
dismissDialog()时
I get
java.lang.IllegalArgumentException:没有通过活动显示id为1的对话框#showDialog
。id为1是正确的id,但为什么它认为该对话框从未显示过?(顺便说一句,这是在任何方向更改之前-我只是打开该对话框,并用“确定”按钮将其关闭以测试该对话框)当我尝试@Override showDialog()时,eclipse将其标记为
无法覆盖活动中的最终方法
。我应该将其放在哪里?检查活动文档。这取决于您的android版本。如果API级别为8或更高,则应使用showDialog(int-id,Bundle-args)如果您使用片段,那么应该使用FragmentDialog。教程并不总是更新,但文档是:)我希望随时支持方向更改,但这是一种有趣的方法。谢谢你给我举个例子,你让我不再头疼了。
@Override
public void onDismiss(DialogInterface dialog) {
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}

@Override
public void onShow(DialogInterface dialog) {
    int loadedOrientation = getResources().getConfiguration().orientation;
    int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
    if (loadedOrientation == Configuration.ORIENTATION_LANDSCAPE) {
        requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
    } else if (loadedOrientation == Configuration.ORIENTATION_PORTRAIT) {
        requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
    }
    setRequestedOrientation(requestedOrientation);
}
<Button 
     android:background="@android:drawable/btn_dropdown" 
     android:gravity="left|center_vertical"
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" />
public void showSpinner() {
    AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
    builder.setTitle(_spinnerPrompt);
    builder.setSingleChoiceItems(_spinnerOptions, _spinnerSelection,
      new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int item) {
            _spinnerSelection = item;
            _pseudoSpinner.setText(_spinnerOptions[item]);
            _restoreSpinnerOnRestart = false;
            dialog.dismiss();
        }
    });
    builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
        @Override
        public void onCancel(DialogInterface dialog) {
            _restoreSpinnerOnRestart = false;
        }
    });
    AlertDialog alert = builder.create();
    _restoreSpinnerOnRestart = true;
    alert.show();
    }

@Override
public Bundle onSaveInstanceState() {
    Bundle state = super.onSaveInstanceState();
    state.putBoolean(STATE_SPINNER_RESTORE, _restoreSpinnerOnRestart);
    state.putInt(STATE_SPINNER_SELECTION, _spinnerSelection);
    return state;
};

@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    _spinnerSelection = savedInstanceState.getInt(STATE_SPINNER_SELECTION, -1);
    _restoreSpinnerOnRestart = savedInstanceState.getBoolean(STATE_SPINNER_RESTORE);
    _pseudoSpinner.setText(_spinnerOptions[_spinnerSelection]);

    if (_restoreSpinnerOnRestart) {
        showSpinner();
    }
};