style - android studio對話方塊




使用getApplication()作為上下文,拋出對話框“無法添加窗口-標記null不適用於應用程序” (16)

我的Activity正在嘗試創建一個需要Context作為參數的AlertDialog。 如果我使用:

AlertDialog.Builder builder = new AlertDialog.Builder(this);

然而,由於潛在的內存洩漏,當Activity被破壞並重新創建時,即使在像屏幕旋轉那樣簡單的情況下,我也不願意使用“this”作為上下文。 來自Android開發者博客上的相關文章

有兩種簡單的方法可以避免與上下文相關的內存洩漏。 最明顯的一點是避免脫離其範圍以外的背景。 上面的例子顯示了一個靜態引用的情況,但內部類和它們對外部類的隱式引用可能同樣危險。 第二種解決方案是使用應用程序上下文。 只要您的應用程序處於活動狀態並且不依賴於活動的生命週期,此上下文就會生效。 如果您打算保留需要上下文的長壽命對象,請記住應用程序對象。 您可以通過調用Context.getApplicationContext()或Activity.getApplication()輕鬆獲得它。

但是對於AlertDialog() getApplicationContext()getApplication()都不能作為Context使用,因為它會引發異常:

“無法添加窗口 - 標記null不適用於應用程序”

每篇參考文獻: 1

所以,如果這真的被認為是一個“錯誤”,因為我們被正式建議使用Activity.getApplication() ,但它不起作用的廣告?

吉姆


您不能通過不是活動或服務上下文顯示應用程序window/dialog 。 嘗試傳遞有效的活動參考


使用MyDialog md = new MyDialog(MyActivity.this.getParent());


加入

dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

清單中的"android.permission.SYSTEM_ALERT_WINDOW"/>

現在它適用於我。 在關閉並打開應用程序後,當時給了我錯誤。


嘗試使用將在對話框下的活動的上下文。 但在使用“this”關鍵字時請小心,因為它不會每次都有效。

例如,如果您將TabActivity作為帶有兩個選項卡的主機,並且每個選項卡都是另一個活動,並且您嘗試從其中一個選項卡(活動)創建對話框,並且如果使用“this”,則會得到異常,在此案例對話框應該連接到託管所有東西並可見的主機活動。 (你可以說最可見的父Activity的上下文)

我沒有從任何文檔中找到這個信息,而是通過嘗試。 這是我的解決方案,沒有強大的背景,如果有更好的知名人士,隨時發表評論。


在我的案例中:

this.getContext();

在新的AlertDialog.Builder(getParent());上下文的參數位置嘗試getParent(); 希望它能起作用,它對我有用。


如果你不在Activity中,那麼你需要在你的函數“NameOfMyActivity.this”中使用Activity活動,例如:

public static void showDialog(Activity activity) {
        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
        builder.setMessage("Your Message")
        .setPositiveButton("Yes", dialogClickListener)
        .setNegativeButton("No", dialogClickListener).show();
}


//Outside your Activity
showDialog(NameOfMyActivity.this);

如果您正在使用片段並使用AlertDialog / Toast消息,請在上下文參數中使用getActivity()

為我工作。

乾杯!


對於未來的讀者,這應該有所幫助:

public void show() {
    if(mContext instanceof Activity) {
        Activity activity = (Activity) mContext;
        if (!activity.isFinishing() && !activity.isDestroyed()) {
            dialog.show();
        }
    }
}

小黑客:你可以防止GC破壞活動(當然,你不應該這樣做,但它可以在某些情況下有所幫助):

public class PostActivity extends Activity  {
    ...
    private Context contextForDialog = null;
    ...
    public void onCreate(Bundle savedInstanceState) {
        ...
        contextForDialog = this;
    }
    ...
    private void showAnimatedDialog() {
        mSpinner = new Dialog(contextForDialog);
        mSpinner.setContentView(new MySpinner(contextForDialog));
        mSpinner.show();
    }
    ...
}

您的對話框不應該是“需要上下文的長期對象”。 文檔很混亂。 基本上,如果你做了這樣的事情:

static Dialog sDialog;

(注意靜態

然後在某個地方做一個活動

 sDialog = new Dialog(this);

在旋轉或類似的過程中,您可能會洩露原始活動,從而破壞活動。 (除非你在onDestroy中清理,但在這種情況下,你可能不會讓Dialog對象成為靜態的)

對於某些數據結構,將它們設置為靜態並基於應用程序的上下文是有意義的,但通常不適用於與UI相關的對象,如對話框。 所以像這樣:

Dialog mDialog;

...

mDialog = new Dialog(this);

是好的,不應該洩漏活動,因為mDialog會被釋放,因為它不是靜態的。


我在一個片段中使用ProgressDialog ,並在傳遞getActivity().getApplicationContext()作為構造函數參數時出現此錯誤。 將其更改為getActivity().getBaseContext()也不起作用。

為我工作的解決方案是通過getActivity() ; 即

progressDialog = new ProgressDialog(getActivity());


我認為這可能會發生,如果你試圖從一個不是主UI線程的線程顯示一個對話框。

在這種情況下使用runOnUiThread()。


或者另一種可能性是創建Dialog如下:

final Dialog dialog = new Dialog(new ContextThemeWrapper(
            this, R.style.MyThemeDialog));

看看API之後,如果你在一個片段中,你可以傳遞對話你的activity或getActivity,然後在返回方法中用dialog.dismiss()強制清理它以防止洩漏。

雖然在我知道的任何地方都沒有明確聲明,但似乎只是為了執行此操作而在OnClickHandlers中傳回對話框。


而不是getApplicationContext() ,只需使用ActivityName.this







builder