在包含RecyclerView的片段之间切换时出现NullPointerException

时间:2014-11-06 21:51:49

标签: java android android-fragments android-support-library

我真的很难想到这一点。我在NullPointerExceptionFragments之间切换时获得RecyclerView,但只是按特定顺序切换。代码和例外情况如下。首先解释一下:

我有一个带有此选项卡式布局的片段,如下所示: enter image description here

其中3个选项卡使用包含RecyclerView的相同Fragment:Schedule,History和Test。如果我先选择它们,它们中的任何一个都会有效。现在的问题是,当我选择其他前面提到的选项卡之一时,我选择的第一个选项卡的右侧!如果我走到我选择的第一个的左边,那将会加载得很好。

如果我选择测试然后转到历史记录,然后安排一切都会正常工作

如果我选择测试然后安排那两个将工作,但然后转到历史将导致 异常。

如果我选择Schedule then History,则会发生异常。

如果我选择历史记录然后安排那两个将工作,但然后去测试异常将发生

如果我选择历史记录然后测试异常将会发生

我扩展了RecycleView并在onMeasure中休息一下,看看我是否能弄清楚发生了什么,我注意到mAdapter的{​​{1}}是{{1} }}。我检查了RecyclerView的{​​{1}}里面,它总是传递一个有效的适配器。所以似乎null在某些时候被清除了。我无法弄清楚为什么只有当我从左到右而不是从右到左打开标签时才会发生这种情况......

任何帮助都会受到赞赏,因为我的智慧会以此结束!

这是NullPointerException:

Link to Exception trace(不得不把它放在这里以避免字符限制)

编辑:抓住setAdapter() RecyclerView后也会弹出。看起来来自mAdapterHere is a link to that output

以下是标签视图的片段:

NullPointerException

这是片段:

IllegalStateException

实现LoaderManager.LoaderCallbacks {

LayoutManager

}

这是RecyclerView.Adapter:

public class FKitViewer extends Fragment implements OnTabChangeListener {

    public static final String TAB_INFO = "Info";
    public static final String TAB_SCHEDULE = "Schedule";
    public static final String TAB_HISTORY = "History";
    public static final String TAB_TEST = "Test";
    public static final String TAB_REQS = "Reqs";

    private View mRoot;
    private TabHost mTabHost;
    private int mCurrentTab;

    @Override
    public void onAttach(Activity activity){
        super.onAttach(activity);
    }

    @Override
    public View onCreateView(LayoutInflater li, ViewGroup container,
                                Bundle savedInstanceState){
        mRoot = li.inflate(R.layout.kit_view, container);
        mTabHost = (TabHost) mRoot.findViewById(android.R.id.tabhost);
        setupTabs();
        return mRoot;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState){
        super.onActivityCreated(savedInstanceState);
        setRetainInstance(true);
        mTabHost.setOnTabChangedListener(this);
        mTabHost.setCurrentTab(mCurrentTab);
        updateTab(TAB_INFO, R.id.tab1);
    }

    private void setupTabs(){
        mTabHost.setup();
        mTabHost.addTab(newTab(TAB_INFO, "Info", R.id.tab1));
        mTabHost.addTab(newTab(TAB_SCHEDULE, "Schedule", R.id.tab2));
        mTabHost.addTab(newTab(TAB_HISTORY, "History", R.id.tab3));
        mTabHost.addTab(newTab(TAB_REQS, "Reqs", R.id.tab4));
        mTabHost.addTab(newTab(TAB_TEST, "Test", R.id.tab5));
    }

    private TabSpec newTab(String tag, String label, int tabContentId){
        TabSpec tabSpec = mTabHost.newTabSpec(tag);
        tabSpec.setIndicator(label);
        tabSpec.setContent(tabContentId);
        return tabSpec;
    }

    private void updateTab(String tabId, int placeholder){
        FragmentManager fm = getFragmentManager();
        if(fm.findFragmentByTag(tabId) == null){
            if(tabId.equals(TAB_INFO))
                fm.beginTransaction()
                    .replace(placeholder, new FListiesView(), tabId)
                    .commit();
            if(tabId.equals(TAB_SCHEDULE))
                fm.beginTransaction()
                    .replace(placeholder, new FKitSchedule(false), tabId)
                    .commit();
            if(tabId.equals(TAB_HISTORY))
                fm.beginTransaction()
                    .replace(placeholder, new FKitSchedule(true), tabId)
                    .commit();
            if(tabId.equals(TAB_REQS))
                fm.beginTransaction()
                    .replace(placeholder, new KitRequirements(), tabId)
                    .commit();
            if(tabId.equals(TAB_TEST))
                fm.beginTransaction()
                    .replace(placeholder, new FKitSchedule(false), tabId)
                    .commit();
        }
    }

    @Override
    public void onTabChanged(String tabId){
        Log.d("MNB", "Changing to tab: " + tabId);
        if(TAB_INFO.equals(tabId)){
            updateTab(tabId, R.id.tab1);
            mCurrentTab = 0;
            return;
        }
        if(TAB_SCHEDULE.equals(tabId)){
            getActivity().getIntent().getExtras().putBoolean("com.crummy.history", false);
            updateTab(tabId, R.id.tab2);
            mCurrentTab = 1;
            return;
        }
        if(TAB_HISTORY.equals(tabId)){
            getActivity().getIntent().getExtras().putBoolean("com.crummy.history", true);
            updateTab(tabId, R.id.tab3);
            mCurrentTab = 2;
            return;
        }
        if(TAB_REQS.equals(tabId)){
            updateTab(tabId, R.id.tab4);
            mCurrentTab = 3;
            return;
        }
        if(TAB_TEST.equals(tabId)){
            getActivity().getIntent().getExtras().putBoolean("com.crummy.history", true);
            updateTab(tabId, R.id.tab5);
            mCurrentTab = 4;
            return;
        }
    }
}

1 个答案:

答案 0 :(得分:3)

当您的onViewCreated()分离时,您应该在onActivityCreated()而不是onActivityCreated() - Fragment进行视图分配(和LayoutManager分配)并通过ViewPager重新附加。视图将被销毁(onDestroyView())并重新创建(onCreateView()),因为它会消失并返回,但RecyclerView在这种情况下永远不会获得LayoutManager

编辑:从评论中拉出来,另一个问题是使用父Activity解析RecyclerView而不是使用Fragment's View。由于findViewById()执行深度优先搜索,如果您有多个Fragments附加包含具有相同ID的视图,您可能最终得到错误的视图,但所有内容仍然会编译并运行,只是意外的结果。使用view中返回的onViewCreated()将您的视图搜索限制为只是您在onCreateView()中充气的布局。