经过前一阶段的调查,大概对性能优化已经有了初步的解决方案:
先给大家介绍一下UC公司的性能优化指标以及部分方案:
Android性能优化代码规范
l 编码之初准备篇:
单个Activity显示的视图一般情况少于20,层数少于4
对于Adapter控件,如ListView ,item的布局层数一般情况为2,不得超过3.
getWindow().setBackgroundDrawable(null);
android的默认背景不为空。
l 将Activity的背景放到Activity的Theme中设置。同时避免fragment和activity背景重复设置:
Theme设置属性
l 采用硬件加速:
androidmanifest.xml中application添加
android:hardwareAccelerated="true"。
需要注意的是:android 3.0以上才可以使用。
l 使用ProGuard去除不必要的代码:
#删除无用的类
-assumenosideeffects class android.util.Log {
public static *** d(...);
public static *** v(...);
public static *** e(...);
public static *** i(...);
public static *** w(...);
}
l apk打包签名时,使用zipalign工具对齐:
zipAlignEnabled true
l 后台可以处理的逻辑不要放在前台,这样可能会有预料不到的问题
l 内存泄露引入三方框架LeakCanary :使用超级方便:
http://blog.csdn.net/walid1992/article/details/50470958
l Android程序冷启动优化(第一次启动应用):
1、在logoactivity设置一个theme,设置windowBackground属性,避免黑屏阶段。
2、对app进行延迟启动控制,采用延迟加载技术
private Handler handler = new Handler();
//延迟加载 runnable
private Runnable delayLoadRunnable = new Runnable() {
@Override
public void run() {
Logger.d("start delayLoadRunnable ");
init();
}
};
//优化的DelayLoad : 采用延迟加载策略
window.getDecorView().post(new Runnable() {
@Override
public void run() {
handler.post(delayLoadRunnable);
}
});
Activity 在启动时,会在第二次执行 performTraversals 才会去真正的绘制,原因在于第一次执行 performTraversals 的时候,会走到 Egl 初始化的逻辑,然后会重新执行一次 performTraversals 。
所以有人问为何在 run 方法里面还要 post 一次,如果在 run 方法里面直接执行 updateText 方法 ,那么 updateText 就会在第一个 performTraversals 之后就执行,而不是在第一帧绘制完成后才去执行,所以我们又 Post 了一次 。所以大概的处理步骤如下:
第一步:Activity.onCreate –> Activity.onStart –> Activity.onResume
第二步:ViewRootImpl.performTraversals –>Runnable
第三步:Runnable –> ViewRootImpl.performTraversals
第四步:ViewRootImpl.performTraversals –> init();
第五步:init();
l 禁止(避免)操作篇:
核心:少的对象创建,意味着少的GC操作。 杜绝引起内存溢出、内存抖动的操作行为;
使用枚举访问速度要比static变量慢4倍,枚举将造成大量的内存浪费;
l 禁止使用异步回调:
异步回调被执行的时间不确定,很有可能发生在activity已经被销毁之后,
这不仅仅很容易引起crash,还很容易发生内存泄露。
例如:context , Activity
对于某些不得不出现static引用context的情况,在onDestroy()方法中,解除Activity与static的绑定关系,
从而去除static对Activity的引用,使Context能够被回收;
l 避免在循环(for、while、listView - getView方法、onDraw)里创建对象:
对于onDraw中 Paint 我们可以这样优化
private Paint paint = new Paint();
public on Draw(){
paint.setColor(mBorderColor);
}
static生命周期过长,对于需要传递的对象,使用(Intent)和(Handler)
浮点数会比整型慢两倍
ScheduledExecutorService,
handler.postDelayed,
handler.postAtTime ,
handler.sendMessageDelayed ,
View.postDelayed,
AlarmManager
l 避免加载过大图片。压缩或者使用对象池后再使用
l 避免使用递归
l 避免使用轮询
l 避免长周期内部类、匿名内部类长时间持有外部类对象导致相关资源无法释放。如:Handler, Thread , AsyncTask
l 避免使用三方库,不需要的东西需要剔除
l 避免使用注解框架,毕竟是反射
l 非必要情况下,少用抽象
l 避免频繁网络请求
访问server端时,建立连接本身比传输需要跟多的时间,如非必要,不要将一交互可以做的事情分成多次交互(这需要与Server端协调好)。有效管理Service 后台服务就相当于一个持续运行的Acitivity,如果开发的程序后台都会一个service不停的去服务器上更新数据,在不更新数据的时候就让它sleep,这种方式是非常耗电的,通常情况下,可以使用AlarmManager来定时启动服务。如下所示,第30分钟执行一次。
1. AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALAR M_SERVICE);
2. Intent intent = new Intent(context, MyService.class);
3. PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0);
4. long interval = DateUtils.MINUTE_IN_MILLIS * 30;
5. long firstWake = System.currentTimeMillis() + interval;
6. am.setRepeating(AlarmManager.RTC,firstWake, interval, pendingIntent);
l 优化操作建议篇:
l 当数据量在100以内时,使用ArrayMap代替HashMap
l 为了避免自动装箱,当数量在1000以下时,使用如下容器
a)SparseBoolMap
b)SparseIntMap
c)SparseLongMap
d)LongSparseMap
l 字符串拼接用StringBuilder或StringBuffer
//这种string第一次初始化的情况下,下面得效率更高
String str1 = "abc"+“def”+"hij";
//非并发情况 , StringBuilder效率更优
StringBuilder str2 = str3 + str1 + "builder" ;
//并发情况使用 StringBuffer
StringBuffer str2 = str1 + "buffer" ;
BufferedInputStream替代InputStream
BufferedReader替代Reader
BufferedReader替代BufferedInputStream.
png虽能提供无损的图片,但相对于JPEG过大。Webp是既保持png优点,又能减少图片大小的新型格式.
基本类似指:int , double , char等。
反复使用的变量,保存到本地成为临时变量活成员变量后进行操作。尤其是在循环中
例:多次比较目标时间和当前时间差。
例如: Object ob = new Object();
int value;
if(i>0) value = ob.getVlaue();
改写为:int value;
if(i>0){
Object ob = new Object(); //用到时加载
value = ob.getVlaue();
}
a = new Object();
当a不为空时,应改写为:
a = null;
a = new Object();
通常对于对象成员如此使用,局部变量不需要
this.object = null;
l 对bitmap进行恰当的操作:
读取图片之前先查看其大小:
1. BitmapFactory.Options opts = new BitmapFactory.Options();
2. opts.inJustDecodeBounds = true;
3. Bitmap bitmap = BitmapFactory.decodeFile(imageFile, opts);
使用得到的图片原始宽高计算适合自己的smaplesize:
1. BitmapFactory.Options opts = new BitmapFactory.Options();
2. opts.inSampleSize = 4 ;// 4就代表容量变为以前容量的1/4
Bitmap bitmap = BitmapFactory.decodeFile(imageFile, opts);
对于过时的Bitmap对象一定要及时recycle,并且把此对象赋值为null:
1. bitmap.recycle();
2. bitmap = null;
l 布局用Java完成比XML快
//非显示的转换ViewStub 获取
View viewStub = findViewById(R.id.network_error_layout);
viewStub.setVisibility(View.VISIBLE); // ViewStub被展开后的布局所替换
networkErrorView = findViewById(R.id.network_error_layout); // 获取 展开后的布局
界面绘制尽量使用fragment代替activity,fragment根据情况使用hide与add方式,还是replace
if (!showFragment.isAdded()) { // 先判断是否被add过
transaction.hide(currentFragment).add(R.id.fl_content, showFragment)
.commitAllowingStateLoss(); // 隐藏当前的fragment,add下一个到Activity中
} else {
// 隐藏 当前的fragment,显示下一个
transaction.hide(currentFragment).show(showFragment).commitAllowingStateLoss();
}
this.currentFragment = showFragment;
要求不高标准:非复杂结构布局,无Background,padding等属性,且子View数量较少
l 数据压缩:
传输数据经过压缩 目前大部门网站都支持GZIP压缩,所以在进行大数据量下载时,尽量使用GZIP方式下载,可以减少网络流量,一般是压缩前数据大小的30%左右。
1. HttpGet request = new HttpGet("http://example.com/gzipcontent");
2. HttpResponse resp = new DefaultHttpClient().execute(request);
3. HttpEntity entity = response.getEntity();
4. InputStream compressed = entity.getContent();
5. InputStream rawData = new GZIPInputStream(compressed);
---------------希望对大家能有帮助,如果有不好的地方希望大家给予建议------------------