【Android】Android AOP 编程框架

devtools/2024/10/18 15:54:26/
什么是AOP编程

AOP编程全称Aspect Oriented Programming,面向切面编程

主要功能是在不改变原代码的前提下,对特点代码节点进行修改,预处理,后期处理

AOP的历史

Android的AOP编程框架比较多,它们大多具备以下特点

  • 以AspectJ为基础,提供AOP编程能力
  • AspectJ最早为Java项目中的编程框架,依赖于Maven插件实现
  • AspectJ的原理是在预编译期间,修改代码文件,生成代理对象,从而实现拦截效果
  • 通过Gradle插件,可以将AspectJ应用到Java和Kotlin项目
  • 但大多Gradle插件,依赖于Gradle版本,并且和Android的插件可能产生冲突
  • 因此大多Android Aspect Gradle Plugin,多年没人维护,不能在最新项目中使用
  • 因为Gradle和Android插件更新太频繁,并且不兼容旧代码,Aspect的适配工作工作量太大,很多作者都放弃维护了
aspectj_18">io.freefair.aspectj

这个是我们今天要介绍的主角

相对于其它AOP框架,它的版本比较新,而且作者自身在使用,因此不用太担心维护问题

这个项目,没有依赖于其它库,是自己从零开始实现的,但支持了AspectJ的全部功能

其实依赖的库和插件越多,自身兼容性越容易出问题

引入插件依赖

这里用的是Gradle8.7+KotlinScript

settings.gradle.kts中输入以下代码

注意各个gradle插件的版本兼容性,这是gradle不可回避的一个问题

不过相信随着gradle越来越强大,功能越来越丰富,终究会有稳定下来的一天

pluginManagement {repositories {maven("https://maven.aliyun.com/repository/public/")maven("https://maven.aliyun.com/repository/central/")maven("https://maven.aliyun.com/repository/gradle-plugin/")maven("https://maven.aliyun.com/repository/apache-snapshots/")maven("https://plugins.gradle.org/m2/")maven("https://jitpack.io/")mavenLocal()gradlePluginPortal()google()mavenCentral()}
}dependencyResolutionManagement {repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)repositories {maven("https://maven.aliyun.com/repository/public/")maven("https://maven.aliyun.com/repository/central/")maven("https://maven.aliyun.com/repository/gradle-plugin/")maven("https://maven.aliyun.com/repository/apache-snapshots/")maven("https://plugins.gradle.org/m2/")maven("https://jitpack.io/")mavenLocal()gradlePluginPortal()google()mavenCentral()}
}buildscript {repositories {maven("https://maven.aliyun.com/repository/public/")maven("https://maven.aliyun.com/repository/central/")maven("https://maven.aliyun.com/repository/gradle-plugin/")maven("https://maven.aliyun.com/repository/apache-snapshots/")maven("https://plugins.gradle.org/m2/")maven("https://jitpack.io/")mavenLocal()gradlePluginPortal()google()mavenCentral()}dependencies {classpath("com.google.code.gson:gson:+")}
}plugins {id("com.android.application") version "8.1.2" apply falseid("com.android.library") version "8.1.2" apply falseid("com.google.devtools.ksp") version "2.0.10-1.0.24" apply falseid("org.jetbrains.kotlin.android") version "2.0.10" apply falseid("io.github.FlyJingFish.AndroidAop.android-aop") version "2.0.9" apply false
}include(":app")
应用插件到模块

在app目录下的build.gradle.kts下输入以下代码

plugins {id("com.android.application")id("org.jetbrains.kotlin.android")id("com.google.devtools.ksp")id("io.github.FlyJingFish.AndroidAop.android-aop")
}dependencies {api("androidx.appcompat:appcompat:1.7.0")api("io.github.FlyJingFish.AndroidAop:android-aop-core:2.0.9")api("io.github.FlyJingFish.AndroidAop:android-aop-annotation:2.0.9")ksp("io.github.FlyJingFish.AndroidAop:android-aop-ksp:2.0.9")
}

两步就集成完成了,下面我们开始实战吧

这里通过三个最常见的场景,来演示这个框架的强大功能

更详细的用法,请参考作者Github https://github.com/FlyJingFish/AndroidAOP

使用说明

该框架会在预编译期间自动根据注解生效,不需要自己去初始化SDK或注册对象之类的

直接新建一个AOP Interceptor类,通过注解指定要做什么就能生效

类和方法代理

将项目代码中的特定类和方法,替换为自己的类和方法

kotlin">package com.android.code.aopimport com.flyjingfish.android_aop_annotation.anno.AndroidAopReplaceClass
import com.flyjingfish.android_aop_annotation.anno.AndroidAopReplaceMethod@AndroidAopReplaceClass("android.util.Log")
object AndroidLogInterceptor {@JvmStatic@AndroidAopReplaceMethod("int e(java.lang.String,java.lang.String)")fun e(tag: String, msg: String): Int {println("AOP AndroidLogInterceptor: $tag $msg")return 0}
}
方法拦截

可以拦截任意方法,进行额外处理

通过类名+方法名+参数类型+继承关系来匹配,被命中的方法会被拦截

kotlin">package com.android.code.aopimport com.flyjingfish.android_aop_annotation.ProceedJoinPoint
import com.flyjingfish.android_aop_annotation.anno.AndroidAopMatchClassMethod
import com.flyjingfish.android_aop_annotation.base.MatchClassMethod
import com.flyjingfish.android_aop_annotation.enums.MatchType@AndroidAopMatchClassMethod(targetClassName = "android.app.Activity",methodName = ["void onCreate(android.os.Bundle)"],type = MatchType.LEAF_EXTENDS
)
class AndroidActivityCreateInterceptor : MatchClassMethod {override fun invoke(joinPoint: ProceedJoinPoint,methodName: String): Any? {val target = joinPoint.target!!.javaClass.simpleNameprintln("AOP AndroidActivityCreateInterceptor: $target onCreate")return joinPoint.proceed()}
}
自定义切入点

