如何让fragment刷新界面_快速实现android版抖音主界面的心得

原文作者:DK_BurNIng

如何快速确定竞品某个界面的实现方式?


当你收到产品一个需求是模仿某个竞品且时间很短没有过多时间给你调研技术方案的时候,如何尽快确定这个功能的技术方案呢? 这里我给出我自己的一个小窍门,可以避免走弯路,比如先确定的方案到最后发现各种各样的原因方案不行,导致最后临时变更 方案,需求延期发布的悲剧。。。

  • Androidsdkools 首先去这个目录下 找到 monitor这个可执行文件,然后打开你想模仿的竞品页面,然后执行这个文件。
a2af0ec7a810a79bd90c87719d757a70.png

比方说抖音的主界面这种滑动整屏的东西,相信之前很多人都没做过,很多人可能以为recyclerview可以拿来做这种场景,实际上recyclerview确实可以做,但是抖音这里能看出来却是使用了viewpager来做。作为一个模仿者,为了少走弯路, 那么显然 我们也是优先要选择viewpager的。

  • 其次用这个软件,还可以看出来界面上的某个控件所属的id。这个id很重要,后面我们反编译的时候可以通过全局 搜索这个id 找到大概的源码位置,虽然都是混淆过的代码,但是大致还是能分析出一些技术细节的。 这里注意一点:很多阿里系的产品用这个方法你分析界面的时候你会发现根本没有id可以捕捉到,放心这并不是什么 阿里的黑科技反 反编译技术,而是阿里使用了诸如weex react native等类似的方案,当使用这种方案的时候, 我们是找不到id的噢,如果你大致了解weex react-native的实现方案的话你应该明白我在说些什么。
  • 反编译就用jadx就可以,足够使用。在用jadx反编译之后搜索你之前的id,就可以大概找到对应的代码位置,我就是通过 这个手段,确定了抖音使用的垂直的viewpager到底是出自于github上哪个开源控件。。。为了避免法律纠纷我这里就 不明说是用的哪个开源的垂直滑动的viewpager,有兴趣的同学可以自己玩一玩。
  • adb shell dumpsys activity | grep mFocusedActivity 这个命令是神器,可以把你当前正在显示的activity的名字 打出来,方便你更加迅速的定位竞品的代码。。
3ef714ace9456a12869ecfe44ec293a4.png

不要小看这条命令哦,很多功能当你不知道竞品是弹了一个popwindow还是一个dialoagfragment还是启动了一个透明的activity的时候,这个方法就很有用了,可以避免走很多弯路。

总结一下模仿抖音主界面的时候遇到的一些问题和解决方案。

1、抖音整体技术方案是 垂直的viewpager+下拉刷新上拉加载控件+fragment的组合方案。不管是前者还是后者我们都有成熟的开源方案可以选择,我们只是把他合并起来而已。这第一步其实并不难。

2、尽量使用FragmentStatePagerAdapter。FragmentPagerAdapter不推荐使用,可能平时我们用FragmentPagerAdapter更多, 但是要知道FragmentPagerAdapter是不会释放内存的,你不可见的fragment也是常驻内存的,像抖音这种几乎无限滑动的 短视频方案,使用FragmentPagerAdapter肯定是爆内存oom的。而用 FragmentStatePagerAdapter的话,对于不可见的 fragment,系统是自动释放内存的,内存里只会保留你能看到的fragment 和这个看到的fragment前后2个fragmnt。当然 这个值可以动态设置,但是至少都会保留3个fragment。

261966168b98f5635dee5ea3cc75ad7b.png

3、fragmentStatePagerAdapter.notifyDataSetChanged()失效? 有时候,notifyDataSetChanged方法调用了,界面却没有变化?实际上对于fragmentStatePagerAdapter来说,界面刷新不刷新 重绘不重绘 主要取决于getItemPosition方法的返回值,默认是返回 POSITION_UNCHANGED 也就是不重绘。只有 返回POSITION_NONE的时候才会重绘界面,重新绘制一遍fragemnt。 很多人不太理解什么意思,我简单描述一下场景:

