Android 界面滑动卡顿分析与解决方案(入门)
Android 界面滑动卡顿分析与解决方案(入门)
导致Android界面滑动卡顿主要有两个原因:
1.UI线程(main)有耗时操作
2.视图渲染时间过长,导致卡顿
目前只讲第1点,第二点相对比较复杂待以后慢慢研究。
众所周知,界面的流畅度主要依赖FPS这个值,这个值是通过(1s/渲染1帧所花费的时间)计算所得,FPS值越大视频越流畅,所以就需要渲染1帧的时间能尽量缩短。正常流畅度的FPS值在60左右,即渲染一帧的时间不应大于17ms。
先看一个例子:
见Video1,该应用通过一组URL加载网络上的图片并显示在ListView中。从视频中可以看到滑动ListView存在一定的卡顿的现象。
分析工具1:Android systrace
打开Android开发工具中的DDMS,选中应用所在的进程并点击倒数第二个图标出现如下界面:
填上相关信息后点击OK,此时Android systrace已经开始工作,你只需要正常操作手机复现卡顿现象即可。
Android systrace 停止以后就会根据你上图中的设置生成trace.xml文件(注:此文件在火狐浏览器中无法正常浏览,需使用chrome)。
打开trace.xml后观察surfaceflinger存在很多断断续续,分布不够均匀。
放大看
在某间隔出的时间是48ms,这远远的大于17ms,正是这个原因直接导致了界面的卡顿感。
接着再看:
此处也存在不规则分布,可以看到主要的耗时操作在:
obtainView和decodeBitmap上面,看到这两个方法似乎是找到了罪魁祸首。那我们就看看这两个方法是在哪里被调用的。
通过查找源代码知道obtainView这个方法被定义在AbsListView.java这个类中,主要作用就是获得一个和数据绑定过的视图,在这个方法中调用到了
mAdapter.getView(position, transientView, this);
这个方法大家再熟悉不过了,因为在自定义Adapter的时候都要去重写getView方法,那我们可以推测卡顿的原因很有可能出自getView。毕竟这个方法里有我们自己写的很大一坨代码。
接着再看getView中最主要的方法
mCacheWrapper.getBitmapFromCache(url, mHandler, position,2);
具体实现是:
public void getBitmapFromCache(final String urlString, Handler handler,
final int position, final int scale) {
final String key = hashKeyForString(urlString);
final Message msg = handler.obtainMessage();
Bitmap bitmapCache = mMemoryCache.get(key);
if (bitmapCache != null) {
msg.arg1 = position;
msg.obj = bitmapCache;
msg.sendToTarget();
Log.d(TAG, "memory include the key");
return;
}
//InputStream is = getInputStreamFromCache(key);
//if (is != null) {
// Bitmap bitmap = getBitmap(is, key, scale);
// if (bitmap != null) {
// mMemoryCache.put(key, bitmap);
// msg.arg1 = position;
// msg.obj = bitmap;
// msg.sendToTarget();
// Log.d(TAG, "disk include the key");
// }
// return;
//}
mExecutor.execute(new Runnable() {
@Override
public void run() {
if (mCurrentTask.contains(key)) {
Log.d(TAG, "the key of task is still execute");
return;
}
mCurrentTask.add(key);
boolean isOK = write2Cache(urlString);
if (isOK) {
InputStream is = getInputStreamFromCache(key);
Log.d(TAG, "the file is write to disk cache");
is = getInputStreamFromCache(key);
if (is != null) {
Bitmap bitmap = getBitmap(is, key, scale);
if (bitmap != null) {
mMemoryCache.put(key, bitmap);
msg.arg1 = position;
msg.obj = bitmap;
msg.sendToTarget();
}
}
}
mCurrentTask.remove(key);
}
});
}
看上面这段代码发现加注释代码存在一定的嫌疑,因为它在主线程中做了IO操作和bitmap的decode操作。
我们稍微修改一下上面这段代码:
public void getBitmapFromCache(final String urlString, Handler handler,
final int position, final int scale) {
final String key = hashKeyForString(urlString);
final Message msg = handler.obtainMessage();
Bitmap bitmapCache = mMemoryCache.get(key);
if (bitmapCache != null) {
msg.arg1 = position;
msg.obj = bitmapCache;
msg.sendToTarget();
Log.d(TAG, "memory include the key");
return;
}
mExecutor.execute(new Runnable() {
@Override
public void run() {
if (mCurrentTask.contains(key)) {
Log.d(TAG, "the key of task is still execute");
return;
}
//mCurrentTask.add(key);
//InputStream is = getInputStreamFromCache(key);
//if (is != null) {
// Bitmap bitmap = getBitmap(is, key, scale);
// if (bitmap != null) {
// mMemoryCache.put(key, bitmap);
// msg.arg1 = position;
// msg.obj = bitmap;
// msg.sendToTarget();
// Log.d(TAG, "disk include the key");
// }
// mCurrentTask.remove(key);
// return;
//}
boolean isOK = write2Cache(urlString);
if (isOK) {
Log.d(TAG, "the file is write to disk cache");
is = getInputStreamFromCache(key);
if (is != null) {
Bitmap bitmap = getBitmap(is, key, scale);
if (bitmap != null) {
mMemoryCache.put(key, bitmap);
msg.arg1 = position;
msg.obj = bitmap;
msg.sendToTarget();
}
}
}
mCurrentTask.remove(key);
}
});
}
将置灰出的代码移动到主线程以外,在看看滑动流畅读video2.mp4
可以看到卡顿现象已经没有了,那罪魁祸首就是在主线程中有IO操作和bitmap的decode操作引起的。
上述分析过程跳跃性比较大,这里再推荐一种简单直观的方法:
分析工具2:Method Profiling.
还是打开DDMS,选中你的应用,点击第六个图标,
这边默认OK
点击OK开始抓取,接着滑动手机复现卡顿现象。最后再次点击第六个钮即可。
这里只看上图中的main就可以了。
点击main方法后会展开它的父方法(即调用main的方法)和它的子方法(即在main中调用的方法)。这里一般点击后面百分数较大的那个子方法(百分数表示方法执行所占用的cpu时间)。
接着要做的就是一步一步往下点,直到找到我们要找的耗时操作。
最后我们还是来到了这边
上图已经定位了decodeStream方法,再往下走也是进到framework没意义了。剩下的就是怎么将decodeStream放到主线程以外的线程的事情了。
总结:
主线程中不要放置耗时的操作,耗时操作可以扔Thread再通过Handler与主线程同步或使用AsyncTask来完成耗时操作。
Android 界面滑动卡顿分析与解决方案(入门)的更多相关文章
- android中listview滑动卡顿的原因
导致Android界面滑动卡顿主要有两个原因: 1.UI线程(main)有耗时操作 2.视图渲染时间过长,导致卡顿 http://www.tuicool.com/articles/fm2IFfU
- 无需SherlockActionbar的SlidingMenu使用详解(一)——通过SlidingMenu设置容器并解决滑动卡顿的问题
想必很多人都听过这个开源框架,一年前真的是风靡一时.只是它的配置较为繁琐,还需要sherlockActionbar的支持,我这里下载了最新的开源库,并且在实际用套用了AppCompat的官方库,这样就 ...
- UITableView cell复用出错问题 页面滑动卡顿问题 & 各杂七杂八问题
UITableView 的cell 复用机制节省了内存,但是有时对于多变的自定义cell,重用时会出现界面出错(例如复用出错,出现cell混乱重影).滑动卡顿等问题,这里只简单敲下几点复用出错时的解决 ...
- android TextView SetText卡顿原因
[android TextView SetText卡顿原因] 不要用wrap_content即可. 参考:http://blog.csdn.net/self_study/article/details ...
- 解决页面使用overflow: scroll,overflow-y:hidden在iOS上滑动卡顿的问题
解决页面使用overflow: scroll,overflow-y:hidden在iOS上滑动卡顿的问题 div{ width: 100%; overflow-y: hidden; -webkit-o ...
- 记 页面使用overflow-scroll在iOS上滑动卡顿的问题
页面使用overflow-scroll在iOS上滑动卡顿的问题 因在做一个滑动的list列表,为某个div使用了overflow: scroll属性. 结果在手机上测试时,ios手机有明显的滑动卡顿问 ...
- 关于iScroll在安卓移动端/chrome模拟移动端上下滑动卡顿问题处理!!!!真实可靠!!!已解决!!!
滑动卡顿效果 安卓手机打开微信浏览网页,Chrome模拟手机浏览网页,都出现的问题滑动卡顿! 修改代码点: 1. <style type="text/css"> ...
- Android中app卡顿原因分析示例
在知乎回答了一个“为什么微博的app在iPhone比Android上流畅”的问题.后面部分是一个典型的动画卡顿的性能分析过程,因此帖在这里.有编程问题可以在这里交流.知乎链接. =========== ...
- Android Scrollview嵌套RecyclerView导致滑动卡顿问题解决
一个比较长的界面一般都是Scrollview嵌套RecyclerView来解决.不过这样的UI并不是我们开发人员想看到的,实际上嵌套之后.因为Scrollview和RecyclerView都是滑动控件 ...
随机推荐
- 转:浅析VO、DTO、DO、PO的概念、区别和用处
原文链接 概念: VO(View Object):视图对象,用于展示层,它的作用是把某个指定页面(或组件)的所有数据封装起来. DTO(Data Transfer Object):数据传输对象,这个概 ...
- 数据结构(逻辑结构,物理结构,特点) C#多线程编程的同步也线程安全 C#多线程编程笔记 String 与 StringBuilder (StringBuffer) 数据结构与算法-初体验(极客专栏)
数据结构(逻辑结构,物理结构,特点) 一.数据的逻辑结构:指反映数据元素之间的逻辑关系的数据结构,其中的逻辑关系是指数据元素之间的前后件关系,而与他们在计算机中的存储位置无关.逻辑结构包括: 集合 数 ...
- hdu 4770 Lights Against Dudely(回溯)
pid=4770" target="_blank" style="">题目链接:hdu 4770 Lights Against Dudely 题 ...
- App登录注册功能,怎样做到用户体验最佳?
用户登录系统,可以细分为三项功能模块,分别是:登录.注册和密码找回.本文作者将结合自身经历,谈谈他在做这块的时候一些想法,主要是涉及业务流程. 登录和注册功能,不论是PC端还是移动端,大多数产品都会涉 ...
- atitit.session的原理以及设计 java php实现的异同
atitit.session的原理以及设计 java php实现的异同 1. session的保存:java在内存中,php脚本因为不能常驻内存,所以在文件中 1 2. php的session机制 1 ...
- First Objective C
// // main.m // hello-objc // // Created by test5d on 14-9-29. // Copyright (c) 2014年 test5d. All ri ...
- JSON的String字符串与Java的List列表对象的相互转换
1.JSON的String字符串与Java的List列表对象的相互转换 在前端: 1.如果json是List对象转换的,可以直接遍历json,读取数据. 2.如果是需要把前端的List对象转换为jso ...
- .htaccess中的apache rewrite规则写法详解
.htaccess中的apache rewrite写法: 1 RewriteEngine On 2 RewriteCond %{HTTP_HOST} ^(www\.)?xxx\.com$ 3 Rewr ...
- 【原创】jpgraph中文乱码问题的解决
php jpgraph库非常强大,可以在后台生成图片 后台生成在需要导出图表型报告的时候非常有用,当然,前端的可视化还是要用highcharts/echarts/anycharts等类库 比较麻烦的是 ...
- Create a new Docker Machine with the Hyper-V driver
docker-machine就是docker工具集中提供的用来管理容器化主机的工具,用来管理运行在不同环境的主机,包括:本地虚拟机,远程虚拟机,公有云中的虚拟机都可以通过一个命令统一进行管理. 01. ...