如果不想写表达式,可以在想要拦截的方法上加一个切入点注解

再定义一个切入点处理器,与注解绑定,来处理拦截工作即可

此外,注解还可以携带一些参数,用于扩展需要

kotlin">package com.android.code.aopimport com.flyjingfish.android_aop_annotation.anno.AndroidAopPointCut@AndroidAopPointCut(AndroidContentViewInterceptor::class)
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
annotation class AndroidContentViewPointcut(vararg val args: String = [])
kotlin">@AndroidContentViewPointcut("HomeActivity")
override fun setContentView(view: View) {super.setContentView(view)
}
kotlin">package com.android.code.aopimport android.graphics.Color
import android.view.View
import com.flyjingfish.android_aop_annotation.ProceedJoinPoint
import com.flyjingfish.android_aop_annotation.base.BasePointCutclass AndroidContentViewInterceptor : BasePointCut<AndroidContentViewPointcut> {override fun invoke(joinPoint: ProceedJoinPoint,annotation: AndroidContentViewPointcut): Any? {val target = joinPoint.target!!.javaClass.simpleNameval pointcut = annotation.args[0]val contentView = joinPoint.args!![0] as ViewcontentView.setBackgroundColor(Color.YELLOW)println("AOP AndroidContentViewInterceptor: before target executed")println("AOP AndroidContentViewInterceptor: $target $pointcut setContentView")val result = joinPoint.proceed()println("AOP AndroidContentViewInterceptor: after target executed")return result}
}

可以看到,Activity的背景自动变成黄色了,完全不用改动原代码!

而且还能看到,在拦截过程中,我们是可以对原有方法执行流程进行调整的

或者进行预处理,后期处理

尾声

是不是觉得很强大呢,代码也十分简洁

以上特性已经足够满足一般AOP的需求了

如果有更复杂的需求,记得前往作者主页去看一看


http://www.ppmy.cn/devtools/97034.html

相关文章

BEM架构

视频 总结&#xff1a; BEM架构&#xff1a;一个命名类的规范而已&#xff0c;说白了就是如何给类起名字使用sass的目的&#xff1a;在<style>中模块化的使用类名&#xff0c;同时减少代码数量 1、 BEM架构 &#xff08;通义灵码查询结果&#xff09; BEM (Block Ele…

人工智能和机器学习 3(复旦大学计算机科学与技术实践工作站)python机器学习、Pytorch库入门、d2l学习+<机器学习、神经网络————原理、理论>

前言 安装 — 动手学深度学习 2.0.0 documentation (d2l.ai)https://zh.d2l.ai/chapter_installation/index.html 安装 我们需要配置一个环境来运行 Python、Jupyter Notebook、相关库以及运行本书所需的代码&#xff0c;以快速入门并获得动手学习经验。 安装 Miniconda 最…

深入探讨C语言中的高级指针操作

目录 指针与内存管理的高级技巧 1. 动态数组的重新分配 2. 内存碎片化的处理 3. 内存对齐 函数指针数组与回调函数的高级用法 1. 基本函数指针用法 2. 函数指针数组 3. 回调函数的使用 指针与数据结构的结合 1. 自定义链表 C语言以其强大的底层操作能力和高效的性能著…

YOLOv8改进方法

YOLOv8改进方法 为解决复杂环境下番茄生长点花蕾检测的难题,本研究针对目标尺度多样、外观相似、遮挡严重等问题,从骨干网络(Backbone)、颈部结构(Neck)和检测头(Head)三个方面系统改进了YOLOv8的网络结构和损失函数,旨在提高其对弱小目标的检测精度和环境适应性。 3.1 YOLOv…

C语言:链表添加

链表的添加的具体方法如下&#xff1a; 先判断链表是否有节点&#xff0c; 若没有&#xff0c; 头指针指向新来的节点&#xff0c;尾指针指向新来的节点。 若有&#xff0c; 尾节点的下一个指向新来的节点&#xff0c;尾指针指向新来的节点。 #include<stdio.h&…

逐级删除空目录 如果目录非空则停止删除操作 os.removedirs(path)

【小白从小学Python、C、Java】 【考研初试复试毕业设计】 【Python基础AI数据分析】 逐级删除空目录 如果目录非空 则停止删除操作 os.removedirs(path) [太阳]选择题 下列关于代码和os.removedirs(path)函数说法正确的是&#xff1f; import os os.makedirs("D:/test1…

Java面试--框架--Spring MVC

Spring MVC 目录 Spring MVC1.spring mvc简介2.spring mvc实现原理2.1核心组件2.2工作流程 3.RESTful 风格4.Cookie&#xff0c;Session4.1 会话4.2 保存会话的两种技术 5.拦截器5.1过滤器、监听器、拦截器的对比5.2 过滤器的实现5.3 拦截器基本概念5.4 拦截器的实现 1.spring …

爱心动画代码HTML5

这段代码是一个HTML5 Canvas动画&#xff0c;它通过JavaScript创建了一个动态的爱心效果。页面初始化时&#xff0c;首先定义了一些基本设置&#xff0c;如粒子数量、持续时间、速度等。然后&#xff0c;定义了Point和Particle类&#xff0c;用于处理粒子的位置和运动。接着&am…