android问题及其解决-优化listView卡顿和如何禁用ListView的fling

问题解决-优化listView卡顿和如何禁用ListView的fling

前戏很长

问题产生

这算是刚到实习公司接触到的第一个任务。公司某一产品中某个界面的listView快速滑动会有卡顿的现象发生,我的任务就是解决它。

产生原因分析

我一开始的想法比较简单,可能是listview的优化没有做到位,例如convertView的复用、viewHolder的使用等等基础的优化措施,然并卵。好长时间后终于找到了问题发生的相关代码...经过在可疑语句上(onTouchEvent方法中的几个case、onScrollStateChanged方法中的SCROLLSTATEXXX状态下)打印log,发现如下几个问题和卡顿现象有关系:

  1. 在每天固定的一个时间段内,listView展示的数据室实时刷新的,也就是服务器会定时向客户端发送数据刷新的信息,客户端再向服务器发出数据请求,客户端主要属于被动刷新;其他时间段只是单由客户端想服务区主动发数据请求。
  2. listView展示的数据是分页请求的,根据滚动位置来动态请求某一段数据。
  3. 根据打印的log,在执行到onScrollStateChanged方法中,也就是说当前listView的状态时滚动状态(包括fling)时,中间可能会插入数据请求的log。
  4. 经过请教导师,问题原因缩小到了数据请求、数据解析更新界面导致的卡顿。

于是再看代码,发现原因在于接受数据、解析数据、更新listView的Adapter内容的代码,没有和listView的滑动状态相关联,即滑动过程中可能就接收到了新数据并刷新了界面,造成卡顿。

问题初解思路

主要是滑动和数据接收更新界面之间的冲突,二者通过一个boolean变量关联一下即可。即只有在scrollState为IDLE时,才允许进行数据接收和界面刷新(调用notifyAdapterDataChanged方法),其他状态(FLING,TOUCH_SCROLL)都不允许。 而在服务器活跃的时间段之外,原本的代码中也是在滑动结束后才主动发起数据请求的,所以这方面不用考虑。

问题再发生

但是组长提出,可能会发生这样的问题,在滑动过程中数据不接收,会发生数据丢失的问题,这个应用本身对数据的实时性很高,所以这个也需要解决。

问题再解

测试了一下发现,卡顿的原因主要在于界面的刷新而不是数据接收,于是将控制范围缩小到了:只有在不滑动的状态下才允许更新界面,而数据接收在滑动过程中也可执行。保留最新接收到的数据即可。在滑动结束后及时判断有无最新的数据缓存。

问题再再提出——disable fling

组长的老板感觉还是卡顿...这次问清楚了,竟然觉得界面上滑块的移动有一顿一顿很难受...我和另一个前辈对此真是相当无语了。最后没办法了,组长说那就把这个fling的功能给禁止了吧...

fling问题研究

百度搜索关键词“android listView fling”,出现的第一条就是下面这个,【Andorid
X 项目笔记】禁用ListView的Fling功能(1)
,可是也是然并卵... ``` /** 手势识别类 */ private class TouchGesture extends SimpleOnGestureListener {

    /** 快速滚动 */
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        return true;
    }

}

private OnTouchListener mOnListViewTouchListener = new OnTouchListener() {

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (mTouchGesture.onTouchEvent(event))
            return true;
        return false;
    }
};

```

代码中mTouchGesture根本没有onTouchEvent(event)这个方法啊啊啊啊啊啊...一开始我是很开心的....
然后就是各种百度,各种google,各种“静态流”(stackOverFlow的中文备案名称,我也是醉了),都没有个能用的解决方案。 其中可以使用但是不能达到要求的一段代码我觉得不错,留下链接-Android
listview垂直滑动指定距离
,利用反射的原理,从AbsListView中找到一个相对来说比较通用的方法boolean
trackMotionScroll(int deltaY, int incrementalDeltaY)
来达到控制滑动距离的目的。以后可能用得上。

禁止fling思路

