免费微信网站模板下载工具,全国电子商务公共服务网,软件开发培训机构哪些比较好,网站建设开发多少钱我记得前年#xff08;2022#xff09;面试的时候有被问到 ViewPager 和 ViewPager2 有什么区别#xff1f;当时因为之前工作一直在开发售货机相关的项目#xff0c;使用的技术要求并不高#xff0c;所以一直没去了解过 ViewPager2~ 去年的时候正好有相关的功能需求#… 我记得前年2022面试的时候有被问到 ViewPager 和 ViewPager2 有什么区别当时因为之前工作一直在开发售货机相关的项目使用的技术要求并不高所以一直没去了解过 ViewPager2~ 去年的时候正好有相关的功能需求索性直接用 ViewPager2 进行了 Tip很多人可能比较关注俩者区别、变更那么我们结论先行然后再接着验证
结论先行
关于它们的区别我仅从我个人理解的角度来讲不知不觉用了好几天…
实现方面
ViewPager 继承自ViewGroup内部并未使用已有的成熟控件更多的是自定义的操作ViewPager2 也继承自ViewGroup但其内部可以明显的看到 RecyclerView 影子所以可以说是基于 RecyclerView实现那么这也意味着性能的提升毕竟ViewHodelr减少了内存开销同时RecyclerView相关方法在ViewPager2也可以看到类似封装
功能方面
TipViewPager2 新增功能是建立在 ViewPager 已有功能的基础上的扩展例如ViewPager2支持垂直滑动同时也是支持水平滑动的
ViewPager2 支持垂直方向滑动而 ViewPager 仅支持水平方向滑动扩展组件功能
关于ViewPager2新支持的RTL方向布局简单概述一下国内一般都是默认的LTR方向布局但是针对国际用户会根据语言环境阿拉伯语等自动启动从右到RTL页面如果想要设置ViewPager2布局方向可以通过设置android:layoutDirection属性或setLayoutDirection()方式
ViewPager2 支持RTL方向布局而 ViewPager 支持LTR方向布局扩展组件功能ViewPager2 DiffUtil 支持减少页面刷新频率当数据未发生变更时不必重新绘制提升用户体验
Adapter适配器方面
ViewPager2 使用的Adapter一般为PagerAdapter、及其子类 FragmentPagerAdapter、FragmentStatePagerAdapterViewPager2 既然基于RecyclerView实现那么它所使用的Adapter同理也应该基于RecyclerView.Adapter所以新增了 FragmentStateAdapter
加载方面
ViewPager 默认执行预加载如果需要懒加载的话需要自行封装ViewPager2 默认执行懒加载但是依旧可以设置预加载
API方面
监听ViewPager2 的registerOnPageChangeCallback 取代了 ViewPager的addPageChangeListener关联TabLayout ViewPager 与 TabLayout 关联用的是 TabLayout 的方法 setupWithViewPager() ViewPager2 是通过 TabLayoutMediator 类来做了个关联 年关将至 基础了解实践效果新增功能源码解析 变更场景ViewPager、ViewPager2 中 引用对比ViewPager、ViewPager2 中 Adapter区别对比ViewPager、ViewPager2 中 Adapter使用对比ViewPager、ViewPager2 中 监听对比ViewPager、ViewPager2 中 预加载、懒加载对比ViewPager、ViewPager2 关联TabLayout从ViewPager 迁移到 ViewPager2 实战演练Demo版本前置配件ViewPager 使用方式ViewPager2 使用方式ViewPager、ViewPager2 一起使用 项目版本 有趣的小问题java.lang.IllegalStateException: Fragment already added 基础了解
实践效果
Demo效果 项目效果 新增功能 如果想了解 ViewPager2我觉得最好的方式可能就是跟着 ViewPager2官方文档 简单的过一下版本的更新情况 从更新记录可以看出部分 ViewPager、ViewPager2 区别
ViewPager2 支持 RTL布局Right To LeftViewPager 仅支持LTR布局ViewPager2 支持 水平方向、垂直方向类似抖音、快手垂直切换视频的场景ViewPager 仅支持横向滑动水平方向DiffUtil 支持减少页面刷新频率当数据未发生变更时不必重新绘制 记得好早以前就有类似工具不过现在很多框架内部都做了Diff操作
2019年2月7日 ViewPager2 应运而生首个测试版本 2019年11月20日 ViewPager2 出了首个稳定的正式版本
源码解析
查看 ViewPager 可以看到其继承自 ViewGroup 同时 内部貌似并未使用现有的View控件 查看 ViewPager2 发现它虽然同样继承自ViewGroup 但其内部却是基于 RecyclerView 实现的故 RecyclerView 具备的方法 ViewPager2 也可以尝试调用常见的类似于LayoutManager、ItemDecorator等类似方法 例如 ViewPager2 支持垂直方向滑动就提供了setOrientation 方法默认水平方向那么通过源码可以看出这种方式其实类似RecyclerView设置 LayoutManager 方式 setOrientation 方向提供了 ORIENTATION_HORIZONTAL、ORIENTATION_VERTICAL在动态设置中伪代码 viewPager2.orientation ORIENTATION_VERTICAL 变更场景
ViewPager、ViewPager2 中 引用对比
记得以前调用的是Suppor V4包下的 ViewPager但现在不论是 ViewPager、ViewPager2 都直接在 androidx 内了基本创建项目后就可以直接引用了 ViewPager、ViewPager2 中 Adapter区别对比
ViewPager 源码注释中其实已经解释了Adapter相关内容 ViewPager 使用的 Adapter 主要是 PagerAdapter 及其子类FragmentPagerAdapter、FragmentStatePagerAdapter俩者的主要区别如下
FragmentPagerAdapter 支持缓存FragmentStatePagerAdapter 不支持缓存
PagerAdapter PagerAdapter 子类 ViewPager2 - API变更 ViewPager2 使用的 Adapter 主要是 RecyclerView.Adapter 的子类 FragmentStateAdapter它也继承了RecyclerView的优点内置了FragmentViewHolder提升了性能 FragmentStateAdapter FragmentStateAdapter 提供了三种构造参数支持绑定组件的生命周期 FragmentViewHolder ViewPager、ViewPager2 中 Adapter使用对比 以前我在别的知识结构 也曾引用过ViewPager如有需要也可以借鉴下 对比后发现继承的 Adapter 和重写方法命名发生变更此处主要说 API变更
ViewPager2 getItemCount 等于 ViewPager 中的 getCountViewPager2 createFragment 等于 ViewPager 中的 getItem
ViewPager
PagerAdapter的子类Adapter已经被标记过时了最好还是开始用ViewPager2吧 示例 class viewPager1Adapter(manager: FragmentManager):FragmentStatePagerAdapter(manager){override fun getCount(): Int {TODO(Not yet implemented)}override fun getItem(position: Int): Fragment {TODO(Not yet implemented)}}ViewPager2 class viewPager2Adapter(fragment: FragmentActivity):FragmentStateAdapter(fragment){override fun getItemCount(): Int {TODO(Not yet implemented)}override fun createFragment(position: Int): Fragment {TODO(Not yet implemented)}}ViewPager、ViewPager2 中 监听对比
ViewPager、ViewPager2 监听的内容相同只有API简单变更了一下
ViewPager 通过 addOnPageChangeListener 添加监听 viewPager1.addOnPageChangeListener(object :OnPageChangeListener{override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {TODO(Not yet implemented)}override fun onPageSelected(position: Int) {TODO(Not yet implemented)}override fun onPageScrollStateChanged(state: Int) {TODO(Not yet implemented)}})ViewPager2 通过 registerOnPageChangeCallback 添加监听注册函数一般都有unregister函数不用的时候可以顺手注销一下防止内存泄露 viewPager2.registerOnPageChangeCallback(object : OnPageChangeCallback() {override fun onPageScrollStateChanged(state: Int) {super.onPageScrollStateChanged(state)}override fun onPageSelected(position: Int) {super.onPageSelected(position)Log.e(tag,position.toString())}override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {super.onPageScrolled(position, positionOffset, positionOffsetPixels)}})ViewPager、ViewPager2 中 预加载、懒加载对比 首先要明确一个概念不论是 ViewPager、ViewPager2都支持预加载 预加载的意义在于不必让用户每次都等切换页面后才执行接口请求、页面绘制等操作而是直接显示效果不过这样做性能开销方面会大一些用户体验有时候需要看加载元素的多少而决定
懒加载顾名思义只有在用户需要的时候才去执行其实现的核心意义在于
是否为当前页面是否可见是否已经加载过了视图是否初始化完成setUserVisibleHint()的调用在onCreateView之前
预加载区别
ViewPager 默认调用了预加载方法且默认预加载值为1一般加载当前视图的左右相邻视图
相关源码 ViewPager2 默认不进行预加载相对应的预加载方法值为-1
相关源码 懒加载区别
ViewPager 并未实现懒加载如果需要懒加载的话需要自行实现通常在 Fragment 场景下就是重写 setUserVisibleHint方法然后继承于该基类ViewPager2 默认实现了懒加载 主要是通过 Lifecycle 对 Fragment 的生命周期进行管理 ViewPager、ViewPager2 关联TabLayout
因为我在项目中的 TabLayout 部分布局需要自定义一下所以并未直接使用 TabLayout有机会在详细说吧
ViewPager 和 TabLayout 的代码关联用的是 TabLayout 的方法 setupWithViewPager()ViewPager2 和 TabLayout 的代码关联是通过 TabLayoutMediator 类来做了关联 从ViewPager 迁移到 ViewPager2
具体迁移操作可参考 从 ViewPager 迁移到 ViewPager2 实战演练
关于ViewPager2的使用也可以看 官网代码示例views-widgets-samples/ViewPager2
因为我Demo中并未结合TabLayout一起使用如有需求也可以前往 用户指南使用 ViewPager2 创建包含标签的滑动视图
Demo版本 同个页面使用ViewPager、ViewPager2 遇到一个有趣的场景最后有讲到原因与处理方式 我写Demo时为了更直观的对比所以将 ViewPager、ViewPager2 一起使用但是在使用时我分别简单讲解了不同的使用方式和综合方式
前置配件
activity_main
?xml version1.0 encodingutf-8?
androidx.appcompat.widget.LinearLayoutCompat xmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:apphttp://schemas.android.com/apk/res-autoxmlns:toolshttp://schemas.android.com/toolsandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:orientationverticaltools:context.MainActivityandroidx.viewpager.widget.ViewPagerandroid:idid/view_pager1android:layout_widthmatch_parentandroid:layout_height0dpandroid:layout_weight1android:background#f78744 /androidx.viewpager2.widget.ViewPager2android:idid/view_pager2android:layout_widthmatch_parentandroid:layout_height0dpandroid:layout_weight1android:background#d589 //androidx.appcompat.widget.LinearLayoutCompatTipDemo内的AFragment、BFragment基本一致直接copy修改下想要布局就好
AFragment
package com.example.viewpager2import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
class AFragment: Fragment() {override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {return LayoutInflater.from(this.requireContext()).inflate(R.layout.fragment_a,null)}
}fragment_a
?xml version1.0 encodingutf-8?
LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/androidandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentTextViewandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:textA-Fragmentandroid:gravitycenterandroid:textStylebold/
/LinearLayoutViewPager 使用方式
package com.example.viewpager2import android.annotation.SuppressLint
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentStatePagerAdapter
import androidx.viewpager.widget.ViewPager
import androidx.viewpager.widget.ViewPager.OnPageChangeListenerclass MainActivity : AppCompatActivity() {SuppressLint(MissingInflatedId)private var fragmentList: MutableListFragment mutableListOf()private var fragmentListA: MutableListFragment mutableListOf()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)var viewPager1 findViewByIdViewPager(R.id.view_pager1)//初始化数据fragmentList.add(AFragment())fragmentList.add(BFragment())//ViewPager使用val viewPager1Adapter ViewPager1Adapter(supportFragmentManager,fragmentList)viewPager1.setOffscreenPageLimit(0);viewPager1.adapter viewPager1Adapter
//viewPager1.addOnPageChangeListener(object : OnPageChangeListener {override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}override fun onPageSelected(position: Int) {}override fun onPageScrollStateChanged(state: Int) {}})}inner class ViewPager1Adapter(manager: FragmentManager, fragmentList: MutableListFragment) : FragmentStatePagerAdapter(manager) {var manager: FragmentManagervar fragmentList: MutableListFragment mutableListOf()init {this.manager managerthis.fragmentList fragmentList}override fun getCount(): Int {return fragmentList.size}override fun getItem(position: Int): Fragment {return fragmentList[position]}}
}ViewPager2 使用方式
package com.example.viewpager2import android.annotation.SuppressLint
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentStatePagerAdapter
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2
import androidx.viewpager2.widget.ViewPager2.ORIENTATION_VERTICAL
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallbackclass MainActivity : AppCompatActivity() {SuppressLint(MissingInflatedId)private var fragmentList: MutableListFragment mutableListOf()private var fragmentListA: MutableListFragment mutableListOf()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)var viewPager2 findViewByIdViewPager2(R.id.view_pager2)//初始化数据fragmentList.add(AFragment())fragmentList.add(BFragment())//ViewPager2使用val viewPager2Adapter ViewPager2Adapter(this)viewPager2.orientation ORIENTATION_VERTICALviewPager2.adapter viewPager2AdapterviewPager2.registerOnPageChangeCallback(object : OnPageChangeCallback() {override fun onPageScrollStateChanged(state: Int) {super.onPageScrollStateChanged(state)}override fun onPageSelected(position: Int) {super.onPageSelected(position)Log.e(tag, position.toString())}override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {super.onPageScrolled(position, positionOffset, positionOffsetPixels)}})}inner class ViewPager2Adapter(fragment: FragmentActivity) : FragmentStateAdapter(fragment) {override fun getItemCount(): Int {return fragmentListA.size}override fun createFragment(position: Int): Fragment {return fragmentListA[position]}}
}ViewPager、ViewPager2 一起使用
为什么我会用到俩个List最后告诉你...
package com.example.viewpager2import android.annotation.SuppressLint
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentStatePagerAdapter
import androidx.viewpager.widget.ViewPager
import androidx.viewpager.widget.ViewPager.OnPageChangeListener
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2
import androidx.viewpager2.widget.ViewPager2.ORIENTATION_VERTICAL
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallbackclass MainActivity : AppCompatActivity() {SuppressLint(MissingInflatedId)private var fragmentList: MutableListFragment mutableListOf()private var fragmentListA: MutableListFragment mutableListOf()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)var viewPager1 findViewByIdViewPager(R.id.view_pager1)var viewPager2 findViewByIdViewPager2(R.id.view_pager2)//初始化数据fragmentList.add(AFragment())fragmentList.add(BFragment())fragmentListA.add(AFragment())fragmentListA.add(BFragment())//ViewPager使用val viewPager1Adapter ViewPager1Adapter(supportFragmentManager,fragmentList)viewPager1.setOffscreenPageLimit(0);viewPager1.adapter viewPager1Adapter
//viewPager1.addOnPageChangeListener(object : OnPageChangeListener {override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}override fun onPageSelected(position: Int) {}override fun onPageScrollStateChanged(state: Int) {}})//ViewPager2使用val viewPager2Adapter ViewPager2Adapter(this)viewPager2.orientation ORIENTATION_VERTICALviewPager2.adapter viewPager2AdapterviewPager2.registerOnPageChangeCallback(object : OnPageChangeCallback() {override fun onPageScrollStateChanged(state: Int) {super.onPageScrollStateChanged(state)}override fun onPageSelected(position: Int) {super.onPageSelected(position)Log.e(tag, position.toString())}override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {super.onPageScrolled(position, positionOffset, positionOffsetPixels)}})}inner class ViewPager1Adapter(manager: FragmentManager, fragmentList: MutableListFragment) : FragmentStatePagerAdapter(manager) {var manager: FragmentManagervar fragmentList: MutableListFragment mutableListOf()init {this.manager managerthis.fragmentList fragmentList}override fun getCount(): Int {return fragmentList.size}override fun getItem(position: Int): Fragment {return fragmentList[position]}}inner class ViewPager2Adapter(fragment: FragmentActivity) : FragmentStateAdapter(fragment) {override fun getItemCount(): Int {return fragmentListA.size}override fun createFragment(position: Int): Fragment {return fragmentListA[position]}}
}项目版本 因为是在项目中使用的实践场景所以只留伪代码做个记录部分框架特有的方法可先行忽略、部分业务逻辑亦可忽略只看类似 TabLayout ViewPager2的效果即可 Activity → Fragment数据共享采用了ViewModel接口返回数据监听采用了LiveData有兴趣的可以前往进阶
组件化之路 - ViewModel一知半解组件化之路 - LiveData一知半解组件化之路 - LiveData ViewModel一知半解
组件中可以有多个ViewModel在这里为了区分功能一个 FundSmileViewModel 用于网络请求等逻辑操作一个 FundCodeViewModel 用于存放共享数据当然也可以只用一个
package cn.com.xximport android.graphics.Color
import android.os.Bundle
import androidx.activity.viewModels
import androidx.core.graphics.toColorInt
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2
import dagger.hilt.android.AndroidEntryPointAndroidEntryPoint
class FundAndSmileActivity : BaseActivity() {private val binding by lazy { ActivityPurchaseAndSmileBinding.inflate(layoutInflater) }private val fundCodeViewModel by viewModelsFundCodeViewModel()private val viewModel by viewModelsFundSmileViewModel()private lateinit var fundCode: Stringprivate var fragmentList: MutableListFragment mutableListOf()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(binding.root)ActivityTaskManager.getManager(TaskTag.FIXED_SMILE).addActivity(this)statusBar()setData()loadingState(LoadingState.LoadingStart)viewModel.requestFundControl5010(fundCode)binding.ivImgTag.isVisible SPUtils.AppSP().get(fundSmileTag, 0) 0viewModel.smileState.observe(this) {loadingState(LoadingState.LoadingEnd)binding.llTab.isVisible itfragmentList.clear()fragmentList.add(FundFixedCreateFragment())if (it) fragmentList.add(SmileInvestmentCreateFragment())initView()}}fun statusBar() {statusBarDarkView(binding.statusBar)binding.titleBarBg.setBackgroundColor(Color.WHITE)binding.titleBar.setLeftImageAction(R.drawable.icon_base_nav_back_black) { onBackPressedDispatcher.onBackPressed() }binding.titleBar.setTitle(text 定投设置, textColor #484848.toColorInt(), medium true)binding.titleBar.setDividerState(color #eeeeee.toColorInt())}fun setData() {fundCode intent.getStringExtra(fundCode) ?: val pickerParams1 intent?.getParcelable(pickerParams1, PickerParams::class)val pickerParams2 intent?.getParcelable(pickerParams2, PickerParams::class)fundCodeViewModel.putFundCode(fundCode)pickerParams1?.let { fundCodeViewModel.putPickerParams1(it) }pickerParams2?.let { fundCodeViewModel.putPickerParams2(it) }}fun initView() {val pagerAdapter PagerAdapter(this)binding.viewPage.isUserInputEnabled false;//禁止滑动binding.viewPage.adapter pagerAdapterbinding.viewPage.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {override fun onPageSelected(position: Int) {tabState(position)}})binding.llTab1.setOnClickListener {tabState(0)binding.viewPage.currentItem 0}binding.llTab2.setOnClickListener {tabState(1)binding.viewPage.currentItem 1}}fun tabState(state: Int) {binding.tvTabTitle1.setTextColor(#333333.toColorInt())binding.tvTabDesc1.setTextColor(#999999.toColorInt())binding.viewTab1.setBackgroundColor(#F9F9FA.toColorInt())binding.tvTabTitle2.setTextColor(#333333.toColorInt())binding.tvTabDesc2.setTextColor(#999999.toColorInt())binding.viewTab2.setBackgroundColor(#F9F9FA.toColorInt())if (state 0) {binding.tvTabTitle1.setTextColor(#1760EA.toColorInt())binding.tvTabDesc1.setTextColor(#801760EA.toColorInt())binding.viewTab1.setBackgroundColor(#1760EA.toColorInt())} else {binding.tvTabTitle2.setTextColor(#1760EA.toColorInt())binding.tvTabDesc2.setTextColor(#801760EA.toColorInt())binding.viewTab2.setBackgroundColor(#1760EA.toColorInt())binding.ivImgTag.isVisible falseSPUtils.AppSP().put(fundSmileTag, 1)}}inner class PagerAdapter(fragment: FragmentActivity) : FragmentStateAdapter(fragment) {override fun getItemCount(): Int {return fragmentList.size}override fun createFragment(position: Int): Fragment {return fragmentList[position]}}
}activity_purchase_and_smileActivityPurchaseAndSmileBinding
Tip部分自定义控件自行取舍、更换即可
?xml version1.0 encodingutf-8?
LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:apphttp://schemas.android.com/apk/res-autoxmlns:toolshttp://schemas.android.com/toolsandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:orientationverticaltools:ignoreMissingDefaultResourceLinearLayoutandroid:idid/title_bar_bgandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:backgrounddrawable/drawable_title_bar_blueandroid:orientationverticalapp:layout_constraintEnd_toEndOfparentapp:layout_constraintStart_toStartOfparentapp:layout_constraintTop_toTopOfparentViewandroid:idid/status_barandroid:layout_widthmatch_parentandroid:layout_height0dptools:layout_height28dp /cn.com.ui.widgets.TitleBarandroid:idid/title_barandroid:layout_widthmatch_parentandroid:layout_height?actionBarSizetools:layout_height48dp //LinearLayoutLinearLayoutandroid:idid/ll_tabandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:background#F9F9FAandroid:orientationhorizontalandroid:visibilitygonetools:ignoreMissingConstraintstools:visibilityvisibleLinearLayoutandroid:layout_marginStart12dpandroid:idid/ll_tab1android:layout_width0dpandroid:layout_heightmatch_parentandroid:layout_weight1android:gravitycenterandroid:orientationverticalcn.com.acts.ui.widgets.MediumTextViewandroid:idid/tv_tab_title1android:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:layout_marginTopdimen/mp_8android:text普通定投android:textColor#1760EAandroid:textSize16dpapp:mediumTexttrue /TextViewandroid:idid/tv_tab_desc1android:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:layout_marginTop1dpandroid:text定期定额android:textColor#801760EAandroid:textSize12dp /Viewandroid:idid/view_tab1android:layout_widthmatch_parentandroid:layout_height2dpandroid:layout_marginTop4dpandroid:background#1760EA //LinearLayoutLinearLayoutandroid:idid/ll_tab2android:layout_width0dpandroid:layout_heightmatch_parentandroid:layout_weight1android:gravitycenterandroid:layout_marginEnd12dpandroid:orientationverticalLinearLayoutandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:orientationhorizontalcn.com.acts.ui.widgets.MediumTextViewandroid:idid/tv_tab_title2android:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:layout_marginTopdimen/mp_8android:text微笑智能定投android:textColor#1760EAandroid:textSize16dpapp:mediumTexttrue /ImageViewandroid:idid/iv_img_tagandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:layout_marginTopdimen/mp_5android:srcdrawable/icon_fund_smile_top_right_tagandroid:visibilitygonetools:visibilityvisible //LinearLayoutTextViewandroid:idid/tv_tab_desc2android:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:layout_marginTop1dpandroid:text定期不定额 全新智能模型android:textColor#801760EAandroid:textSize12dp /Viewandroid:idid/view_tab2android:layout_widthmatch_parentandroid:layout_height2dpandroid:layout_marginTop4dpandroid:background#1760EA //LinearLayout/LinearLayoutandroidx.viewpager2.widget.ViewPager2android:idid/view_pageandroid:layout_widthmatch_parentandroid:layout_height0dpandroid:layout_weight1 //LinearLayout有趣的小问题java.lang.IllegalStateException: Fragment already added
当我在Activity中同时设置ViewPager、ViewPager2的Adapter时引用同一份数据源报了以下错误
Tip从错误来看标明Fragment已经被添加过了具体原因是当我们添加一个Fragment到Activity中FragmentManager会负责管理Fragment生命周期和状态如果尝试多次添加同一个Fragment实例就会报以下错误 知道报错原因那么解决方案就由之而来故最终我在 ViewPager、ViewPager2 一起使用 中分别使用了不同的数据源曲线救国非最优解~
以下个人瞎捉摸可忽略我扭头看了一下 fragmentList 仅添加了一次数据为什么会有重复实例 然后我就看到了ViewPager、ViewPager2所使用 Adapter构造的不同获取FragmentManager后涉及到了组件 lifecycle
FragmentStatePagerAdapter FragmentStateAdapter