天天看点

在fragment中使用viewpager_notifyDataSetChanged()?你真的会用ViewPager吗?前言正文尾声

前言

最近发现自己有很多颇为基础的内容“不会写”了,就比如今天写的内容:ViewPager。

最近有小伙伴,在后台私信一些技术细节,大家真的好勤奋~~因为工作的原因,有些私信回复的不是很及时,多多包涵。996伤不起啊!

正文

平时我们很容易遇到这样的需求:页面底部很多Tab,可以点击或者活动切换不同的页面...估计话还没有说完,有朋友就会脱口而出: ViewPager + Fragment实现。

说起 ViewPager,日常需求中必不可少的角色。无论是轮播,还是Tab页面效果,ViewPager都帮咱们输出了成吨的伤害。

没错,今天我们就聊一聊这个“传统”的用法。

一、最最基本的写法

ViewPager + Fragment实现这种效果很简单。直接上代码:

在fragment中使用viewpager_notifyDataSetChanged()?你真的会用ViewPager吗?前言正文尾声

当然, Fragment也很简单:

在fragment中使用viewpager_notifyDataSetChanged()?你真的会用ViewPager吗?前言正文尾声
在fragment中使用viewpager_notifyDataSetChanged()?你真的会用ViewPager吗?前言正文尾声

这个效果难不倒我们。但是,我们日常需求肯定不可能这么的简单。最直接来说,如果我们页面需要动态的更换内容,怎么办?

有朋友可能会说: notifyDataSetChanged()。

二、notifyDataSetChanged()

最开始,我是这么想的:当Fragment数据需要变化时,改变 fragmentData的内容,然后调Adapter中的 notifyDataSetChanged()。比如这样:

在fragment中使用viewpager_notifyDataSetChanged()?你真的会用ViewPager吗?前言正文尾声

然而run起来,我并没有发现页面有任何的变化。并且没有发现任何方法被重新调用!这也就是说明, notifyDataSetChanged()一定需要特定的条件。

我猜踩过坑的小伙伴应该知道,此时应该重写 getItemPosition(@NonNullObjectobject)方法

那么接下来就让我们从源码中一探究竟,如何才能使 notifyDataSetChanged()生效...

三、源码分析

在fragment中使用viewpager_notifyDataSetChanged()?你真的会用ViewPager吗?前言正文尾声

而逻辑的关键就在 dataSetChage()中:

在fragment中使用viewpager_notifyDataSetChanged()?你真的会用ViewPager吗?前言正文尾声

点进 setCurrentItemInternal()方法,我们会发现细节比较多,这里我们就不深究这么多的边界条件,直接进入它内部的 populate(),而这个方法内部又会调用 addNewItem(),这个方法我们需要看一下:

在fragment中使用viewpager_notifyDataSetChanged()?你真的会用ViewPager吗?前言正文尾声

这里的实现,有一个我们比较熟悉的方法 instantiateItem()。而这个方法在 FragmentPagerAdapter里被重写了:

注意看这个方法,有很多细节藏在里边!
在fragment中使用viewpager_notifyDataSetChanged()?你真的会用ViewPager吗?前言正文尾声

看完这个方法,我们能得到俩个信息:

  • 1、如果FragmentManager能通过Tag找到Fragment的实例,那么就直接attch()上这个Fragment
  • 2、如果找不到,才会调 用getItem()去初始化这个Fragment

基于这个实现,我们就明白了。前文中因为POSITION_NONE被detach掉的Fragment在这里被attach上的。

四、解决问题

既然如此,那么对于我们开篇的那个动态改Fragment内容信息的需求,也就迎刃而解了:

这里我们只需写getItemPosition(),让 object是 TestFragment2类型的时候,返回PagerAdapter.POSITION_NONE。就可以解决这个问题了。

在fragment中使用viewpager_notifyDataSetChanged()?你真的会用ViewPager吗?前言正文尾声

detach/attach过程,会使Fragment重绘,也就是重走 onCreateView()、 onViewCreated()。因此此时我们的数据源已经发生了变化,所以Fragment重绘就可以更新为最新的数据了。

尾声

代码写的很糙,大家勿喷。主要是通过这么一个小需求,记录一下自己那些年无视的源码细节~~