比如说,我们刚进抖音的主界面,假设返回了10条视频数据,我们默认播第一条。展示的是第一个fragment,对吧。 然后这个时候我们下拉刷新又来了10条数据,我们应该播放的是新来的这10条数据的第一条。于是你等待接口返回 以后把新来的10条数据插在了我们的数据源这个数组的 头部。 然后调用了notifyDataSetChanged这个方法。 如果你没有重写getItemPosition的方法的话,这个方法默认返回POSITION_UNCHANGED,这是fragmentStatePagerAdapter就认为 我这个界面不需要重绘。所以你还是在不停的播放老的视频。 有人可能会问,我们一直加载更多的话为什么不会出现这种情况?

比方说现在的加载更多其实都是预加载,比如我们一页是返回10条数据,当我们滑到第5条数据的时候 我们可能就会自动请求下一页数据了。所以我们不停的滑动viewpager往后面滑,因为position在不停的变化,所以是不断的有新的fragment进来的。 所以不管getItemPosition 的值如何变化,针对此种情况我们都会刷新界面的。

但是对于下拉刷新这种情况就不行,因为我们默认加载的是第一条数据,我们内存里面已经有了这一条数据了,对于position 位置为0的fragment来说,他已经在内存里了,等我们下拉刷新来了新数据以后,虽然我们调用了notifyDataSetChanged方法, 但是我们发现这个位置为0的fragment 内存里已经有了啊,getItemPosition又返回了POSITION_UNCHANGED,那我就不重绘了, 这就是一个容易出bug的地方。

4、既然如此我们getItemPosition固定返回POSITION_NONE行不行? 答案是不行的,固定返回POSITION_NONE这个值,虽然可以解决下拉刷新 界面不刷新的问题,但是会引发新的问题。 主要有2:

第一,固定返回POSITION_NONE 意味着每次notifyDataSetChanged被调用的时候,我们内存里存在的三个fragment都要重新绘制这样的成本太大,低端手机明显会卡,android大部分视频播放都是软解码方案,这样的性能不行。

第二:还是上面的预加载,比方说我们第一页返回了10条数据,当我们滑到第五条数据的时候,我们预加载预先请求了第二页的时候然后第二页的数据回来以后 我们调用了notifyDataSetChanged,注意这个时候我们可能第五条数据对应的视频我们还没看完呢,比如这条短视频我们才看到第六秒,结果整个界面突然重绘了,直接又重新从第一秒开始播放。。这个体验明显不可接受。

所以我们要做的就是在需要的时候返回POSITION_NONE不需要的时候返回 POSITION_UNCHANGED ,具体的逻辑可以根据你们自己的业务进行相应的调整。

比方说我们可以判断一下,如果源数据也就是mData里面的id和正在播放的fragmetn里面的id相等话,我们就判定不需要刷新界面否则不相等,就刷一下,刚好对应加载更多和下拉刷新的2个场景。

5、如何定位内存泄漏的问题? 对于播放器来说,初次接触的团队如果没有经验,即使有b站开源播放器的帮助也会发生内存泄漏的问题,比方说我们 绘制一个播放界面,总免不了要画进度条,要展示倒计时,textview默认的跑马灯效果那么差,说不定还要自己写个自定义view来完成跑马灯的特效,这些都免不了使用线程,handler,timer等等容易发生内存泄漏的东西。所以当不停的滑动的时候, 如果被滑走的fragment没有及时被释放掉,那上线就肯定会发生oom的问题。对于android studio 3.0或者以上的版本来说:

8b18bb1e74744f47457a644068a1c76b.png
f3305d72a75ce02d6d2d135eede43968.png
45f47775d179f4da11f2eb9936659b96.png

嗯,既然mat都能读了,剩下的就不啰嗦了,网上一搜一大堆。

6、如何根据index 取对应的fragment? 这个也是比较小众的一个知识点,对于fragmentStatePagerAdapter来说,我们知道除了当前在使用的fragment,我们 还有这个fragment前后2个fragment,对于滑动操作来说,我们至少要完成 滑动到下一个fragmetn 要停止前面一个fragment 的视频播放和动画播放等等。 所以根据index 来取fragment对象就变的十分重要。

