2011-08-02 14 views
6

在我的應用程序中,我有一個自定義AlertDialog(由系統使用showDialog()處理),其中包含一個帶有2個選項卡的tabhost。在其中一個標籤是一個微調。只要微調控制器未打開,我就可以旋轉屏幕而不會出現任何問題(顯示微調對話框)。如果旋轉器中打開時,我得到這個:當自定義alertdialog具有打開的微調器時,處理方向更改的正確方法是什麼?

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; 
} 

編輯與暫時的解決辦法

對於任何有興趣,我設法通過繼承微調和壓倒一切的onDetachedFromWindow()像這樣至少停止崩潰:

public static class CatchingSpinner extends Spinner 
{ 
    public CatchingSpinner(Context context, AttributeSet attrs) 
    { 
     super(context, attrs); 
    } 

    @Override 
    protected void onDetachedFromWindow() 
    { 
     try 
     { 
      super.onDetachedFromWindow(); 
     } 
     catch (IllegalArgumentException e) 
     { 
      // do whatever 
     } 
    } 
} 

就像我說的,一個解決辦法。仍在研究解決方案。 :/

+0

你嘗試這個方法:的ShowDialog(DIALOG_PAUSED_ID);在對話框教程中提到:http://developer.android.com/guide/topics/ui/dialogs.html – ania

+0

是的 - 我的對話框由活動管理。 – wirbly

+0

可以提供用於顯示和解除對話框的代碼嗎?如果你說你使用dialog.dismiss(),那麼你不是使用yourActivity.showDialog(DIALOG_NAME)方法,而是使用dialog.show()。 – ania

回答

1

好吧,我想我已經找到了自己的問題:dialog.dismiss();
你正在做的真是奇怪的事情 - 要創建活動,通過對話,但說要解僱它不活動,以消除它 - 這是兩個不同的你不能混用的方法。你應該選擇一個方法:dialog.show和dialog.dismiss或activity.showDialog()和activity.dismissDialog()< - 這是更好的,因爲處理方向改變。
你應該做的只是從類變量中刪除對話框,無處不在使用activity.showDialog。可能你的問題在於解僱onClick中的對話框。只需使用YourActivityName.this.dismissDialog(DIALOG_NUMBER),它應該可以工作。
瞭解更多關於對話形成的開發者網站 - 我也有過這樣的問題,並採取長的時間來了解它是如何工作的,但畢竟 - 對話都沒有這麼複雜;)

+0

這是有道理的,但是當我改變我的代碼使用'dismissDialog()'我得到了'java.lang.IllegalArgumentException:沒有對話與ID 1曾經通過活動#showDialog'顯示。 ID 1是正確的ID,但它爲什麼不認爲該對話框顯示過? (順便說一句,這是之前任何方向更改 - 我只是調出對話框,並用OK按鈕來解僱它來測試這個) – wirbly

+0

把@Override給showDialog :) – ania

+0

當我嘗試@Override showDialog()時,eclipse標記它作爲'不能覆蓋活動'最後的方法。我應該把它放在哪裏? – wirbly

1

我也有類似的崩潰。我在顯示對話框時通過禁用方向更改來解決問題。

@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); 
} 

注:我居然發現有以lock screen orientation沒有可靠的方法。

+0

我想始終支持方向更改,但這是一個有趣的方法。感謝這個例子。 – wirbly

3

我找到了更好的解決方案。實際上用一個外觀和行爲像Spinner的按鈕替換Spinner並不難(幸運的是除了崩潰)。

<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(); 
    } 
}; 
+0

你只是讓我從頭痛中解脫出來。 – NitroG42

相關問題