如何从 viewpager2 访问 RecyclerViews?
Posted
技术标签:
【中文标题】如何从 viewpager2 访问 RecyclerViews?【英文标题】:How to access RecyclerViews from view pager2? 【发布时间】:2021-12-16 12:57:02 【问题描述】:已创建 tabLayout 和 pager2
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
myFragment = inflater.inflate(R.layout.fragment_home, container, false);
tabLayout = myFragment.findViewById(R.id.tab_layout);
pager2 = myFragment.findViewById(R.id.view_pager2);
Button calculate = myFragment.findViewById(R.id.calculate_button);
FragmentManager fm = getFragmentManager();
adapter = new FragmentAdapterRecycler(fm, getLifecycle());
pager2.setAdapter(adapter);
位于onCreateView中:如果页面滑动,那么调用fillFragement()时RecyclerView会正常填充如果先点击tab,那么fillFragment()中的RecyclerView会因为java导致程序崩溃.lang.NullPointerException:
pager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback()
@Override
public void onPageSelected(int position)
calc = (TextView) myFragment.findViewById(R.id.numDisplay);
fillFragment(pager2.getCurrentItem());
tabLayout.selectTab(tabLayout.getTabAt(position));
);
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener()
@Override
public void onTabSelected(TabLayout.Tab tab)
pager2.setCurrentItem(tab.getPosition());
@Override
public void onTabUnselected(TabLayout.Tab tab)
@Override
public void onTabReselected(TabLayout.Tab tab)
);
fillFragment() 这会定位 RecyclerView 并根据所选页面填充它。每个页面都有自己的 RecyclerView。
public void fillFragment(int position)
if (position == 0 && isChosen)
String iterations = "Total Iterations: " + collatz.getIterationTotal();
calc.setText(iterations);
if (tabLoaded1 == false)
mRecyclerView = (RecyclerView) getView().findViewById(R.id.recycler_view);
mRecyclerView.setHasFixedSize(false);
mLayoutManager = new LinearLayoutManager(getActivity());
mAdapter = new CollatzAdapter(collatz.getCollatzList());
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setAdapter(mAdapter);
tabLoaded1 = true;
if (position == 1 && isChosen)
String evenTotal = "Total Even: " + collatz.getEvenTotal();
calc.setText(evenTotal);
if (tabLoaded2 == false)
mRecyclerView = (RecyclerView) myFragment.findViewById(R.id.recycler_view_even);
mRecyclerView.setHasFixedSize(false);
mLayoutManager = new LinearLayoutManager(getActivity());
mAdapter = new CollatzAdapter(collatz.getEvenList());
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setAdapter(mAdapter);
tabLoaded2 = true;
if (position == 2 && isChosen)
String oddTotal = "Total Odd: " + collatz.getOddTotal();
calc.setText(oddTotal);
if (tabLoaded3 == false)
mRecyclerView = (RecyclerView) myFragment.findViewById(R.id.recycler_view_odd);
mRecyclerView.setHasFixedSize(false);
mLayoutManager = new LinearLayoutManager(getActivity());
mAdapter = new CollatzAdapter(collatz.getOddList());
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setAdapter(mAdapter);
tabLoaded3 = true;
总而言之,当调用 fillFragment() 时,单击选项卡会导致空对象引用。滑动页面时它工作正常。这是因为单击选项卡时,会在创建 Pager2 项之前首先调用 fillFragment()。滑动时先创建Pager2项,然后调用fillFragment(),即先创建RecyclerView再访问。
如果 pageView 总是在我填充它导致空对象引用后创建,我如何在单击选项卡时填充 RecyclerView?
StackTrace
【问题讨论】:
你能发布堆栈跟踪吗? java.lang.NullPointerException: 尝试在空对象引用上调用虚拟方法 'void androidx.recyclerview.widget.RecyclerView.setHasFixedSize(boolean)' 对于职位 1,您有getView()
,但对于其他职位,您有 myFragment
,这是故意的吗?
我在尝试不同的东西。我忘记改回来了。它仍然有效,但它们应该都是一样的。
布局中是否真的有 3 个不同的 RecyclerView
s R.layout.fragment_home
R.id.recycler_view_odd
, R.id.recycler_view_even
, R.id.recycler_view
这看起来很奇怪?
【参考方案1】:
您可以通过对当前解决方案稍作改动来解决此问题。但我建议你重新考虑一下什么是对什么负责。
由于片段遵循自己的生命周期,因此您无法保证在任何给定时间附加片段。
因此,当您将 RecyclerViews 从可能“存在”或可能不“存在”的片段中提取出来时,您将得到 null。
Fragments 应该对自己的观点负全部责任,任何其他实体都不应触及它们。
最好的解决方案是拥有一个所有 4 个片段都可以访问的 SharedViewModel。
// in evenFragment
CollatzViewModel collatzViewModel;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
collatzViewModel = new ViewModelProviders(getActivity()).get(CollatzViewModel.class);
evenFragment = inflater.inflate(R.layout.fragment_even, container, false);
mRecyclerView = (RecyclerView) evenFragment .findViewById(R.id.recycler_view_even);
mRecyclerView.setHasFixedSize(false);
mLayoutManager = new LinearLayoutManager(getActivity());
mAdapter = new CollatzAdapter();
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setAdapter(mAdapter);
collatzViewModel.getCollatz().observe(getViewLifeCycle(),(list)->
mAdapter.setList(list);
mAdapter.notifyDataSetChanged();
);
return evenFragment;
//in odd fragment
CollatzViewModel collatzViewModel;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
collatzViewModel = new ViewModelProviders(getActivity()).get(CollatzViewModel.class);
oddFragment = inflater.inflate(R.layout.fragment_odd, container, false);
mRecyclerView = (RecyclerView) oddFragment.findViewById(R.id.recycler_view_odd);
mRecyclerView.setHasFixedSize(false);
mLayoutManager = new LinearLayoutManager(getActivity());
mAdapter = new CollatzAdapter();
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setAdapter(mAdapter);
collatzViewModel.getCollatz().observe(getViewLifeCycle(),(list)->
mAdapter.setList(list);
mAdapter.notifyDataSetChanged();
);
return oddFragment;
//in iteration fragment
CollatzViewModel collatzViewModel;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
iterationFragment = inflater.inflate(R.layout.fragment_iteration, container, false);
collatzViewModel = new ViewModelProviders(getActivity()).get(CollatzViewModel.class);
mRecyclerView = (RecyclerView) iterationFragment.findViewById(R.id.recycler_view);
mRecyclerView.setHasFixedSize(false);
mLayoutManager = new LinearLayoutManager(getActivity());
mAdapter = new CollatzAdapter();
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setAdapter(mAdapter);
collatzViewModel.getCollatz().observe(getViewLifeCycle(),(list)->
mAdapter.setList(list);
mAdapter.notifyDataSetChanged();
);
return iterationFragment;
//ViewModel class
public class CollatzViewModel extends ViewModel
private MutableLiveData<List<BigInteger>> collatz = new MutableLiveData();
public MutableLiveData<List<BigInteger>> getCollatz()
return collatz;
//home fragment
CollatzViewModel collatzViewModel;
public void fillFragment(int position)
if (position == 0 && isChosen)
String iterations = "Total Iterations: " + collatz.getIterationTotal();
calc.setText(iterations);
if (tabLoaded1 == false)
collatzViewModel.getCollatz().setValue(collatz.getCollatzList())
tabLoaded1 = true;
if (position == 1 && isChosen)
String evenTotal = "Total Even: " + collatz.getEvenTotal();
calc.setText(evenTotal);
if (tabLoaded2 == false)
collatzViewModel.getCollatz().setValue(collatz.getEvenList())
tabLoaded2 = true;
if (position == 2 && isChosen)
String oddTotal = "Total Odd: " + collatz.getOddTotal();
calc.setText(oddTotal);
if (tabLoaded3 == false)
collatzViewModel.getCollatz().setValue(collatz.getOddList())
tabLoaded3 = true;
【讨论】:
您好,谢谢您的建议。我实现了一切,现在的问题是 RecyclerView 没有显示任何数据。我检查了是否从 collatzViewModel 检索到的列表是否包含任何内容,并且确实如此。不确定是什么问题。如果您想查看它,我更新了存储库。感谢您的帮助。 @ErickSorto 不要使用mAdapter = new CollatzAdapter(list);
您正在重新制作适配器,而不是将其设置回 recyclerView
CollatzAdapter
应该包含一个 setList(List<BigInteger> list)
函数,您可以在其中设置适配器制作完成后的列表。不要重新创建不需要的适配器。
我在CollatzAdapter
中添加了一个设置器,但“mAdapter”无法访问该方法。我尝试了“mAdapter.setList”,但它不起作用。
RecyclerView.Adapter mAdapter
需要在您的成员字段中为 CollatzAdapter mAdapter
。
有效!!最后,非常感谢。我已经坚持了这么久。你太棒了。以上是关于如何从 viewpager2 访问 RecyclerViews?的主要内容,如果未能解决你的问题,请参考以下文章
如何从使用 Fragment 的 ViewPager2 获得用户点击?
如何更新 Tablayout 中的片段? (Viewpager2, FragmentStateAdapter)
Android MVVM框架搭建RecyclerVIew + ViewPager2 + BaseQuickAdapter