Android: исключение NullPointerException с использованием findFragmentById() после обновления библиотек поддержки
Я просто переключил старый проект Android с Eclipse на Android Studio, и в ходе этого процесса я обновил версию старой библиотеки поддержки. 19.0.1
в 22.2.0
, После этого я получаю некоторые ошибки в моем ранее работающем коде. Я загрузил все SDK между ними и проверил, где ошибка впервые появилась, и, кажется, в версии 21.1.0
и выше. Я посмотрел в примечаниях к выпуску для этой версии, но не смог найти ничего интересного.
Моя ошибка в том, что я получаю NullPointerException
Вот. Обратите внимание, что этот метод является частью Activity
не родитель Fragment
,
public synchronized void onRecipesFiltered(ArrayList<Recipe> filteredRecipes)
{
FilteredRecipesListFragment filteredRecipesListFragment = (FilteredRecipesListFragment)
getSupportFragmentManager().findFragmentById(R.id.mm_filtered_recipes_list_fragment);
// filteredRecipesListFragment becomes null
filteredRecipesListFragment.onRecipesFiltered(filteredRecipes);
}
Fragment
Я получаю здесь ListFragment
который является частью XML-файла, который раздувается при запуске приложения. Похоже вот так ListFragment
добавляется в FragmentManager
внутри родителя Fragment
во время инфляции. Вероятно, поэтому я получаю нулевой указатель при получении FragmentManager
из Activity
, Таким образом, мой вопрос:
Как я могу получить ListFragment
в Activity
? Нужно ли сохранять ссылку на родителя? Fragment
чтобы получить ListFragment
через его FragmentManager
? Родитель Fragment
раздувается при возвращении new MyFragment()
в FragmentPagerAdapter#getItem()
нигде, следовательно, немного сложнее получить правильную ссылку в Activity
,
Еще одна вещь, на которую следует обратить внимание: я видел несколько сообщений, в которых говорилось, что мне следует обновить до JDK 1.7
что я и сделал (OpenJDK 1.7
). Я не помню, что я сделал, но в разделе "Внешние библиотеки" я вижу <1.7> (/usr/lib/jvm/java-1.7.0-openjdk-amd64)
, Не уверен, если это имеет значение.
2 ответа
Я решил проблему, следуя этому ответу. Кажется, что на самом деле не возможно получить Fragment
с из ViewPager
таким образом, они должны быть сохранены как ссылки после создания и извлечены при необходимости.
Я скопирую основной код ответа здесь, на всякий случай. Основная идея состоит в том, чтобы сохранить Fragment
в SparseArray
чтобы получить их, когда это необходимо. Они должны быть вставлены и удалены после создания / перед удалением.
public class MyPagerAdapter extends FragmentStatePagerAdapter {
SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public int getCount() {
return ...;
}
@Override
public Fragment getItem(int position) {
return MyFragment.newInstance(...);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
}
После этого я могу переписать свой метод следующим образом, используя getChildFragmentManager()
как отметил @Skizo:
public synchronized void onRecipesFiltered(ArrayList<Recipe> filteredRecipes)
{
MyPagerAdapter myPagerAdapter = (MyPagerAdapter) mMyViewPager.getAdapter();
FilteredRecipesFragment filteredRecipesFragment = (FilteredRecipesFragment)
myPagerAdapter.getRegisteredFragment(PagerConstants.PAGE_FILTER_RECIPES);
if (filteredRecipesFragment == null)
{
// Fragments that has not yet been instantiated will be returned as null. Cannot do anything about it.
// Should be fairly unlikely. See:
// https://stackru.com/a/15261142/1139324
return;
}
FilteredRecipesListFragment listFragment = (FilteredRecipesListFragment)
filteredRecipesFragment.getChildFragmentManager().findFragmentById(R.id.mm_filtered_recipes_list_fragment);
listFragment.onRecipesFiltered(filteredRecipes);
}
Попробуйте заменить:
FilteredRecipesListFragment filteredRecipesListFragment = (FilteredRecipesListFragment)
getSupportFragmentManager().findFragmentById(R.id.mm_filtered_recipes_list_fragment);
к:
FilteredRecipesListFragment filteredRecipesListFragment = (FilteredRecipesListFragment)
getChildFragmentManager().findFragmentById(R.id.mm_filtered_recipes_list_fragment);
Узнайте больше о getChildFragmentManager()
в документации getChildFragmentManager()