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()

Другие вопросы по тегам