2018年五一假期框架知識整理之Android AOP編程思想

開篇廢話

真心非常感謝有這么一個五一假期,自己能夠挪出來這么一大塊的時間來好好學習,感覺無比幸福

近期,由于一個人的時間畢竟有限,工作上,學習上,生活上,都占用了太多時間,實在是沒有抽出來時間好好整理自己的一些知識點,更糟糕的是,本來想到了不少的知識點想分享的,到今天想分享的時候,已經有點記不起哪些是當時想要分享的了,對此,我應該在一個日志工具中記錄一下,免得出現現在這種情況。

近期花了一筆不少的錢報了一個在線進階的班,跟著老師系統的把Android知識學習一遍,個人覺得還是挺值得的。因此,想著能把自己學到冰山一角整理一下,鞏固一下自己的記憶,也供我們開發(fā)者一些參考。

廢話就不多說了,今天就簡單介紹一下AOP編程思想吧。。。


技術詳情

1. 什么是AOP

  官方釋義:面向切面編程,看到這個解釋,其實對于沒有接觸過AOP的人來說,依然是一臉懵逼。
  我們可以聯想一下我們自己使用最多的一種思想,就是面向對象編程。
  然后相較于面向對象,面向切面編程就是在多個功能中嵌入但又不是那個功能模塊的一個主要功能,舉個例子,大概是這樣:
  A模塊負責網絡訪問模塊,B模塊負責本地數據庫模塊,C模塊負責日志打印模塊,那么A和B模塊里面都會嵌入
  C模塊,也就是都需要打印一些日志,供我們調試或者記錄,這個時候,我們就可以把C模塊當做A模塊和B模塊的一個共同切面,
  而不是在A模塊或者B模塊的各個地方都寫上的日志,而是集中在C模塊中進行管理。

這么說可能還是不怎么好理解,那么我們就用代碼的方式來比較說明吧

2. AOP的簡易使用

首先,我們實現一個簡易的功能:計算某一段代碼運行的時長,這樣,我們可以知道到底是哪一個地方或者方法耗時比較多,可以有針對的對我們的app進行優(yōu)化。

針對這個功能,我們應該在一段代碼運行前,記錄一個時間點,運行完,再用當前時間減去運行前的時間點,就會得出,這段代碼運行的時長。

實現代碼如下:

  /**
 * 模擬耗時操作:查詢數據庫
 * @param view
 */
public void onFetchDatabase(View view){
    long begin = System.currentTimeMillis();
    SystemClock.sleep(new Random().nextInt(2000));
    long duration = System.currentTimeMillis() - begin;
    Log.i(TAG,"本次查詢數據庫耗時: " + duration + "ms");
}

/**
 * 模擬耗時操作:訪問網絡服務器
 * @param view
 */
public void doNetAction(View view){
    long begin = System.currentTimeMillis();
    SystemClock.sleep(new Random().nextInt(2000));
    long duration = System.currentTimeMillis() - begin;
    Log.i(TAG,"本次訪問網絡服務器耗時: " + duration + "ms");
}


/**
 * 模擬耗時操作:保存本地文件
 * @param view
 */
public void saveLocalFile(View view){
    long begin = System.currentTimeMillis();
    SystemClock.sleep(new Random().nextInt(2000));
    long duration = System.currentTimeMillis() - begin;
    Log.i(TAG,"本次保存本地文件耗時: " + duration + "ms");
}

/**
 * 模擬耗時操作:做其他操作
 * @param view
 */
public void onDoOtherSomething(View view){
    long begin = System.currentTimeMillis();
    SystemClock.sleep(new Random().nextInt(2000));
    long duration = System.currentTimeMillis() - begin;
    Log.i(TAG,"本次操作耗時: " + duration + "ms");
}

從以上代碼,我們可以看出來,在每一個方法里面,都必須有一段相同的代碼來計算耗時,當我們的功能模塊很多很多的時候,這種寫法就會很蛋疼了,到時候后期維護也不得了,這還只是單純的一個耗時統計功能而已,如果還有其他類似的功能呢?

那么,下面我們使用AOP的思想來完成這個功能,其中的好處,自行體會。

涉及的知識點有:

  1.自定義注解的簡易使用
  2.AspectJ的引入(可以理解為引入一個jar包),作為切面處理的一個工具類

首先創(chuàng)建一個自定義注解CalculateDuration :

  @Target(ElementType.METHOD)
  @Retention(RetentionPolicy.RUNTIME)
  public @interface CalculateDuration {
      String value();
  }

然后引入AspecgJ編譯器(一種與javac類似的編譯器,可以不用深究,能用就行),具體使用,可以查看我的github源碼中的app模塊的gradle配置

接著就是實現切面的邏輯代碼:

@Aspect
public class CalculateDurationAspect {

  //TODO 定義切面的規(guī)則
  //TODO 1.就是原來的應用中,哪些注釋的地方放到當前切面進行處理
  //execution(注解名  注解用的地方)
  @Pointcut("execution(@senduo.com.aopdemo.annotation.CalculateDuration * *(..) )")
  public void methodAnonotatedWithCalculateDuration(){}

  //TODO 2.對進入切面的內容如何處理
  //advice
  //@Before() 在切入點之前運行
  //After()  在切入點之后運行
  / /Around() 在切入點前后運行
  @Around("methodAnonotatedWithCalculateDuration()")
  public Object weaveJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable{

      //獲取切面簽名
      MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
      //根據簽名 獲取更多的信息
      String className = methodSignature.getDeclaringType().getSimpleName();//類名
      String methodName = methodSignature.getName();//方法名
      String funName =       methodSignature.getMethod().getAnnotation(CalculateDuration.class).value();//功能名

      long begin = System.currentTimeMillis();
      Object result = joinPoint.proceed();//這里就是原先處理的邏輯
      long durarion = System.currentTimeMillis() - begin;
      Log.d("senduo",className + " " + methodName + " " + "本次" + funName + "耗時:" + durarion + "ms");

      return result;
  }
}

通過以上切面的實現,在我們最開始的那段代碼就變成一下的樣子了:

@CalculateDuration("查詢數據庫")
public void onFetchDatabase(View view){
    SystemClock.sleep(new Random().nextInt(2000));
}

@CalculateDuration("訪問網絡服務器")
public void doNetAction(View view){
    SystemClock.sleep(new Random().nextInt(2000));
}

@CalculateDuration("保存本地文件")
public void saveLocalFile(View view){
    SystemClock.sleep(new Random().nextInt(2000));
}

@CalculateDuration("做其他操作")
public void onDoOtherSomething(View view){
    SystemClock.sleep(new Random().nextInt(2000));
}

這樣,在這個地方,我們只需要關注自身的功能實現,而不需要插入那么多亂七八糟的代碼

關于此項目的源代碼,在文章最后,會提供github地址,歡迎star

干貨總結

以上,是這一次關于AOP編程思想知識的一個簡易整理,如果對于這一塊有興趣,可以多花點時間,好好去研究,我這邊暫時也只能進行一個簡單陳述。

此文章的作用有如下幾點:

  1.認識一下AOP編程
  2.能夠優(yōu)化我們工作中的一些全局業(yè)務(比如性能檢測,權限驗證,資源釋放,用戶行為統計等)
  3.服務器那邊可通過AOP思想進行數據挖掘,數據分析

以下是此demo的源碼:

Android-AOP

?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容