整整困扰了我三天,既然不能从正面刚,那从侧面试试看吧。于是开始查询事件分发机制、fling的实现方式、fling的触发条件、scroll的相关内容...其中比较有用的是

  1. fling的触发是一系列的ACTIONXXX事件结合的结果,用户触摸屏幕后快速滑动,出现一个ACTIONDOWN,多个ACTIONMOVE和一个ACTIONUP相结合。链接-Android:
    触屏fling/scroll/drag的区别及其详细过程
  2. 触摸事件分发就比较复杂了,主要涉及到三个重要的方法,分别是dispatchTouchEvent涉及事件分发,onInterceptTouchEvent涉及事件拦截和onTouchEvent涉及事件处理。遇到几次和这个相关的问题,每次都得查看相关的知识点...总是记不住。链接-Android
    触摸事件分发ViewGroup&View
    多看几遍就看懂了。
  3. VelocityTracker这个类是用来测量滑动速度的。链接-手势事件:滑动动速度跟踪类VelocityTracker介绍
  4. AbsListView中,滑动达到了一定的速度,就会触发fling,而在AbsListView的源码中是由一个runnable的自定义类来完成的,太复杂所以没怎么看,但是有空了是一定要仔细研究的。

那么从上面这几点可以总结出一个结论,就是fling是由touch事件来控制的,而touch事件是由view&viewGroup来进行分发、拦截、相应的。今天早上起床的一个念头就是解决问题的方法:

拦截掉touch事件来从源头上打破触发fling的事件链,从而达到禁止fling的目的

说干就干,到了公司,找到问题发生的listView,找到容纳该listView的viewGroup(是一个LinearLayout的子类),将那三个touch函数写下了,打印log分析,从哪里拦截,拦截哪个事件比较好。最终决定在dispatchTouchEvent中拦截,在ACTION_UP中判断当前滑动在y(纵轴)方向上的速度,当速度达到某一个阀值后,return
false
,也就是将可以出发fling的事件链中最后一个事件给消灭掉,不传给子view。试了一下,果然好使!

总结

对公司项目代码还是不熟,大部分事件都花在定位问题代码上面了。再加上解决问题的积累还是不够,不能从根本上考虑,处处碰壁之后才想到从源头上来解决。其实我感觉解决问题的根本还是看一个人的知识积累和知识整合的能力,“熟读唐诗三百首”就是这个道理。

额外补充

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-06 20:08:37

android问题及其解决-优化listView卡顿和如何禁用ListView的fling的相关文章

android问题及其解决-优化listView卡顿和怎样禁用ListView的fling

问题解决-优化listView卡顿和怎样禁用ListView的fling 前戏非常长,转载请保留出处:http://blog.csdn.net/u012123160/article/details/47720257 问题产生 这算是刚到实习公司接触到的第一个任务.公司某一产品中某个界面的listView高速滑动会有卡顿的现象发生,我的任务就是解决它. 产生原因分析 我一開始的想法比較简单.可能是listview的优化没有做到位,比如convertView的复用.viewHolder的使用等等基础

android viewpager fragment切换时界面卡顿解决办法