1a67943faa45d6b583c733a9c376c182.png

这里给出反射的实现:

 public static Fragment getIndexFragment(FragmentStatePagerAdapter fragmentStatePagerAdapter, int index) {        try {            Field privateArrayList = FragmentStatePagerAdapter.class.getDeclaredField("mFragments");            privateArrayList.setAccessible(true);            ArrayList mFragments = (ArrayList) privateArrayList.get(fragmentStatePagerAdapter);            return mFragments.size() > 0 ? mFragments.get(index) : null;        } catch (NoSuchFieldException e) {        } catch (IllegalAccessException e) {        }        return null;    }

同为Android开发的朋友,欢迎各位关注转发哦!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/354277.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

js的深浅拷贝( 赋值后原值被覆盖的问题 )

1,浅拷贝( 浅拷贝会复制所有引用对象的指针,而不是具体的值 ) 复制对象的所有属性都不是引用类型时,就可以使用浅拷贝 浅拷贝方式: Object.assign() [].slice()2,深拷贝( 复制一个…

使用JBoss Cool Store的终极云零售指南

我们一直在讨论为什么应用程序开发人员在App Dev Cloud Stack系列中不能再忽略其堆栈了。 带有JBoss Cool Store的App Dev Cloud 我们从头到尾讨论了各个层,但尚未为您提供除Red Hat Container Development Kit(CDK)之外的任何应用程序开发…

02.Python 3.6.4下载与安装

02.Python 3.6.4下载与安装 https://www.python.org/downloads/release/python-364/ Windows x86-64可执行文件安装程序视窗对于AMD64 / EM64T / x64,不是安腾处理器bee5746dc6ece6ab49573a9f54b5d0a131684744SIG我下载的是这个: https://www.python.or…

根据浏览器navigator区分PC端还是移动端,区分操作系统,区分浏览器型号

1,区分PC端还是移动端 methods:{_isMobile() {let flag navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i)return flag;}, }, m…

mysql 用户授权_mysql添加、删除用户和授权用户

