2012-07-06 98 views
0

我不知道如何管理對話框而不使用configChanges來指定要手動處理方向更改。 因此,可以說,你有這樣的AndroidManifest:爲什麼不會在onDestroy或onPause中解僱Dialog,removeDialog或dialog.dismiss工作?

<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
    package="com.example.testandroid" 
    android:versionCode="1" 
    android:versionName="1.0" > 

    <uses-sdk 
     android:minSdkVersion="8" 
     android:targetSdkVersion="15" /> 

    <application 
     android:icon="@drawable/ic_launcher" 
     android:label="@string/app_name" 
     android:theme="@style/AppTheme" > 
     <activity 
      android:name=".MainActivity" 
      android:label="@string/title_activity_main" > 
      <intent-filter> 
       <action android:name="android.intent.action.MAIN" />  
       <category android:name="android.intent.category.LAUNCHER" /> 
      </intent-filter> 
     </activity> 
    </application>  
</manifest> 

藉此MainActivity.java:

package com.example.testandroid; 

import android.app.Activity; 
import android.app.AlertDialog; 
import android.app.AlertDialog.Builder; 
import android.app.Dialog; 
import android.os.Bundle; 
import android.util.Log; 
import android.view.Menu; 
import android.view.View; 

public class MainActivity extends Activity { 
    private final static String TAG = "MainActivity"; 
    Dialog mDialog = null; 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     Log.d(TAG, "onCreate"); 
     setContentView(R.layout.activity_main); 
    }  
    public void doShowDialog(View b) { 
     Log.d(TAG, "doShowDialog"); 
     showDialog(1); 
    } 

    private void tryDismiss() { 
     Log.d(TAG, "tryDismiss"); 
     try {   
      dismissDialog(1); 
      removeDialog(1); 
      mDialog.dismiss(); 
     } catch(IllegalArgumentException ex) { 
      Log.e(TAG, ex.getMessage()); 
     } 
    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     getMenuInflater().inflate(R.menu.activity_main, menu); 
     return true; 
    } 

    @Override 
    protected void onPause() { 
     tryDismiss(); 
     super.onPause(); 
     Log.d(TAG, "onPause"); 

    } 
    @Override 
    protected Dialog onCreateDialog(int dialog) { 
     Builder b = new AlertDialog.Builder(this); 
     b.setTitle("Hello").setMessage("Waiting.."); 
     mDialog = b.create(); 
     return mDialog; 

    }  
} 

和這個佈局(main.xml中)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:tools="http://schemas.android.com/tools" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
android:orientation="vertical" 
> 
    <Button 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="Open Dialog" 
     android:onClick="doShowDialog" 
     /> 

</LinearLayout> 

它似乎沒有不重要的是,如果您從onDestroy或onPause調用,對話框將在方向切換後顯示備份。但爲什麼?我告訴它走開。如果調用removeDialog/dismissDialog,則在方向更改之前調用它時不執行任何操作。我無法弄清楚爲什麼會這樣。擺脫的唯一途徑這是我所知道的是處理方向通過

android:configChanges="keyboardHidden|orientation" 

我知道工作的新方法是使用FragmentDialog東西,我還沒有升級到尚未改變自己和我不準備重寫我的整個應用程序。看起來很奇怪,這不起作用。

這只是我在我的應用程序中的用戶可以從遠程服務器請求某些數據(以更新微調器的數據)的實際問題的示例,並且如果它們切換方向,則加載對話框將永遠不會消失,除了使用android:configChanges選項處理方向更改之外,似乎還沒有解決此問題的方法。我可以做,但我必須這樣做似乎很荒謬。

- 更新 - 刪除了按鈕以關閉對話框,因爲它沒有必要,並且由於對話框位於頂部,因此無法單擊它。

要重現剛剛啓動的應用程序,請單擊打開對話框的按鈕,然後旋轉手機。

+0

請清楚地瞭解你的重現步驟。你加載它的肖像。點擊按鈕顯示對話框,然後點擊停止對話框,然後切換到橫向並顯示出來? – 2012-07-06 20:03:16

+0

沒有看到您將參數分配給doDismiss(l)的位置?你是如何初始化的?這個價值是什麼? – 2012-07-06 20:05:13

+0

您是否設置了斷點以確定這些方法正在被調用?檢查參數是否真的與您創建的對話框匹配。 – 2012-07-06 20:06:42

回答

2

你的對話保存在onSaveInstanceState,所以它推出之前,你可以嘗試貶:

@Override 
protected void onSaveInstanceState(Bundle state) 
{ 
    tryDismiss(); 
    super.onSaveInstanceState(state); 
} 

此外,我真的不明白爲什麼要使用活動的onCreateDialog管理對話框。它的設計原因是自動處理方向更改。如果你想手動處理它,爲什麼你不使用對話框的功能?不要使用showDialog(id)onCreateDialog(id)直接啓動它,它將不會在旋轉屏幕後重新出現。

