В сообщениях об ошибках консоли разработчика иногда я вижу отчеты с проблемой NPE. Я не понимаю, что не так с моим кодом. На эмуляторе и на моем устройстве приложение работает хорошо без принудительной блокировки, однако некоторые пользователи получают NullPointerException в классе фрагмента при вызове метода getActivity ().
Деятельность
pulic class MyActivity extends FragmentActivity{
private ViewPager pager;
private TitlePageIndicator indicator;
private TabsAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
pager = (ViewPager) findViewById(R.id.pager);
indicator = (TitlePageIndicator) findViewById(R.id.indicator);
adapter = new TabsAdapter(getSupportFragmentManager(), false);
adapter.addFragment(new FirstFragment());
adapter.addFragment(new SecondFragment());
indicator.notifyDataSetChanged();
adapter.notifyDataSetChanged();
// push first task
FirstTask firstTask = new FirstTask(MyActivity.this);
// set first fragment as listener
firstTask.setTaskListener((TaskListener) adapter.getItem(0));
firstTask.execute();
}
indicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
Fragment currentFragment = adapter.getItem(position);
((Taskable) currentFragment).executeTask();
}
@Override
public void onPageScrolled(int i, float v, int i1) {}
@Override
public void onPageScrollStateChanged(int i) {}
});
}
Класс AsyncTask
public class FirstTask extends AsyncTask{
private TaskListener taskListener;
...
@Override
protected void onPostExecute(T result) {
...
taskListener.onTaskComplete(result);
}
}
Фрагмент класса
public class FirstFragment extends Fragment immplements Taskable, TaskListener{
public FirstFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.first_view, container, false);
}
@Override
public void executeTask() {
FirstTask firstTask = new FirstTask(MyActivity.this);
firstTask.setTaskListener(this);
firstTask.execute();
}
@Override
public void onTaskComplete(T result) {
// NPE is here
Resources res = getActivity().getResources();
...
}
}
Возможно, эта ошибка возникает, когда приложения возобновляются из фона. В этом случае, как я должен справиться с этой ситуацией правильно?
Ответы:
Кажется, я нашел решение своей проблемы. Очень хорошие объяснения даны здесь и здесь . Вот мой пример:
Основная идея этого кода заключается в том, что при нормальной работе приложения вы создаете новые фрагменты и передаете их адаптеру. Когда вы возобновляете работу, у менеджера фрагментов вашего приложения уже есть экземпляр этого фрагмента, и вам нужно получить его из менеджера фрагментов и передать его адаптеру.
ОБНОВИТЬ
Также рекомендуется использовать фрагменты для проверки isAdded перед вызовом getActivity (). Это помогает избежать исключения нулевого указателя, когда фрагмент отсоединен от действия. Например, действие может содержать фрагмент, который выдвигает асинхронную задачу. Когда задача завершена, вызывается прослушиватель onTaskComplete.
Если мы откроем фрагмент, нажмем задание, а затем быстро нажмем назад, чтобы вернуться к предыдущему действию, когда задание будет выполнено, оно попытается получить доступ к действию в onPostExecute (), вызвав метод getActivity (). Если действие уже отключено, и этой проверки нет:
тогда приложение вылетает.
источник
isAdded()
перед каждым доступом ... делает код ужасным.if(isAdded())
илиif(getActivity() != null)
Хорошо, я знаю, что этот вопрос действительно решен, но я решил поделиться своим решением для этого. Я создал абстрактный родительский класс для моего
Fragment
:Как видите, я добавил слушателя, поэтому всякий раз, когда мне нужно получить
Fragments
Activity
вместо стандартногоgetActivity()
, мне нужно позвонитьисточник
Лучше всего избавиться от этого, чтобы сохранить ссылку на активность при
onAttach
вызове и использовать ссылку на активность, где это необходимо, например,Отредактировано, поскольку
onAttach(Activity)
устарело и сейчасonAttach(Context)
используетсяисточник
getActivity()
возвращает ноль, то это потому, что вы больше не в активности. Это грязный обходной путь.Не вызывайте методы внутри фрагмента, которые требуют getActivity (), пока onStart в родительском действии.
источник
Некоторое время я боролся с такой проблемой и думаю, что нашел надежное решение.
Это довольно трудно , чтобы знать наверняка , что
this.getActivity()
не собирается возвращатьсяnull
дляFragment
, особенно если вы имеете дело с любым типом поведения сети , которая дает ваш код достаточно времени , чтобы вывестиActivity
ссылки.В приведенном ниже решении я объявляю небольшой класс управления, называемый
ActivityBuffer
. По сути, этоclass
касается поддержания надежной ссылки на собственникаActivity
и обещания выполнитьRunnable
s в допустимомActivity
контексте, когда есть допустимая ссылка. ВRunnable
s запланированы для выполнения на тему UI немедленно , еслиContext
доступен, в противном случае исполнение откладывается до тех пор , чтоContext
не готов.С точки зрения его реализации, мы должны позаботиться о применении методов жизненного цикла, чтобы они совпали с поведением, описанным выше Pawan M :
И, наконец, в любых областях, в
Fragment
которыхBaseFragment
вы не заслуживаете доверияgetActivity()
, просто позвонитеthis.getActivityBuffer().safely(...)
и объявитеActivityBuffer.IRunnable
задачу!Содержание вашего
void run(final Activity pActivity)
будет гарантированно исполнено в потоке пользовательского интерфейса.Затем
ActivityBuffer
можно использовать следующим образом:источник
источник
Я знаю, что это старый вопрос, но я думаю, что должен дать свой ответ на него, потому что моя проблема не была решена другими.
во-первых: я динамически добавлял фрагменты, используя FragTransactions. Второе: мои фрагменты были изменены с помощью AsyncTasks (запросы к БД на сервере). В-третьих: мой фрагмент не был создан при запуске действия. В-четвертых: я использовал пользовательский экземпляр фрагмента «создай или загрузи его», чтобы получить переменную фрагмента. Четвертое: активность была воссоздана из-за смены ориентации
Проблема заключалась в том, что я хотел «удалить» фрагмент из-за ответа на запрос, но этот фрагмент был создан неправильно ранее. Я не знаю, почему, возможно, из-за «коммита», который будет сделан позже, фрагмент еще не был добавлен, когда пришло время его удалять. Следовательно, getActivity () возвращал значение NULL.
Решение: 1) Мне нужно было проверить, правильно ли я пытался найти первый экземпляр фрагмента, прежде чем создавать новый. 2) Мне пришлось поместить serRetainInstance (true) в этот фрагмент, чтобы сохранить его путем изменения ориентации (без обратного стека). следовательно, не нужно никаких проблем) 3) Вместо того, чтобы «воссоздавать или получать старый фрагмент» непосредственно перед «удалить его», я непосредственно помещаю фрагмент в начало действия. Создание экземпляра при запуске действия вместо «загрузки» (или создания экземпляра) переменной фрагмента перед его удалением предотвратило проблемы с getActivity.
источник
В Kotlin вы можете попробовать этот способ для обработки нулевого условия getActivity ().
Он проверит активность на ноль или нет, а если не ноль, то выполнит внутренний код.
источник