MySql中添加用户,新建数据库,用户授权,删除用户,修改密码(注意每行后边都跟个;表示一个命令语句结束):1.新建用户1.1 登录MYSQL:>mysql -u root -p>密码1.2 创建用户:mysql> insert into mysql.user(Host,User,Password) values("localhos…

2018年1月 常用的linux命令

项目中经常用到的Linux命令 (注意:linux命令要小写哦!) (1)、ls 显示当前目录下的文件 (2)、vi vim 进入编辑器,可以选择你要编辑的文档,一般我们将项目打…

vue-element-admin中 vuex 的使用

vue-element-admin 中 vuex 是模块化的。 登录流程 1,HTTP 配置(utils/request.js) 2,API 配置(api/user.js) import request from /utils/requestexport function login(username, password) {return …

javafx2_JavaFX 2 GameTutorial第4部分

javafx2介绍 这是与JavaFX 2游戏教程相关的六个部分系列的第四部分。 如果您错过了第1部分 , 第2部分或第3部分 ,我建议您在开始本教程之前仔细阅读它们。 回顾一下,在第3部分中,我为您提供了许多经典街机风格游戏以及所使用的不同…

mysql 实体类_Mysql生成实体类

-- 查询数据表结构SELECTCONCAT(‘"e.‘,SUBSTRING(COLUMN_NAME,1),‘,"‘),COLUMN_NAME,‘,‘,COLUMN_TYPE,column_commentFROMINFORMATION_SCHEMA.COLUMNSWHERE table_schema ‘xcb‘and table_name ‘t_product‘;-- 生成Java实体类SELECTCONCAT(‘Column(name&…

vue 兄弟组件之间的传值

1. 定义一个公共的bus.js //bus.js import Vue from vue export default new Vue()2. 在子组件A里用$emit发射数据 <script> // 引入公共的bug&#xff0c;来做为中间传达的工具 import Bus from ./bus.js export default {methods: {details(data) {//发射组件A的数据…

Java 8:声明接口中的私有方法和受保护的方法

引入Java 8时&#xff0c;我们可以在接口中使用默认方法。 此功能的主要驱动程序是允许扩展接口&#xff0c;同时保留对旧接口版本的向后兼容性。 一个示例是在现有Collection类中引入stream()方法。 有时&#xff0c;当我们想引入几种默认方法时&#xff0c;它们可能共享一些…

sysbench 1.0.6 mysql_Sysbench 测试mysql数据库性能(version:sysbench-1.1.0)

继上面安装完Mysql rpm 安装之后需要用sysbench对数据库进行性能测试&#xff1a;下载git clone https://github.com/akopytov/sysbench.git或者直接去github下载&#xff1a;https://github.com/akopytov/sysbench安装前准备除了上面Mysql rpm 安装提到的需要安装的四个rpm&am…

elementUI vxe-table结合使用(通用表格)

App.vue 样式 .my-main{margin: 20px; } .dfc{display: flex;flex-direction: column; } .dfr{display: flex;flex-direction: row; } .f1{flex: 1; } .fl{float: left; } .fr{float: right; } .baseColor{background-color:RGB(48,65,86);color:#fff; }父组件 <!-- --&g…

vue.config.js 配置

// 去除 console const UglifyJsPlugin require(uglifyjs-webpack-plugin) // const path require(path); 别名配置 // 图形化打包详情 const BundleAnalyzer require(webpack-bundle-analyzer).BundleAnalyzerPluginmodule.exports {publicPath: process.env.NODE_ENV p…

mysql主从维护_mysql主从日常管理维护

mysql主从日常管理维护1)查看从服务器状态为了防止复制过程中出现故障从而导致复制进程停止&#xff0c;我们需要经常检查从服务器的复制状态。一般使用show slave status命令来检查。例如&#xff1a;mysql> show slave status \G;*************************** 1. row ****…

JLBH示例2 –协调遗漏的会计处理

在这篇文章中&#xff1a; 在运行JLBH时考虑或不考虑协调遗漏 一个示例&#xff0c;以数字说明协同遗漏的效果 关于流量控制的讨论 这是我用来描述如果不考虑协调遗漏而进行测量的情况下的示例&#xff1a; 假设您正在等待火车&#xff0c;但由于前面的火车晚了&#xff0…

基于windows平台的命令行软件安装工具Chocolatey的安装

本文介绍Chocolatey的安装和使用 Chocolatey 这是基于.NET Framework 4以上的windows安装软件的命令行工具安装 第一步&#xff0c;打开你的powershell.exe&#xff0c;使用管理员方式运行 第二步&#xff0c;运行命令 Get-ExecutionPolicy如果返回 Restricted &#xff0c;那么…

vue项目 乐橙云 轻应用直播SDK imouplayer.js

官网案例&#xff1a;https://open.imoulife.com/book/light/sdk.html 文档&#xff1a; https://open.imou.com/developDoc/31 1&#xff0c;下载 对应的资源 https://open.imoulife.com/book/readme/upload.html 2&#xff0c;引入资源 2.1 把下载的资源(static&#xff0c…

windows 开启mysql日志记录_windows下mysql日志开启与查询

修改 my.ini文件加入以下语句(在没有设置的前提下)log-errord:/log/mysql/mysql_log_err.txtlogd:/log/mysql/mysql_log.txt#log-bind:/log/mysql/mysql_log_binlog-slow-queries d:/log/mysql/mysql_log_slow.txt使用以下命令查看是否启用了日志mysql>show variables like …

jmx 复用 jmx_JMX:一些入门说明

jmx 复用 jmxJMX&#xff08;Java管理扩展&#xff09;是一种J2SE技术&#xff0c;可以管理和监视Java应用程序。 基本思想是实现一组管理对象&#xff0c;并将实现注册到平台服务器&#xff0c;在平台服务器上&#xff0c;可以使用一组连接器或适配器从本地或远程调用这些实现…