2013-02-26 2 views
5

Я постоянно расстраивался этим, и я не могу найти хороший ответ, поэтому надеемся, что кто-то здесь может предложить руководство.фрагменты, когда я «активен»?

У меня есть фрагмент, который довольно широко использует AsyncTask. я постоянно страдает от ошибок, когда фрагмент вызывает getActivity(), который возвращает null. Я предполагаю, что это происходит из-за того, что какой-либо метод в фрагменте активируется до того, как действие будет подключено или после его отсоединения.

Каков правильный способ справиться с этим в моем коде? я не хочу, чтобы эта идиома валялись повсюду,

Activity activity = getActivity(); 
if (activity != null) { // do something } 

глядя на документы для Fragment, я могу придумать множество возможных крюков для решения этой проблемы: isDetached(), onActivityCreated(), onAttach(), isResumed(), и скоро. Какая правильная комбинация?

EDIT:

Несколько человек предложили отменить задачи во время паузы, но это означает, что стандартная идиома,

new AsyncTask<...>.execute(); 

не могут быть использованы. Это означает, что каждый exec'd AsyncTask должен быть отслежен до завершения или отменен. Я просто никогда не видел этого в примере кода от Google или в другом месте. Нечто подобное,

private final Set<AsyncTask<?>> tasks = new HashSet<>; 
... 
AsyncTask<?> t = new AsyncTask<...>() { 
    ... 
    public void onPostExecute(...) { 
    tasks.remove(this); 
    ... 
    } 
} 
tasks.add(t); 
t.execute(); 
... 
@Override 
public void onPause() { 
    for (AsyncTask<?> t: tasks) { 
    t.cancel(); 
    } 
    tasks.clear(); 
} 
+0

Определенно не ответ, но ... Ваша ошибка является архитектурной.Я не знаю точно, что вы делаете с AsyncTasks, но могу сказать, что если getActivity возвращает null, пока один из них запущен, вы не должны использовать AsyncTask. Все, что вы делаете в задаче, должно выполняться в Службе. Операция/фрагмент, который должен знать состояние поиска, может попросить Службу получить. Проверьте IntentService: он прост в использовании и намного проще, чем AsyncTask (нормально, теперь подождите: он проще, чем AsyncTask на самом деле ** **, не проще, чем он появляется). –

+0

@ G.BlakeMeike спасибо за отзыв. у нас на самом деле есть оба шаблона в приложении: «IntentService» и «AsyncTask». Я предпочитаю семантику вызова 'AsyncTask'. Re: неправильная архитектура - я не знаю, согласен ли я. в любое время, когда вам нужен контекст, вы должны называть 'getActivity()'. так что нужно, чтобы сказать, что строка в onPostExecute() означает, что у меня неправильная арка? –

+0

Ну .. да, я думаю, это в значительной степени то, что я говорю. Вся сделка с AsyncTask заключается в том, что у нее есть жизненный цикл, полностью отделенный от действий. Вы не можете рассчитывать на * любой * контекст активности, находящийся вокруг, в любой момент времени в жизни AT. Рассматривали ли вы передачу ApplicationContext в конструктор AT? –

ответ

2

Попробуйте отменить AsyncTasks в onPause или onStop методами. Это предотвратит вызов onPostExecute, когда Fragment больше не активен (getActivity() возвращает null).

Или вы можете проверить, подключен ли Fragment по телефону this.isAdded() в вашем Fragment.

+0

спасибо. проблема в том, что мне нужно будет держать дескриптор для каждой «AsyncTask», которую я выполняю. например, хранить их в стеке, вызывать их, когда вызывается 'onPostExecute()' или когда я их отменю. нет метода 'isAttached()', только 'isDetached()', что справедливо только тогда, когда фрагмент был отсоединен, а не когда он еще не был присоединен (см. javadocs). –

+0

Я фактически изменил метод 'isAttached' на' isAdded' непосредственно после отправки ответа;) См. Также http://stackoverflow.com/questions/10919240/fragment-myfragment-not-attached-to-activity – nhaarman

+0

Кроме того, Обычно я стараюсь сохранить число 'AsyncTask' '' '' '' '' '' '' Fragment'' ниже 3, так что это выполнимо. – nhaarman

0

С точки зрения координации жизненных циклов, я сохраняю onActivityCreated как ментальный критерий - он отмечает точку, в которой базовая деятельность завершила свою собственную onCreate. До этого я не верю, что есть активность до getActivity().

То, что получает активность, возвращает нулевые звуки, подобные тому, что вы вызываете getActivity() слишком рано (т. Е. До его создания) или слишком поздно (т. Е. Когда он перестает взаимодействовать с фрагментом). Остановка ваших задач в onPause() предотвратит возврат getActivity от null, так как он отключит задачу после того, как фрагмент перестанет взаимодействовать с основной деятельностью, потому что сама деятельность была приостановлена. Я думаю, что ожидание onStop() может быть слишком запоздалым, поскольку, если задача должна была выполняться, когда основное действие приостановлено, оно может все еще содержать значение null.

1

отвечая на мой собственный вопрос ...

я не смог найти хорошее решение. в целом, используйте либо Loader, либо убедитесь, что getActivity() не возвращает значение null перед его использованием. Я изучил использование Loader s, но шаблон делает много предположений о структуре приложения и характере извлечения данных, которые не сработали для меня.

Смежные вопросы