Builder b = new AlertDialog.Builder(this); 
    b.setTitle("Hello").setMessage("Waiting.."); 
    Dialog mDialog = b.create(); 
    mDialog.show(); // <----- 
+0

是的showDialog(id)和onCreateDialog(id)在方向更改時發生問題。更好,如果我們去@Sebastian Nowak回答 – Dharmendra 2012-07-09 14:21:42

+0

同時創建對話框的全局實例,並在onDestroy()方法中使用類似if(dialog!= null && dialog.isShowing()){dialog.dismiss();} – Dharmendra 2012-07-09 14:23:34

+0

雖然我不明白這個想法。在調用dismissDialog或removeDialog的方向改變不起作用後,所以看起來android會爲你處理對話框做一件非常糟糕的工作。 – 2012-07-09 15:21:34

1

塞巴斯蒂安得到它,但我想解釋一下情況了一下,我的對話框上的發現,因爲它可以相當混亂:

  1. 塞巴斯蒂安穿上它,你必須調用dismissDialog/removeDialog from onSaveInstanceState如果您希望對話框在旋轉之前消失。
  2. 雖然您可以從onCreate創建對話框,但如果您在方向 更改之前沒有關閉該對話框,則當活動重新啓動時,您將無法在onCreate方法中關閉該對話框。你必須從onPostCreate
  3. 調用dismissDialog並未onRestoreInstanceState工作方向更改後如叫dismissDialog。我之前和調用super.onRestoreInstanceState後試圖和既不工作(以爲它會因爲dimissing的onSaveInstanceState中發生)

比這更重要的是,我學會了,如果你正在做一些異步任務,如HTTP調用,並且您有一個內部類,它包含一個將在任務完成時運行的回調函數,您需要注意,如果旋轉屏幕,那麼內部類方法將包含對外部Activity類的原始實例的引用。這對我來說並不是很明顯,因爲我實際上沒有使用AsyncTask,因爲許多其他人遇到問題(我正在使用異步http庫)。

以一個小例子類似我真正的代碼:

 public class MyActivity extends Activity { 
    private static MyActivity sThis; 

    @Override 
    public void onCreate(Bundle state) { 
     super.onCreate(state); 
     sThis = this; 
     doAsyncWork(); 
    } 

    @Override 
    public void onDestroy() { 
     super.onDestroy(); 
     sThis = null; 
    } 
    private void doAsyncWork() { 
     showDialog(LOADING_DIALOG); 
     ExampleAsyncWorker.work(new AsyncWorkerCallback() { 
      @Override 
      public void onWorkComplete() { 
      dismissDialog(LOADING_DIALOG); //doesn't work if orientation change happened. 
      }   
     }); 
    } 
} 

上面的代碼,通過CategoryManager,連接到外部服務器,下載類別列表,一旦它是完整的呼叫onCategoriesObtained然後onFetchComplete(爲簡潔起見,還刪除了一些錯誤處理回調函數)。如果在fetchCategories調用和onFetchComplete之間發生方向更改,那麼在onFetchComplete中調用dismissDialog將無法工作。原因是這個內部類有一個隱式引用,它是在方向改變之前創建的Activity類的原始實例。因此,當您調用dismissDialog時,您將在原始實例上調用它,而不是新的實例,這將導致dismissDialog失敗,並顯示以下消息:「沒有任何與ID爲1的對話框曾經通過Activity#showDialog顯示」。我也沒搞清楚,解決的辦法,但它有點黑客:

在你的Activity類,包括靜態參考參考,並設置它的onCreate和空它的onDestroy,並使用該參考從你的內部類如下:

public class MyActivity extends Activity { 
    private static MyActivity sThis; 

    @Override 
    public void onCreate(Bundle state) { 
     super.onCreate(state); 
     sThis = this; 
     doAsyncWork(); 
    } 

    @Override 
    public void onDestroy() { 
     super.onDestroy(); 
     sThis = null; 
    } 
    private void doAsyncWork() { 
     showDialog(LOADING_DIALOG); 
     ExampleAsyncWorker.work(new AsyncWorkerCallback() { 
      @Override 
      public void onWorkComplete() { 
       sThis.dismissDialog(LOADING_DIALOG); 
      }   
     }); 
    } 
} 

請注意,我不知道這是一個偉大的做法,但它對我很有用。我知道在涉及外部類的活動(泄漏上下文)中可能存在內部類的問題,所以可能有更好的方法來解決這個問題。

-1

創建你的應用程序沒有savedinstace你可以使用super.onCreate(null);

0

AFAIK,這個泄漏窗口可以通過兩種方式處理。

@Override 
public void onDestroy(){ 
    super.onDestroy(); 
    if (Dialog!=null && Dialog.isShowing()){ 
     Dialog.dismiss(); 
    } 
} 

或者

if(getActivity()!= null && !getActivity().isFinishing()){ 
      Dialog.show(); 
} 

這裏Dailog是你的進步/警報dailog

相關問題