with - какая разница между dialog и alertdialog в android




Вызов метаданных «Невозможно добавить нулевой токен окна-это не приложение» с getApplication() как контекст (16)

Вы не можете отображать window/dialog через контекст, который не является активностью или службой . Попробуйте передать действительную ссылку на действительность

Моя активность пытается создать AlertDialog, который требует контекста в качестве параметра. Это работает, как и ожидалось, если я использую:

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

Тем не менее, я склонен использовать «это» в качестве контекста из-за потенциальной утечки памяти, когда Activity разрушается и воссоздается даже во время чего-то простого, подобного вращению экрана. Из связанного сообщения в блоге разработчика Android :

Существует два простых способа избежать утечек памяти, связанных с контекстом. Самое очевидное - избегать выхода из контекста вне его собственной сферы. В приведенном выше примере показан случай статической ссылки, но внутренние классы и их неявная ссылка на внешний класс могут быть одинаково опасными. Второе решение - использовать контекст приложения. Этот контекст будет жить до тех пор, пока ваше приложение будет живым и не будет зависеть от жизненного цикла деятельности. Если вы планируете хранить долгоживущие объекты, которым нужен контекст, запомните объект приложения. Вы можете легко получить его, вызвав Context.getApplicationContext () или Activity.getApplication ().

Но для AlertDialog() ни getApplicationContext() либо getApplication() является приемлемым как контекст, поскольку он выдает исключение:

«Невозможно добавить нулевой токен окна не для приложения»

по ссылкам: 1 , 2 , 3 и т. д.

Итак, следует ли это считать «ошибкой», поскольку нам официально рекомендуется использовать Activity.getApplication() и все же он не работает так, как рекламируется?

Джим


***** kotlin версия *****

Вы должны передать [email protected] вместо applicationContext или baseContext


В поле « Activity нажатие кнопки показывает диалоговое окно

Dialog dialog = new Dialog(MyActivity.this);

Работал для меня.


Ваш диалог не должен быть «долгоживущим объектом, которому нужен контекст». Документация запутанна. В принципе, если вы делаете что-то вроде:

static Dialog sDialog;

(обратите внимание на статичность )

Затем в какой-то деятельности вы сделали

 sDialog = new Dialog(this);

Вероятно, вы протекаете первоначальную активность во время ротации или схожим образом, что приведет к разрушению активности. (Если вы не очистите в onDestroy, но в этом случае вы, вероятно, не станете объектом Dialog)

Для некоторых структур данных было бы целесообразно сделать их статичными и основать на контексте приложения, но, как правило, не для связанных с пользовательским интерфейсом вещей, таких как диалоги. Так что-то вроде этого:

Dialog mDialog;

...

mDialog = new Dialog(this);

Прекрасно и не должно терять активность, поскольку mDialog будет освобожден от активности, поскольку он не является статичным.


Вы можете продолжать использовать getApplicationContext() , но перед использованием вы должны добавить этот флаг: dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT) , и ошибка не будет отображаться.

Добавьте в свой манифест следующее разрешение:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

Вы правильно определили проблему, когда вы сказали «... для AlertDialog (), ни getApplicationContext (), либо getApplication () не является приемлемым как контекст, поскольку он генерирует исключение:« Невозможно добавить нулевой токен окна не для приложение'"

Для создания диалогового окна вам нужен контекст активности или контекст службы , а не контекст приложения (как getApplicationContext (), так и getApplication () возвращают контекст приложения).

Вот как вы получаете контекст активности :

(1) В деятельности или услуге:

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

(2) В фрагменте: AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

Утечки памяти не являются проблемой, которая является неотъемлемой частью «этой» ссылки, которая является ссылкой на объект (например, ссылка на фактическую выделенную память для хранения данных объекта). Это случается с любой выделенной памятью, для которой сборщик мусора (GC) не может высвободиться после того, как выделенная память изжила свою полезную продолжительность жизни.

В большинстве случаев, когда переменная выходит за пределы области действия, память будет восстановлена ​​GC. Однако утечки памяти могут возникать, когда ссылка на объект, удерживаемый переменной, например «x», сохраняется даже после того, как объект изжил свою полезную продолжительность жизни. Таким образом, выделенная память будет потеряна до тех пор, пока «x» содержит ссылку на нее, поскольку GC не освобождает память до тех пор, пока эта память все еще ссылается. Иногда утечки памяти не очевидны из-за цепочки ссылок на выделенную память. В этом случае GC не освободит память до тех пор, пока все ссылки на эту память не будут удалены.

Чтобы предотвратить утечку памяти, проверьте свой код на логические ошибки, которые заставляют выделенную память на неопределенное время ссылаться на «это» (или другие ссылки). Не забудьте также проверить ссылки на цепи. Вот некоторые инструменты, которые вы можете использовать, чтобы помочь вам проанализировать использование памяти и найти эти досадные утечки памяти:


Если вы используете фрагмент и используете сообщение AlertDialog / Toast , используйте параметр getActivity() в параметре контекста.

Работал для меня.

Ура!


Если вы используете фрагмент и используете сообщение AlertDialog / Toast, используйте параметр getActivity () в параметре контекста.

как это

ProgressDialog pdialog;
pdialog = new ProgressDialog(getActivity());
pdialog.setCancelable(true);
pdialog.setMessage("Loading ....");
pdialog.show();

Или другая возможность - создать диалог следующим образом:

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

Использование this не MyActivityName.this мне, но MyActivityName.this . Надеюсь, это поможет любому, кто не может заставить this работать.


Маленький взлом: вы можете предотвратить уничтожение деятельности 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();
    }
    ...
}

Попробуйте getParent() в месте аргумента контекста, например new AlertDialog.Builder(getParent()); Надеюсь, это сработает, это сработало для меня.


Посмотрев API, вы можете передать диалог своей активности или getActivity, если вы находитесь в фрагменте, а затем принудительно очистите его с помощью dialog.dismiss () в методах возврата для предотвращения утечек.

Хотя это явно не указано нигде, я знаю, кажется, что вы передали диалог в OnClickHandlers только для этого.


Я должен был отправить свой контекст через конструктор на пользовательский адаптер, отображаемый в фрагменте, и имел эту проблему с getApplicationContext (). Я решил это с помощью:

this.getActivity().getWindow().getContext() в onCreate .


Я использовал ProgressDialog в фрагменте и получал эту ошибку при передаче getActivity().getApplicationContext() в качестве параметра конструктора. Изменив его на getActivity().getBaseContext() тоже не работал.

Решение, которое работало для меня, состояло в том, чтобы передать getActivity() ; т.е.

progressDialog = new ProgressDialog(getActivity());


в действии просто используйте:

MyActivity.this

в Фрагменте:

getActivity();






builder