Android 动态更新Viewpager+fragment完美解决方案

2024-09-03 06:58

本文主要是介绍Android 动态更新Viewpager+fragment完美解决方案,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

最近遇到个问题,一直没有找到很好的解决方案,今天终于解决了。

Viewpager嵌套多个Fragment

  1. 现在我要改变fragment中的数据。

    这个非常的简单,网上有很多答案都能解决。

  2. 改变Viewpager的数量,也就是说我要动态的增加或者删除Viewpager的页面数量。

    这个就非常操蛋了。

查遍资料,才找到解决办法。写下来备忘。

从FragmentPagerAdapter的运行机制中找解决办法

通常使用FragmentPagerAdapter都会另外写个类,继承自FragmentPagerAdapter,类似下面的写法

    public class MyFragmentPagerAdapter extends FragmentPagerAdapter {public MyFragmentPagerAdapter(FragmentManager fm) {super(fm);}@Overridepublic Fragment getItem(int position) {return NewsListFragment.newInstance(myUrls.get(position));}@Overridepublic int getCount() {return myUrls.size();}}

以上只是个简单示例,链表正常是应该写在里面的。

之前查资料看网上的答案是,复写 getItemPosition 方法,让其每次都调用getItem 方法加载新的内容,以此达到动态更新viewPager的目的。代码如下

@Override
public int getItemPosition(Object object) {//return super.getItemPosition(object);return POSITION_NONE;
}

实际上,这种方法在使用FragmentPagerAdapter 时时行不通的。FragmentPagerAdapter中有一个 instantiateItem方法,此方法会在 getItem 之前被调用。看下源码:

