Let's start with the code. You can ignore the creation of sets and fragment s in the adapter style we often write.
public class VP2TaskPagerAdapter extends FragmentStateAdapter { private List<TaskTableBean> taskTableBeans; public VP2TaskPagerAdapter(FragmentManager fragmentManager, Lifecycle lifecycle,List<TaskTableBean> taskTableBeans) { super(fragmentManager, lifecycle); this.taskTableBeans = taskTableBeans; } //Update data public void update(List<TaskTableBean> taskTableBeans) { this.taskTableBeans = taskTableBeans; notifyDataSetChanged(); } @NonNull @Override public Fragment createFragment(int position) { Fragment fragment = null; switch (getItemViewType(position)) { case 5: fragment = GroupTaskFragment.newInstance(); break; case 7: fragment = NewdiscoveryTaskFragment.newInstance(); break; case 4: fragment = new GrowthPlanFragmentMvc(); break; case 6: case 8: fragment = ExclusiveTaskFragment.newInstance(); break; case 9: fragment = ExperiencetaskFragment.newInstance(); break; case 0: case 1: case 2: case 3: fragment = NewCardFragment.newInstance(); break; case 10: fragment = TounLockFragment.newInstance(); break; } return fragment; } @Override public int getItemViewType(int position) { TaskTableBean taskTableBean = taskTableBeans.get(position); return Integer.valueOf(taskTableBean.taskType); } @Override public int getItemCount() { return taskTableBeans.size(); } }
ViewPager2 is generally refreshed. What we call is
adapter.notifyDataSetChanged() method, but when the data changes, we will find that our page has not changed. Why? By viewing
FragmentStateAdapter
Source code
private void ensureFragment(int position) { long itemId = getItemId(position); if (!mFragments.containsKey(itemId)) { // TODO(133419201): check if a Fragment provided here is a new Fragment Fragment newFragment = createFragment(position); newFragment.setInitialSavedState(mSavedStates.get(itemId)); mFragments.put(itemId, newFragment); } }
You can see the mFragments created by our fragment Containskey (itemid) is created by the judgment, and the default getItemId method returns the value of position. Let's look at the variable mFragments
Final LongSparseArray < fragment > mfragments, the key of LongSparseArray's data is actually position, so our position must be included in it, so we
When notifyDataSetChanged, the fragment will not be re created, so our data and interface will not be rebuilt.
So how should we update the interface?
There are two options:
The first is to add an update operation directly to the fragment, and call the update method every time it needs to be changed.
The second is what we want to introduce now, by rewriting
The getItemId method lets our adapter help us rebuild this fragment
What exactly should I do?
Now that we know that the system judges whether to rebuild according to the return value of getItemId, we can find a way to change this value.
So how do I return this value?
I use the hashCode() method. If the object changes internally, we can easily know whether the data has changed by overriding the hashCode() method
for example
@Override public int hashCode() { int hashCode=super.hashCode(); if (!TextUtils.isEmpty(nowTime)){ hashCode += nowTime.hashCode(); } if (!TextUtils.isEmpty(jadeStarMsg)){ hashCode += jadeStarMsg.hashCode(); } return hashCode; }
hash accumulation is performed for some important parameters. The probability of repetition is very low, which is basically negligible.
Next, I attach my adapter source code
public class VP2TaskPagerAdapter extends FragmentStateAdapter { private List<TaskTableBean> taskTableBeans; public VP2TaskPagerAdapter(FragmentManager fragmentManager, Lifecycle lifecycle,List<TaskTableBean> taskTableBeans) { super(fragmentManager, lifecycle); this.taskTableBeans = taskTableBeans; } public void update(List<TaskTableBean> taskTableBeans) { this.taskTableBeans = taskTableBeans; notifyDataSetChanged(); } @NonNull @Override public Fragment createFragment(int position) { Fragment fragment = null; switch (getItemViewType(position)) { case 5: fragment = GroupTaskFragment.newInstance(); break; case 7: fragment = NewdiscoveryTaskFragment.newInstance(); break; case 4: fragment = new GrowthPlanFragmentMvc(); break; case 6: case 8: fragment = ExclusiveTaskFragment.newInstance(); break; case 9: fragment = ExperiencetaskFragment.newInstance(); break; case 0: case 1: case 2: case 3: fragment = NewCardFragment.newInstance(); break; case 10: fragment = TounLockFragment.newInstance(); break; } return fragment; } @Override public long getItemId(int position) { if (taskTableBeans.size() == 0||taskTableBeans.size()<=position) { return 0; } return taskTableBeans.get(position).hashCode(); } @Override public boolean containsItem(long itemId) { return false; } @Override public int getItemViewType(int position) { TaskTableBean taskTableBean = taskTableBeans.get(position); return Integer.valueOf(taskTableBean.taskType); } @Override public int getItemCount() { return taskTableBeans.size(); } }
This can solve the problem that the data is not refreshed.
Note: creation of fragment
createFragment method I think many small partners are selected by subscript through the set of fragments passed in. This method can not be updated. And that method is also easy to cause memory leakage.
If you have any questions, I hope you can raise them.