Intereting Posts
Как определить ширину и высоту видео на Android Круг с SweepGradient для анимации Ионный 2: Как обращаться с кнопкой возврата оборудования, которая проверяет подтверждение выхода в приложении In-App Billing: инвентаризация не правильная; Снова закупает пользователя Игра libgdx на некоторых устройствах Как изменить шрифт по умолчанию для приложения Android? Не удалось войти в систему. Проверьте подключение к сети и повторите попытку. Android: класс НЕ НАЙДЕНО в Eclipse-встроенной внешней банке, но НАЙДЕН в Netbeans-построенном Android настроенная кнопка; Изменение цвета текста Анимация FragmentTransaction для перехода сверху JSONObject возвращает ненулевое значение «null» после создания экземпляра со строкой Центральная кнопка в LinearLayout FragmentTabHost & Fragments – Как передать данные между вкладками? ViewPager.setOffscreenPageLimit (0) не имеет никакого эффекта. Как загружать только одну страницу за один раз в ViewPager? Нулевой указатель в getApplicationContext ()

AsyncTask, Фрагменты, Представления и Backstacks

Я немного использовал этот шаблон. Вот очень надуманный пример индикатора прогресса AsyncTask +:

new AsyncTask<Void, Void, Void>() { WeakReference<MyFragment> weakFragment = new WeakReference<MyFragment>(MyFragment.this); @Override protected void onPreExecute() { Fragment fragment = weakFragment.get(); if(fragment != null) fragment.getView().findViewById(R.id.progress).setVisibility(View.VISIBLE); } @Override protected Document doInBackground(Void... params) { Fragment fragment = weakFragment.get(); if(fragment == null) return null; // Do something ... } @Override protected void onPostExecute() { Fragment fragment = weakFragment.get(); if(fragment != null) fragment.getView().findViewById(R.id.progress).setVisibility(View.GONE); } }.execute(); 

Он работает нормально с изменениями ориентации, но я заметил, что фрагмент не равен null, а фрагмент.getView () является нулевым, когда я выталкиваю фрагмент из задней части. Это, очевидно, заставляет это рухнуть. Какой подход вы используете? Я не могу найти идеальное решение в Интернете. Важно отметить, что это фрагмент, и я вызываю setRetainInstance(true); На этом фрагменте в его onActivityCreated (…).

AsyncTask – это асинхронная задача, которая означает, что вы обычно не знаете, когда она будет завершена, и когда она вызывает onPostExecute() . Я думаю, ваша проблема здесь. Когда вы поворачиваете свое устройство, ваша асинтеза еще не закончилась, а вид фрагмента уничтожен и снова воссоздается очень быстро, в то время как асинтектура находится в рабочем потоке, и когда она выполнила свое задание, у вашего фрагмента есть представление, а возвращаемое значение getView не null . Но если время вращения займет много, вы получите null потому что AsyncTask закончен, но у вашего фрагмента нет никакого представления. Теперь этот сценарий происходит именно с вашей задней стопой. Когда вы нажимаете фрагмент на заднюю часть, его представление уничтожается ( смотрите изображение ), но сам фрагмент отсутствует (фрагмент возвращается к макету из backstack). Теперь ваш AsyncTask завершает работу и вызывает метод getView fragment и доза не имеет никакого view поэтому вы получите NPE .

Мое решение:

Сначала вы должны использовать WeakReference<ProgressBar> вместо WeakReference<MyFragment> и в onPostExecute() проверить, является ли оно нулевым или нет, если оно равно null, ничего не делать, поскольку значение по умолчанию невидимо, если оно не является нулевым вызовом setVisibility(View.GONE) .

Обновить:

Фрагмент жив, но взгляд был dealloc'd. Это возможно?

Да, просто посмотрите на рисунок 2 по ссылке. Когда фрагмент активен (зеленый квадрат), the fragment added to back stack фрагменту the fragment added to back stack переходит в onPause , onStop onDestroyView . Затем, когда фрагмент выскакивает из заднего стека, он идет прямо в onCreateView со ссылкой на стрелку с этим текстом: the fragment returns to the layout from backstack .

Чтобы подтвердить свой ответ, вы можете создать AsyncTask и вызвать SystemClock.sleep(30000) внутри вашего doInbackground . Теперь вы можете подтолкнуть свой фрагмент к backstack и вытащить его из backstack без исключения, потому что asynctask еще не закончил и когда он вызовет onPostExecute() ваш фрагмент уже имеет представление.

Еще одна хорошая вещь, которую вы можете увидеть, – setRetainInstance

Это можно использовать только с фрагментами, не входящими в задний стек.

Поэтому, когда вы нажимаете свой фрагмент на задний стек, он может полностью уничтожаться, и вы можете получить новую ссылку на фрагмент, когда она появится. Но когда вы используете setRetainInstance(true); Для изменений конфигурации ваш фрагмент сохраняется во время повторного создания Activity, что означает, что это тот же самый фрагмент, и onCreate не вызывается. И это очень важно, потому что если вы запустите свой AsyncTask в методе onCreate , когда вы нажмете свой фрагмент в задний стек и выскочите его, у вас может появиться новый фрагмент, и это значит, onCreate метод onCreate запущен, а другой AsyncTask запущен. Это означает, что у вас нет никакого контроля над количеством вызовов AsyncTask поэтому следите за утечками памяти!