Android:在升级支持库之后使用findFragmentById()的NullPointerException

时间:2015-07-16 20:43:02

标签: android android-appcompat fragmentmanager

我刚刚将旧的Android项目从Eclipse切换到Android Studio,在此过程中,我从旧的支持库版本19.0.1更新为22.2.0。在此之后,我在以前的代码中遇到了一些错误。我在其间下载了所有SDK并检查了错误最初发挥作用的位置,它似乎在版本21.1.0及更高版本中。我在release notes查看了该版本,但找不到任何有趣的内容。

我的错误是我在这里得到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);
}

我到达的FragmentListFragment,它是XML文件的一部分,在应用启动时会膨胀。在通货膨胀期间似乎将ListFragment添加到父FragmentManager内的Fragment 内。这可能是我在获取FragmentManager的{​​{1}}时获得nullpointer的原因。因此,我的问题是:

如何获取Activity中的ListFragment?是否有必要保留对父Activity的引用,以便通过其Fragment获取ListFragment?在FragmentManager中返回Fragment时父亲new MyFragment()被夸大了,因此在FragmentPagerAdapter#getItem()中获得正确的引用更加棘手。

还有一件事需要注意:我看到一些消息告诉我应该更新为Activity,我做了(JDK 1.7)。我不记得我做了什么,但在&#34;外部图书馆&#34;我看到OpenJDK 1.7。不确定这是否重要。

2 个答案:

答案 0 :(得分:1)

我按照this回答解决了这个问题。似乎不可能以一种漂亮的方式从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://stackoverflow.com/a/15261142/1139324
        return;
    }

    FilteredRecipesListFragment listFragment = (FilteredRecipesListFragment)
            filteredRecipesFragment.getChildFragmentManager().findFragmentById(R.id.mm_filtered_recipes_list_fragment);
    listFragment.onRecipesFiltered(filteredRecipes);
}

答案 1 :(得分:0)

尝试替换:

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

上的getChildFragmentManager()