当前位置:   article > 正文

Android Kotlin使用AspectJ进行AOP面向切面编程_failed to apply plugin 'android-aspectjx'.

failed to apply plugin 'android-aspectjx'.

前言

什么是面向切面编程?首先我们来了解下两个概念:
OOP(面向对象编程):针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分。
AOP(面向切面编程):则是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。

由此可知,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

配置AspectJ以及报错处理

这里,我们就使用AspectJ进行切面编程,其相对应的github地址:hujiang.aspectjx

配置步骤如下:

  1. 根目录build.gradle中添加 classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.10'
  2. 对应app模块build.gradle 添加:
apply plugin: 'android-aspectjx'
implementation 'org.aspectj:aspectjrt:1.8.9'
  • 1
  • 2

AspectJ配置
当然如果按照以上配置就可以编译通过,那要先祝贺你了,这里我记录下我配置后编译报错的一些问题:

> Failed to apply plugin 'android-aspectjx'.
   > Build was configured to prefer settings repositories over project repositories but repository 'MavenLocal' was added by plugin 'android-aspectjx'
  • 1
  • 2

解决方案: 替换setting.gradle文件dependencyResolutionManagement配置中 repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
aspect问题1

Cause: zip file is empty
  • 1

解决方案:对应app模块添加配置

aspectjx{
        exclude 'org.jetbrains.kotlin', "module-info", 'versions.9'
    }
  • 1
  • 2
  • 3

aspect问题2
经过上述的配置,我们就可以开始使用AspectJ进行切面编程了!!!

一个小栗子

这里,我们举个简单又实际开发中会碰到的案例:
比如在开发中,碰到很多地方需要先判断当前是否有网络,如果没有网络就弹Toast,有网络的时候才进行对应界面跳转!
那怎么去处理这类问题呢?我们常用的做法是一个个地方去进行判断是否有网络,这样如果需求进行变动,就会很麻烦,同时这种做法也不太优雅。
下面我们就使用AspectJ来解决这个问题;

  • 首先定义CheckNet注解
package com.crystal.essayjoker.aop
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
annotation class CheckNet()
  • 1
  • 2
  • 3
  • 4
  • CheckNet注解进行界面处理
package com.crystal.essayjoker.aop

import android.app.Activity
import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkInfo
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.fragment.app.Fragment
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Pointcut

@Aspect
class CheckNetAspect {
   /**
    * 找到要处理的切点
    *  * *(..)表示可以处理所有的方法 比如有参无参的
    */
   @Pointcut("execution(@com.crystal.essayjoker.aop.CheckNet * *(..))")
   fun checkNetBehavior() {

   }

   /**
    * 处理切面
    */
   @Around("checkNetBehavior()")
   fun checkNetRound(joinPoint: ProceedingJoinPoint): Any? {
       Log.e("CheckNetAspect", "checkNetRound")
       val target = joinPoint.`this` //获取当前切点所在的类
       val context = getContext(target)
       if (context != null) {
           if (!isNetworkAvailable(context)) {
               Toast.makeText(context, "请检查网络是否正常", Toast.LENGTH_SHORT).show()
               return null
           }
       }
       return joinPoint.proceed()
   }

   private fun getContext(target: Any): Context? {
       return when (target) {
           is Activity -> {
               target
           }
           is Fragment -> {
               target.context
           }
           is View -> {
               target.context
           }
           else -> null
       }
   }

   /**
    * 判断网络是否可用
    */
   private fun isNetworkAvailable(context: Context): Boolean {
       // 获取手机所有连接管理对象(包括对wi-fi,net等连接的管理)
       val connectivityManager =
           context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
       // 获取NetworkInfo对象
       val networkInfo = connectivityManager.allNetworkInfo
       if (networkInfo.isNotEmpty()) {
           for (i in networkInfo.indices) {
               // 判断当前网络状态是否为连接状态
               if (networkInfo[i].state == NetworkInfo.State.CONNECTED) {
                   return true
               }
           }
       }
       return false
   }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 测试验证
class CheckNetActivity : AppCompatActivity() {
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContentView(R.layout.activity_check_net)
       findViewById<Button>(R.id.btn).setOnClickListener {
           onCheckNet()
       }
   }

   @CheckNet
   fun onCheckNet() {
       Toast.makeText(this@CheckNetActivity, "跳转到其他界面", Toast.LENGTH_SHORT).show()
   }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

测试结果:点击按钮时,会去检查网络,没有会提示请检查网络是否正常,有网则会提示跳转到其他界面!

AspectJ实现原理

上面我们简单实用AspectJ进行了切面编程,那咱一定很好奇它是如何做到切面处理的呢?我们使用jadx反编译生成的APK,找到CheckNetActivity中的onCheckNet方法

  private static final /* synthetic */ void onCheckNet_aroundBody0(CheckNetActivity ajc$this, JoinPoint joinPoint) {
        Toast.makeText(ajc$this, "跳转到其他界面", 0).show();
    }

    private static final /* synthetic */ Object onCheckNet_aroundBody1$advice(CheckNetActivity ajc$this, JoinPoint thisJoinPoint, CheckNetAspect ajc$aspectInstance, ProceedingJoinPoint joinPoint) {
        Intrinsics.checkNotNullParameter(joinPoint, "joinPoint");
        Log.e("CheckNetAspect", "checkNetRound");
        Object target = joinPoint.getThis();
        Intrinsics.checkNotNullExpressionValue(target, TypedValues.AttributesType.S_TARGET);
        Context context = ajc$aspectInstance.getContext(target);
        if (context == null || ajc$aspectInstance.isNetworkAvailable(context)) {
            onCheckNet_aroundBody0(ajc$this, joinPoint);
            return null;
        }
        Toast.makeText(context, "请检查网络是否正常", 0).show();
        return null;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

可以看出在编译时AspectJ将代码插入到onCheckNet方法中,由此实现了切面编程!

小结

如果以上文章对您有一点点帮助,希望您不要吝啬的点个赞加个关注,您每一次小小的举动都是我坚持写作的不懈动力!ღ( ´・ᴗ・` )

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/266752
推荐阅读
相关标签
  

闽ICP备14008679号