一、APP的启动方式优化 (Spring框架中的一个重要内容 这个需要学习 , Aop框架、ARTHook框架)
1.代码添加路径
android的路径下
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.0'
}
app的路径下
apply plugin: 'android-aspectjx'
compile 'org.aspectj:aspectjrt:1.8.+'
2.注解相关介绍
@Aspect:作用是把当前类标识为一个切面供容器读取
@Pointcut:Pointcut是植入Advice的触发条件。每个Pointcut的定义包括2部分,一是表达式,二是方法签名。方法签名必须是 public及void型。可以将Pointcut中的方法看作是一个被Advice引用的助记符,因为表达式不直观,因此我们可以通过方法签名的方式为 此表达式命名。因此Pointcut中的方法只需要方法签名,而不需要在方法体内编写实际代码。
@Around:代码执行前、执行后分别执行
@AfterReturning:后置增强,相当于AfterReturningAdvice,方法正常退出时执行
@Before:代码执行前执行
@AfterThrowing:异常抛出增强,相当于ThrowsAdvice
@After: 代码执行后执行
3. 代码展示
@Aspect
public class PerformanAop {
@Around("call(* com.example.mi.okhttp.MainActivity.**(..))")
public void getTime(ProceedingJoinPoint joinPoint){
Signature signature = joinPoint.getSignature();
String name = signature.toShortString();
long time = System.currentTimeMillis();
try {
joinPoint.proceed(); ----------------->执行该程序的方法
} catch (Throwable throwable) {
throwable.printStackTrace();
}
Log.d("ceshi", name + "=" + (System.currentTimeMillis() - time));
}
}
4.异步优化实践案例
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4)); //可以获取不同手机分配的cpu
private CountDownLatch countDownLatch = new CountDownLatch(1); //这个是为了防止某一个方法没有执行调用时候会然而没有生成该方法(多线程会出现这样的问题)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ExecutorService services = Executors.newFixedThreadPool(CORE_POOL_SIZE);
services.submit(new Runnable() {
@Override
public void run() {
//动态授予权限
grantPremisson();
}
});
services.submit(new Runnable() {
@Override
public void run() {
textLog();
countDownLatch.countDown();
}
});
try {
countDownLatch.await(); //为了等待某方法执行完后才可以正常结束
} catch (InterruptedException e) {
e.printStackTrace();
}
}
异步优化易错点:异步执行时候,handler必须执行在主线程的;
某一个线程没有执行完,而另一个线程却要执行该线程也会出现问题
5.异步启动使用启动器来做最优化的解
启动器(拓扑排序算法)核心思想 ; 充分利用CPU多核,自动梳理任务的顺序
启动器的好处:
TASK的编写框架
6. Feed卡顿的处理(需要学习IdleHandler)
a . 通过handle的setDelayPost使用,对延迟任务进行分批处理化(一起IdleHandler的使用)
7.优化总方针:异步、延迟、懒加载
1.监控APP的生命周期间隔时间、Activity的时间(需要百度查一下)
2. 提前加载SharedPreferences : 在Multidex(这个是什么)之前加载,利用此阶段的CPU
3.启动阶段不要启动子进程
4.类加载优化: 提前异步类加载
a.Class.forName()只加载类本身及其静态变量的引用类
b.new 类实例可以额外加载类成员变量的引用类(需要学习ClassLoader如何自定义,然后打印日志去看哪个是先执行的类)
5.启动阶段抑制GC():不需要学习,比较难
二、app启动的优化总结
1.获取方法耗时:采用AOP方式把逻辑代码和获取时间代码完全隔离
1) . wall time 和 cpu time的区别
wall time : 是代码执行完花费的时间(包含cpu和IO的读写操作)
cpu time : 是cpu花费多少时间执行完这段代码(这里才是作为主要的优化时间点)
2.异步初始化: 主要是为了分担主线程的压力
缺点(遇到的问题):一个类依赖另一个类,有的类必须在onCreate方法必须执行,这些都是无法控制的
1).解决方式:
采用启动器(拓扑排序算法): 可解决一个类依赖另一个累先后启动方式,或者再某个阶段必须执行完某个方法
CountDownLatch : await 和 countDown进行使用
3. 延迟初始化
常规方式使用handler.delayPost 和 post使用
场景:Feed的卡顿
使用IdleHandler的方法,在CPU空闲的时候才会去执行该代码
4.其他优化
启动阶段不启动子进程,避免和主线程抢占资源
提前异步类加载(ClassLoader)
三、启动优化面试总结----->启动优化容易忽略的注意点
1.cpu time 和wall time
2.注意延迟初始化的优化(adleHandler的使用)
3.异步类加载,Multidex.install 之后,启动一个线程,Class.forName()作为启动
4.版本迭代导致的启动变慢的解决方式 ------>技术深挖,启动器的介绍
四、Android 的app性能优化的工具
1.traceView的使用方法
1).Debug.startMethodTracing("App");
2).setContentView(R.layout.activity_main);
3).Debug.stopMethodTracing();
2. systrace的工具使用(有时间学学)
python systrace.py -t 10 [other-options][categorise]
二、APP内存的优化(implementation 'top.zibin:Luban:1.1.8' 鲁班这个库可以压缩图片)
1.内存抖动 : 内存频繁的分配和回收导致内存不稳定
表现:频繁的GC、内存曲线呈锯齿状
危害:导致卡顿、OOM的出现
2.Bitmap 的内存模型
1.获取Bitmap占用内存
1).getByteCount
2).宽*高*一像素占用内存
2.ARTHook的使用(AOP编程需要在网址搜索去学习)
public class ThreadPollUtils extends XC_MethodHook {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
//实现我们自己的逻辑
Thread thread = (Thread) param.thisObject;
}
1).Epic 是一个虚拟机层面、以JavaMethod为粒度运行时Hook的框架
2). https://github.com/tiann/epic
三、APP布局优化
1.不嵌套使用RelativeLayout
2.不嵌套使用LinearLayout中的weight
3.merge标签:减少一个层级,只能用于根view
4.布局加载为什么会卡顿
产生原因:IO、反射、遍历、重绘
解决办法: X2C框架、较少绘制层级、避免重绘(自定义view使用clipRect来屏蔽被遮盖的view绘制)
5.X2C的简单使用
implementation 'com.zhangyue.we:x2c-lib:1.0.6'
annotationProcessor 'com.zhangyue.we:x2c-lib:1.0.6'
@Xml(layouts = "activity_main")
X2C.setContentView(MainActivity.this , R.layout.activity_main);
6. setContentView(R.layout.activity_main) 详细过程(还需要再学习)
LayoutInflaterCompat.setFactory2(getLayoutInflater(), new LayoutInflater.Factory2() {
@Override
public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
if(TextUtils.equals("TextView" , name)){
}
long startTime = System.currentTimeMillis();
View view = getDelegate().createView(parent, name, context, attrs);
long endTime = System.currentTimeMillis() - startTime;
Log.i(TAG, "onCreateView: = " + endTime);
return view;
}
@Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
return null;
}
});
Factory2和Factory的区别:Factory2比Factory对一个Parent参数,是否有父布局,我们通常使用Factory2这个来插装
四、APP卡顿优化
1.界面秒开
onCreate---->onWindowFocusChanged
2.Lancet库的介绍
@Proxy :通常用与对系统API调用的Hook
@Insert : 通常用于操作App于library的类
@TargetClass 看看是做什么的
classpath 'me.ele:lancet-plugin:1.0.4'
apply plugin: 'me.ele.lancet'
provided 'me.ele:lancet-base:1.0.4'
第一点用线下systemtrace这个工具先去定位(还有线上直接交给自动化测试)
第二点用如下图片
五、APP线程优化(需要花时间去写代码)
1.异步方式:
a.Thread : 不容易复用,频繁创建及开销大
b.HandlerThread : 自带消息循环,适用于长时间运行,不断从队列中获取任务
c.IntentService : 继承Service在内部创建一个HandlerThread , 异步,不占用主线程,优先级较高,不容易被系统kill
d. AsyncTask : 无需处理线程切换,使用简单
e.线程池:容易复用,减少频繁创建、销毁时间, 定时、任务队列、并发数控制
2.设置优先级
Process.setThreadPriority() --------->这个可以设置优先级的高低
线程优化的方向:
IO和CPU线程池的区别
IO线程池:作为对网络操作还有文件的读写可以多开辟些线程池
CPU线程池: 如果开启更多的线程反而不适合操作,因为开启越多它会频繁切换线程。
六、APP技术优化
1.列表页面卡顿优化
布局优化
1) . convertView的复用、使用ViewHolder这个保存之前存储的控件ID
2). 耗时任务可以执行异步任务
3). 减少布局的层级、避免过度的绘制、使用X2C的框架,将XML文件转换为代码
图片优化
1).避免图片过大尺寸,尽可能使用压缩的图片
2).滑动时候取消加载
线程优化
1). 使用线程池来作为优化,降低线程的优先级,避免UI线程被抢占