@Overridepublic Object instantiateItem(ViewGroup container, int position) {if (mCurTransaction == null) {mCurTransaction = mFragmentManager.beginTransaction();}final long itemId = getItemId(position);// Do we already have this fragment?String name = makeFragmentName(container.getId(), itemId);Fragment fragment = mFragmentManager.findFragmentByTag(name);if (fragment != null) {if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);mCurTransaction.attach(fragment);} else {fragment = getItem(position);if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);mCurTransaction.add(container.getId(), fragment,makeFragmentName(container.getId(), itemId));}if (fragment != mCurrentPrimaryItem) {fragment.setMenuVisibility(false);fragment.setUserVisibleHint(false);}return fragment;}

可以看到,getItem 是在此方法中调用的。这里大概的意思是,每次getItem之前,都会判断有无这个fragment,如果有,就直接创建,如果没有,则调用getItem 得到一个fragment。

之所以这么做,大概是为了运行效率吧,毕竟fragment还是很大的,每次都去重新创建,太耗性能了。所以,我们要如何来更新fragment ?

网上的几种方法 大概的原因是 复写instantiateItem 方法,来做相关处理。但是实际使用中,当我增加或删除页面数量时,就会出问题。

所以,尝试另外一种方法。上面的instantiateItem 方法中,保存tag时,使用的是 itemId作为标识,所以当我们改变了数据时,去改变一下 ID不就好了?

public class MyFragmentPagerAdapter extends FragmentPagerAdapter {private long baseId = 0;public MyFragmentPagerAdapter(FragmentManager fm) {super(fm);}//        @Override
//        public int getItemPosition(Object object) {
//            //return super.getItemPosition(object);
//            return POSITION_NONE;
//        }@Overridepublic long getItemId(int position) {// give an ID different from position when position has been changedreturn baseId + position;}@Overridepublic Fragment getItem(int position) {return NewsListFragment.newInstance(myUrls.get(position));}/*** 更新fragment的数量之后,在调用notifyDataSetChanged之前,changeId(1) 改变id,改变tag* @param n*/public void changeId(int n) {// shift the ID returned by getItemId outside the range of all previous fragmentsbaseId += getCount() + n;}@Overridepublic int getCount() {return myUrls.size();}@Overridepublic CharSequence getPageTitle(int position) {return myUrls.get(position).getName();}}

首先增加了个 baseId 作为标识。

myUrls 只是我的一个链表数据,这个忽略掉就行。

增加了一个 changeId 方法,用来改变 ID,重写 getItemId方法。

所以此时,当我需要改变Viewpager中的fragment的数量或者数据时,先调用 changeId 方法,再调用notifyDataSetChanged ,如下:

mAdapter.changeId(1);
mAdapter.notifyDataSetChanged();
mViewpager.setAdapter(mAdapter);

此时,由于id不一样,所以FragmentPagerAdapter 会认为现在的 fragment和之前创建的fragment都不一样,从而调用getItem 来重新加载。从而达到 既可以改变数据,也能动态增加删除fragment的效果。

参考:http://stackoverflow.com/questions/10396321/remove-fragment-page-from-viewpager-in-android

原文:http://539go.com/2016/09/01/Android-%E5%8A%A8%E6%80%81%E6%9B%B4%E6%96%B0Viewpager+fragment%E5%AE%8C%E7%BE%8E%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/

这篇关于Android 动态更新Viewpager+fragment完美解决方案的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1132345

相关文章

java.sql.SQLTransientConnectionException连接超时异常原因及解决方案

《java.sql.SQLTransientConnectionException连接超时异常原因及解决方案》:本文主要介绍java.sql.SQLTransientConnectionExcep... 目录一、引言二、异常信息分析三、可能的原因3.1 连接池配置不合理3.2 数据库负载过高3.3 连接泄漏

Java使用Javassist动态生成HelloWorld类

《Java使用Javassist动态生成HelloWorld类》Javassist是一个非常强大的字节码操作和定义库,它允许开发者在运行时创建新的类或者修改现有的类,本文将简单介绍如何使用Javass... 目录1. Javassist简介2. 环境准备3. 动态生成HelloWorld类3.1 创建CtC

C#文件复制异常:"未能找到文件"的解决方案与预防措施

《C#文件复制异常:未能找到文件的解决方案与预防措施》在C#开发中,文件操作是基础中的基础,但有时最基础的File.Copy()方法也会抛出令人困惑的异常,当targetFilePath设置为D:2... 目录一个看似简单的文件操作问题问题重现与错误分析错误代码示例错误信息根本原因分析全面解决方案1. 确保

504 Gateway Timeout网关超时的根源及完美解决方法

《504GatewayTimeout网关超时的根源及完美解决方法》在日常开发和运维过程中,504GatewayTimeout错误是常见的网络问题之一,尤其是在使用反向代理(如Nginx)或... 目录引言为什么会出现 504 错误?1. 探索 504 Gateway Timeout 错误的根源 1.1 后端

C# LiteDB处理时间序列数据的高性能解决方案

《C#LiteDB处理时间序列数据的高性能解决方案》LiteDB作为.NET生态下的轻量级嵌入式NoSQL数据库,一直是时间序列处理的优选方案,本文将为大家大家简单介绍一下LiteDB处理时间序列数... 目录为什么选择LiteDB处理时间序列数据第一章:LiteDB时间序列数据模型设计1.1 核心设计原则

Android协程高级用法大全

《Android协程高级用法大全》这篇文章给大家介绍Android协程高级用法大全,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友跟随小编一起学习吧... 目录1️⃣ 协程作用域(CoroutineScope)与生命周期绑定Activity/Fragment 中手

SpringBoot3匹配Mybatis3的错误与解决方案

《SpringBoot3匹配Mybatis3的错误与解决方案》文章指出SpringBoot3与MyBatis3兼容性问题,因未更新MyBatis-Plus依赖至SpringBoot3专用坐标,导致类冲... 目录SpringBoot3匹配MyBATis3的错误与解决mybatis在SpringBoot3如果

C++ vector越界问题的完整解决方案

《C++vector越界问题的完整解决方案》在C++开发中,std::vector作为最常用的动态数组容器,其便捷性与性能优势使其成为处理可变长度数据的首选,然而,数组越界访问始终是威胁程序稳定性的... 目录引言一、vector越界的底层原理与危害1.1 越界访问的本质原因1.2 越界访问的实际危害二、基

MySQL 数据库表操作完全指南:创建、读取、更新与删除实战

《MySQL数据库表操作完全指南:创建、读取、更新与删除实战》本文系统讲解MySQL表的增删查改(CURD)操作,涵盖创建、更新、查询、删除及插入查询结果,也是贯穿各类项目开发全流程的基础数据交互原... 目录mysql系列前言一、Create(创建)并插入数据1.1 单行数据 + 全列插入1.2 多行数据

Python 字符串裁切与提取全面且实用的解决方案

《Python字符串裁切与提取全面且实用的解决方案》本文梳理了Python字符串处理方法,涵盖基础切片、split/partition分割、正则匹配及结构化数据解析(如BeautifulSoup、j... 目录python 字符串裁切与提取的完整指南 基础切片方法1. 使用切片操作符[start:end]2