ViewPager+Fragment data source cannot be refreshed after changing

FragmentPagerAdapterPerform notifyDataSetChangedroot cause refresh is invalid, the maintenance of FragmentManagercaches added a Fragment cause, the solution naturally from the FragmentManagerstart.

1. Problem scenario

Use ViewPager+Fragment to achieve the page-turning effect of the homepage. If you are not logged in, fill in the Frament that contains the jump login:FragmentLoginNeeded

Log is as follows:5c88c3ca1f667

Note: MainFragmemtMine has its own handling of not logged in

However, after logging in and performing an notifyDataSetChangedoperation, the page is not refreshed. The refresh code is as follows:

boolean login = isLogin();  
if (login) {
    
      
    FragmentMain fragmentMain = //...
  fragments.add(fragmentMain);  
  MainFragmentPerson fragmentPerson = //。。。 
  fragments.add(fragmentPerson);  
  fragments.add(FragmentRecord.getInstance());  
  fragments.add(MainFragmentMessage.getInstance());  
} else {
    
      
    fragments.add(FragmentLoginNeeded.getInstance());  
  fragments.add(FragmentLoginNeeded.getInstance());  
  fragments.add(FragmentLoginNeeded.getInstance());  
  fragments.add(FragmentLoginNeeded.getInstance());  
}  
fragments.add(MainFragmentMine.getInstance("我的"));  
mFragments.clear();  
mFragments.addAll(fragments);  
mFragmentAdapter.notifyDataSetChanged();

At this time, the log is as follows:5c88c4cb35e14

It can be seen from the above that although the destoryoperation is performed, instantiateItemthe target of initialization is still the original object, so it is clear that the Adapter data source of ViewPager has changed, but the interface data has not changed. This is the existing problem.

Second, the source code view

The same is inheritance Adapter. In our own implementation of Adapter, after the data source changes, the Adapter.notifyDataSetChanged()data will be refreshed to the latest when executed ; but the FramentPagerAdapterrefresh is not executed, so we need to FramentPagerAdaptercheck from the source code.

In the source code of FragmentPagerAdapter, no exception was found in other methods, but instantiateItemthe handling of Fragment in the code is somewhat interesting as follows:5c8a3361efd1f

Fragment processing is achieved through FragmentManager.findFragmentByTag()(FragmentManager will cache the Fragment added to its transaction, and will be retrieved through TAG next time) The composition of the Tag is as follows: 5c8a33c5e100f
Here, it can be seen that the Tag is determined by container.getId()and getItemId(), where container.getId()The value of is the Id of the View in the Adapter, and getItemId()the value of position is returned by default:

    public long getItemId(int position) {
    
    
        return position;
    }

The combination of container ID and position controls whether to initialize a new Fragment, and does not give the Fragment any chance to change... Therefore, the way to solve the problem is to judge the Fragment each time the Item is initialized, but because the source code is correct Fragment judgment and operation involve cache optimization, so the next best thing is to clear the Fragment from the FragmentManager when destroying the item, and the problem is solved (only limited to the situation where the number is small and the initialization is completed at one time).

Three, problem solving

After the above analysis, the solution is ready at night. Rewrite the destoryItem()method: as follows.
5c8a33d54bb11
Finally, imitate the processing method in the FragmentPagerAdapter source code, and submit the transaction to OK.

    @Override
    public void finishUpdate(@NonNull ViewGroup container) {
    
    
        super.finishUpdate(container);
        if (mTransaction != null) {
    
    
            mTransaction.commitNowAllowingStateLoss();
            mTransaction = null;
        }
    }

Note: The above processing method is limited to mVpFragmentMain.setOffscreenPageLimit(4);the situation where the entire list will be initialized at the first initialization. In the case of Fragment+ViewPager, it is basically used for the home page, so it can solve most scenarios

Guess you like

Origin blog.csdn.net/u014235093/article/details/88560889