前言
?性能優化的方向之一就是計算方法的耗時,去分析初始化所耗時間是否和預期差不多。耗時計算方法可以分為手動打點和AOP打點,手動打點可以查看Android性能優化之App啟動優化,本文主要講述的是AOP打點方法。
一、什么是AOP?
?AOP為Aspect Oriented Programming的縮寫,意為:面向切面編程,通過預編譯方式和運行期間動態代理實現程序功能的統一維護的一種技術。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。
?OOP、AOP都是編程思想,沒有具體的語言實現。我們可以從看問題的角度去理解OOP和AOP,OOP是將屬性、細節封裝成對象,可以稱之為模塊化。而AOP是將需要統一處理的事務集中起來做處理,例如在某個相同的方法前都需要做一件事(打印日志),做這件事其實就是AOP編程思想的體現。使用AOP去處理問題有以下兩點好處:
1.針對同一類問題統一處理(例如性能問題,需要在所有Activity的Oncreate方法中進行打點)
2.無侵入添加代碼(手動打點侵入性強)
二、如何使用AOP?
?Android中我們常用的AOP的框架是AspectJ,集成步驟如下:
?1.插件引用
在項目根目錄的build.gradle里依賴AspectJX
dependencies {
classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.8'
}
?2.添加到包含有AspectJ代碼的module.
implementation 'org.aspectj:aspectjrt:1.8.+'
?3.在app項目的build.gradle里應用插件
apply plugin: 'android-aspectjx'
//或者這樣也可以
apply plugin: 'com.hujiang.android-aspectjx'
三、AspectJ相關知識點
JoinPoints
?程序運行時的執行點,可以作為切面的地方,例如:
1.函數調用、執行的地方
2.獲取、設置變量
3.類初始化
PointCut
?帶條件的JoinPoints,通過設置條件篩選出我們需要的切面。
Advice
?插入代碼的位置。常用的三種語法類型:
1.Before:PointCut之前執行
2.After:PointCut之后執行
3.Around:PointCut之前之后分別執行
語法介紹
@Before("execution(* android.app.Activity.on**(..))")
public void onActivityCalled(JoinPoint joinPoint) throw Throwable{
//todo
}
1.Before
:Advice,具體插入位置
2.execution
:處理Join Point的類型,例如:call、execution。
call
在方法調用的地方插入
class MainActivity() {
//調用方法的地方插入
Log.d("msg","before insert")
init()
Log.d("msg","after insert")
}
execution
在方法內部插入
class MainActivity : AppCompatActivity() {
//調用方法
init()
}
private fun init() {
//方法內部插入
Log.d("msg","before insert")
//TODO 搞事情
Log.d("msg","after insert")
}
3.android.app.Activity.on**(..)
:*
表示的是返回值它的意思是可以任意返回值,匹配所有android.app.Activity.on
開頭的方法,(..)
表示無論有無參數都進行匹配
4.onActivityCalled
:要插入的代碼。
四、AOP實踐
如何取得聯系?
?使用@Aspect
注解定義文件就可以讓AspectJ在編譯期自動去解析文件。
@Aspect
class PerformanceAop {
@Around("call(* com.example.myapplication.MyApplication.**(..))")
fun getTime(joinPoint: ProceedingJoinPoint) {
val signature = joinPoint.signature
val time = System.currentTimeMillis()
joinPoint.proceed()
Log.d("msg---" + signature.name, "${System.currentTimeMillis() - time}MS")
}
}
class MyApplication() : Application() {
override fun onCreate() {
super.onCreate()
initBugly()
initUmeng()
initBaidu(false);
}
private fun initBaidu(b: Boolean) {
Thread.sleep(100)
}
private fun initUmeng() {
Thread.sleep(200)
}
private fun initBugly() {
Thread.sleep(300)
}
}
?執行結果:
joinPoint.proceed()手動執行一次代碼,Around與Before、After不同點就在于此。我們可以在切面執行之前和之后做一些事(計算方法執行時間)。