一.面向切面编程(AOP)
在学习轮子哥的开源项目时,发现有防重复点击注解(SingleClick)和防重复点击切面(SingleClickAspect),比较好奇为什么有两种不同方法。
(1) 防重复点击注解(SingleClick):这是一个注解,用于标记需要防止重复点击的地方。可以在需要防止重复点击的按钮或者视图上添加这个注解。当用户点击标记了该注解的视图时,系统会根据注解定义的规则来判断是否执行点击操作。
(2)防重复点击切面(SingleClickAspect): 这是一个切面(Aspect),它通过 AOP(面向切面编程)的方式来实现防重复点击的功能。切面是一种编程范式,它允许在程序运行过程中,将一些横切关注点(cross-cutting concerns)从核心业务逻辑中分离出来,以便更好地管理和维护这些关注点。在这种情况下,防重复点击是一个横切关注点,通过切面的方式来实现可以将这个功能与业务逻辑解耦,使得代码更加清晰和可维护。
(3)它们之间的关系在于,防重复点击注解(SingleClick)可以在代码中直接标记需要防止重复点击的视图,而防重复点击切面(SingleClickAspect)则是一种更加通用的解决方案,可以在切面中统一管理所有需要防止重复点击的操作,而不必在每个视图上添加注解。
(4) 在防重复点击切面(SingleClickAspect)的例子中,切面的作用是在特定的连接点(如按钮点击事件)周围应用一段代码,以阻止短时间内的重复点击。这通过环绕通知来实现,环绕通知可以在方法执行前后添加自定义行为。AOP 通过提供这种高度模块化的方式来处理跨应用程序的共有问题,从而让开发者能够集中精力编写核心业务逻辑,同时还能保持代码的清晰和易于维护。
然后就对切面编程(AOP)、切面(Aspect),以及横切关注点的概念进行了粗略的了解
(1) 面向切面编程(AOP)是一种编程范式,它允许开发者将全局关注点(如日志记录、安全性、缓存等)从业务逻辑代码中分离出来。这种分离有助于减少代码的重复,并提高其模块化。AOP 不是取代传统的面向对象编程(OOP),而是与之相辅相成。
(2)切面是 AOP 的主要构建块。一个切面是一个模块化的关注点的实现,例如日志记录或事务管理。切面可以定义为包含一些点的集合(称为连接点)和在这些点上采取的操作(称为通知)。
(3)横切关注点是指那些影响多个类的问题或行为,但不是类的主要功能。例如,日志记录通常需要跨多个类和模块进行,但它并不是这些类的主要业务目的。
(4)AOP 主要术语
1.连接点(Join Point):程序执行过程中插入切面的点,如方法调用或字段赋值操作。
2.通知(Advice):在切面的某个特定连接点执行的动作。通知类型包括前置通知、后置通知、环绕通知等。
3.切入点(Pointcut):匹配一个或多个连接点的表达式。切入点帮助确定在何处应用通知。
4.引入(Introduction):添加方法或字段到现有的类中。
5.目标对象(Target Object):被一个或多个切面所通知的对象。
6.织入(Weaving):是指将切面与其他应用程序类型或对象连接起来,可以在编译时、加载时或运行时完成。
二.关于注解的部分知识
在学习轮子哥的开源项目时,很容易发现@NonNull 和 @Nullable 注解,字面上很好理解,一个可为空,一个不可为空,主要是为了避免空指针异常的发生。但是在定义的时候还发现了元注解@Retention 和 @Target 就简单了解了一下。
(1)在编写自定义注解时,可以根据需要添加其他元注解以提供额外的元数据或限制。
(2)@Retention:用于指定被修饰的注解在编译后的代码中的保留策略。它有一个 RetentionPolicy 类型的属性 value,用于指定保留的级别。
常见的级别包括:
1.RetentionPolicy.SOURCE:注解仅保留在源代码中,不会包含在编译后的字节码文件中。
2.RetentionPolicy.CLASS:注解会被包含在编译后的字节码文件中,但在运行时不可访问。
3.RetentionPolicy.RUNTIME:注解会被包含在编译后的字节码文件中,并在运行时可通过反射获取。
例如,@Retention(RetentionPolicy.RUNTIME) 指示被修饰的注解在运行时可通过反射访问。
(3)@Target:用于指定被修饰的注解可以应用到的元素类型(类、方法、字段等)。它有一个 ElementType 类型的数组属性 value,用于指定可以应用注解的目标。
常见的目标包括:
1.ElementType.TYPE:类、接口、枚举等。
2.ElementType.FIELD:字段。
3.ElementType.METHOD:方法。
4.ElementType.PARAMETER:方法的参数。
5.ElementType.CONSTRUCTOR:构造函数。
6.ElementType.LOCAL_VARIABLE:局部变量。
7.ElementType.ANNOTATION_TYPE:注解类型。
8.ElementType.PACKAGE:包。
例如,@Target(ElementType.METHOD) 指示被修饰的注解只能应用到方法上。
(4)除了 @Retention 和 @Target 这两个常见的元注解之外,还有其他一些元注解,例如:
1.@Documented:用于指示注解是否应该包含在 Java 文档中。
2.@Inherited:用于指示注解是否可以被子类继承。
3.@Repeatable:用于指示注解是否可以多次应用于同一元素。
4.@Deprecated:用于指示注解已过时。
(5)这些元注解可以根据需要添加,以提供更多的元数据或限制。但对于大多数情况来说,只使用 @Retention 和 @Target 就足够了。所以没有更深入的去了解
(6)自定义注解的格式在 Java 和 Kotlin 中有所不同,以下是一个简单的自定义注解例子。
Java:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) // 指定注解保留到运行时
@Target(ElementType.METHOD) // 指定注解作用于方法上
public @interface MyAnnotation {
String value() default ""; // 定义注解的属性,可以在使用时传入值
int priority() default 0; // 定义注解的另一个属性
}
Kotlin:
@Retention(AnnotationRetention.RUNTIME) // 指定注解保留到运行时
@Target(AnnotationTarget.FUNCTION) // 指定注解作用于函数上
annotation class MyAnnotation(
val value: String = "", // 定义注解的属性,可以在使用时传入值
val priority: Int = 0 // 定义注解的另一个属性
)
三.安卓网络技术的简单应用
(1)Okhttp的使用
在使用OkHttp之前,我们需要先在项目中添加OkHttp库的依赖,然后需要创建一个OkHttpClient
的实例,创建一个Request
对象,调用OkHttpClient的newCall()
方法来创建一个Call
对象,并调用它的execute()
方法来发送请求并获取服务器返回的数据
private fun sendRequestWithOkHttp() {
thread {
try {
// 1.创建一个OkHttpClient实例
val client = OkHttpClient()
// 2.创建并完善一个请求,传入url地址
val request = Request.Builder()
.url("https://www.baidu.com")
.build()
// 3.创建Call对象发生请求并返回数据
val response = client.newCall(request).execute()
//4. 返回的数据有多部分,获取响应体的数据并转为String类型
val responseData = response.body?.string()
if (responseData != null) {
showResponse(responseData)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
如果是发起一条POST
请求,需要先构建一个Request Body
对象来存放待提交的参数,然后在Request.Builder中调用一下post()
方法,并将RequestBody
对象传入:
val requestBody = FormBody.Builder()
.add("username", "admin")
.add("password", "123456")
.build()
val request = Request.Builder()
.url("https://www.baidu.com")
.post(requestBody)
.build()