ListView的优化
- 复用convertview , 历史的view对象
- 减少子孩子查询的次数 viewholder
- 异步加载数据(把图片缓存)
- 条目多时分页加载数据
- 加载时显示进度条让用户等待
- Item的布局层次结构尽量简单,避免布局太深或者不必要的重绘
- 避免在 getView 方法中做耗时的操作:
例如加载本地 Image 需要载入内存以及解析 Bitmap ,都是比较耗时的操作,如果用户快速滑动listview,会因为getview逻辑过于复杂耗时而造成滑动卡顿现象。用户滑动时候不要加载图片,待滑动完成再加载,可以使用这个第三方库glide - 应该尽量避免 static 成员变量引用资源耗费过多的实例,比如 Context。
- 尽量使用 getApplicationContext:如果为了满足需求下必须使用 Context 的话:Context 尽量使用 Application Context,因为Application 的 Context 的生命周期比较长,引用它不会出现内存泄露的问题
- 在一些场景中,ScollView内会包含多个ListView,可以把listview的高度写死固定下来。
由于ScollView在快速滑动过程中需要大量计算每一个listview的高度,阻塞了UI线程导致卡顿现象出现,如果我们每一个item的高度都是均匀的,可以通过计算把listview的高度确定下来,避免卡顿现象出现 - 使用 RecycleView 代替listview:
每个item内容的变动,listview都需要去调用notifyDataSetChanged来更新全部的item,太浪费性能了。RecycleView可以实现当个item的局部刷新,并且引入了增加和删除的动态效果,在性能上和定制上都有很大的改善 - ListView 中元素避免半透明:
半透明绘制需要大量乘法计算,在滑动时不停重绘会造成大量的计算,在比较差的机子上会比较卡。 在设计上能不半透明就不不半透明。实在要弄就把在滑动的时候把半透明设置成不透明,滑动完再重新设置成半透明。 - 尽量开启硬件加速:
硬件加速提升巨大,避免使用一些不支持的函数导致含泪关闭某个地方的硬件加速。当然这一条不只是对 ListView。
布局的优化
- 尽量重用一个布局文件,使用include标签,多个相同的布局可以复用
- 减少一个布局的不必要节点
- 尽量使用view自身的参数,例如:Button,有一个可以把图绘制在左边的参数:android:drawableLeft
- 使用< ViewStub />标签来加载一些不常用的布局;使用< merge />标签减少布局的嵌套层次
viewPager的优化
- viewpager会默认加载左右俩个页面,有时候我们并不想看,会浪费用户的流量,可以在setOnPageChangeListener的onPageSelected的方法里选中哪个页面,初始化哪个页面
- 由于viewpager会默认销毁第三页面,可以强制让viewpager加载所有的页面pagerView.setOffscreenPageLimit(pageCount);,但是如果页面多的话就不能这样干了
- 可以定义一个集合将页面缓存起来,在destroyItem的时候保存起来,在instantiateItem读取集合,有就用,没有的话再创建,就像listview的convertView似的
class HomeAdapter extends PagerAdapter { // 当前viewPager里面有多少个条目 LinkedList<ImageView> convertView=new LinkedList<ImageView>(); @Override public int getCount() { return Integer.MAX_VALUE; } /* 判断返回的对象和 加载view对象的关系 */ @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == arg1; } @Override public void destroyItem(ViewGroup container, int position, Object object) { ImageView view=(ImageView) object; convertView.add(view);// 把移除的对象 添加到缓存集合中 container.removeView(view); } @Override public Object instantiateItem(ViewGroup container, int position) { ImageView view; if(convertView.size()>0){ view=convertView.remove(0); }else{ view= new ImageView(UiUtils.getContext()); } bitmapUtils.display(view, HttpHelper.URL + "image?name=" + datas.get(index)); container.addView(view); // 加载的view对象 return view; // 返回的对象 } }
内存的优化
- 回收已经使用的资源,比如游标cursor 、I/O、Bitmap(close并且引用置为null)
- 合理的使用缓存,比如图片是很耗内存的,使用lru缓存图片和压缩
- 合理设置变量的作用范围
- 节制的使用服务,后台任务运行完,即使它不执行任何操作,服务也会一直运行,这些是十分消耗内存的,可以用intentservice
- 当界面不可见时释放内存,在activity的onTrimMemory方法里与ui的相关资源,在onstop里释放与组件相关的资源
- 合理的使用多进程,如果后台任务和前台界面是相互独立在,可以在组件标签下写process,这样这个组建就在另一个进程里了。而服务的话更倾向于开启自己所依赖的进城,而那个进程可能很多东西都不需要,比如ui
- 使用线程池、对象池
- Bitmap对象在不使用时,应该先调用recycle()释放内存,然后才它设置为null。
代码优化
这部分就是是细微的优化,但是细微多了也就内存节约了
任何一个Java类,包括内部类、匿名类,都要占用大概500字节的内存空间。
任何一个类的实例要消耗12-16字节的内存开支,因此频繁创建实例也是会一定程序上影响内存的,所以要避免创建不必要的对象
- 如果有一个需要拼接的字符串,那么可以优先考虑使用StringBuffer或者StringBuilder来进行拼接,而不是加号连接符,因为使用加号连接符会创建多余的对象,拼接的字符串越长,加号连接符的性能越低
- 尽量使用基本数据类来代替封装数据类型,int比Integer要更加高效,其它数据类型也是一样
使用静态
- 使用枚举通常会比使用静态常量要消耗两倍以上的内存,在Android开发当中应当尽可能地不使用枚举。
- 如果你并不需要访问一个对象中的某些字段,只是想调用它的某个方法来去完成一项通用的功能,那么可以将这个方法设置成静态方法,这会让调用的速度提升15%-20%,同时也不用为了调用这个方法而去专门创建对象了,这样还满足了上面的一条原则。另外这也是一种好的编程习惯,因为我们可以放心地调用静态方法,而不用担心调用这个方法后是否会改变对象的状态(静态方法内无法访问非静态字段)
对常量使用static final修饰符
使用增强型for循环语法
多使用系统封装好的API,比如:indexOf(),System.arraycopy()
性能优化:尽量使用drawable对象保存图片而不是bitmap
drawable = Drawable.createFromStream(new URL(url).openStream(), "image.png");
ui组件需要用到的图片是apk包自带的,那么一律用setImageResource或者setBackgroundResource,而不要根据resourceid
注意:get(getResources(),R.drawable.btn_achievement_normal)该方法通过resid转换为drawable,需要考虑回收的问题,如果drawable是对象私有对象,在对象销毁前是肯定不会释放内存的。
时间: 2024-10-17 03:38:22