目前开发的程序在切换View时界面卡顿现象比较严重,影响用户体验,当前项目共就四个View,每个View也只是按钮,所以可以同时加载,不让其它view销毁. 只需在Adapter中重载destroyItem类即可 @Override public void destroyItem(ViewGroup container, int position, Object object) { //重载该方法,防止其它视图被销毁,防止加载视图卡顿 //super.destroyItem(container,

iOS开发——项目实战总结&UITableView性能优化与卡顿问题

UITableView性能优化与卡顿问题 1.最常用的就是cell的重用, 注册重用标识符 如果不重用cell时,每当一个cell显示到屏幕上时,就会重新创建一个新的cell 如果有很多数据的时候,就会堆积很多cell.如果重用cell,为cell创建一个ID 每当需要显示cell 的时候,都会先去缓冲池中寻找可循环利用的cell,如果没有再重新创建cell 2.避免cell的重新布局 cell的布局填充等操作 比较耗时,一般创建时就布局好 如可以将cell单独放到一个自定义类,初始化时就布局好

iOS 如何解决UITableView刷新卡顿现象

对之前的项目总结一下: 事情是这样的,我需要在定制Cell完成新闻类app的展示 虽然说SDWebImage提供了一个方法,异步加载图片到UIImageView上 但是,有些时候.需要的图片并不是需要铺满UIImageView 于是就抛弃了,后来想想还是挺二逼的.我可以在下面在铺一层边框UIImageView也能达到这个效果 于是乎,故作高大上,非要自己写. 后来看别人的方法,找到点感觉,还是写出来了,不过还是建立在网络良好的情况下 解决办法 主要要做到一下几个方面: 1.除了UI部分,所有的加

横向滑动的listview效果的实现方法,scrollview嵌套水平滑动的listview卡顿的解决方法

很多时候,界面需要实现横向滑动的listview效果.网络上有一种方法,自定义了HorizontalListView,用法同正常的listview,可实现水平滑动效果. 但是如果一个界面 为垂直滑动的scrollview嵌套水平滑动的listview的时候,滑动水平listview的时候,会很卡.我最近就遇到了这样的问题,一直把思路放在监听水平和垂直滑动手势,想实现滑动角度小于45的时候 垂直的scrollview 滑动效果被禁止.但是一直没有研究出来. 于是一个偶然的机会,灵光一闪,想到用Ho

彻底解决 Intellij IDEA 卡顿 优化笔记,重要的快捷键

由于工作中经常出现分支各种切换,使用Eclipse便不再像以前那么舒服了,不停的修改工作空间,每次修改完工作空间又是一堆一堆的个性化设置,来回的切换,真的很累.我们做软件的,怎么能不去尝试新鲜的呢,毕竟,再难走的路,也有人已经走过,我们只需要Google一下而已. 本篇适用于Idea 14.x 15.x 16.x 这次在使用了2天的IDEA之后,我发现这玩意简直屌爆了! 这次我重新进行征服IDEA过程中,遇到了很多很多的问题,当然,有一句话说的很好,遇到一件很难搞的事情,但凡你有半点犹豫,那就肯

Android卡顿优化:卡顿分析方法

基础知识在具体讲卡顿工具前,你需要了解一些基础知识,它们主要都和 CPU 相关.造成卡顿的原因可能有千百种,不过最终都会反映到CPU 时间上.我们可以把 CPU 时间分为两种:用户时间和系统时间.用户时间就是执行用户态应用程序代码所消耗的时间:系统时间就是执行内核态系统调用所消耗的时间,包括 I/O.锁.中断以及其他系统调用的时间. CPU 性能在开发过程中,我们可以通过下面的方法获得设备的 CPU 信息.// 获取 CPU 核心数cat /sys/devices/system/cpu/poss

ListView卡顿问题解决思路总结

ListView滚动速度优化主要可以应用以下几点方法来实现: 1.使用Adapter提供的convertView convertView是Adapter提供的视图缓存机制,当第一次显示数据的时候,adapter会创建n个(n等于页面可见的item的数目)convertView,当下次需要显示新的item的时候,adapter会循环利用这些已经创建的convertView,减少再次创建convertView所带来的开销,从而达到性能的提升. 2.使用自定义的视图缓存类 就是自定义一个视图缓存类,在

Android fragment 切换加载数据卡顿问题

接着上一篇项目的进度,上一篇讲了如何利用fragment来实现下拉菜单,公用菜单,以实现切换主界面数据的功能,这时候遇到的问题是:使用了fragment的切换界面方法,但加载的数据太多,用户从一个界面切换到这个界面的时候,至少有一两秒的卡顿,这是无法忍受的,代码如下: private void initOpenMenuItem(View popupWindow_view) { <span style="white-space:pre"> </span>Drawa