安卓学习笔记(三)

本文探讨了面向切面编程(AOP)中的防重复点击注解和切面实现,以及Java注解的元注解Retention和Target在自定义注解中的作用。同时介绍了OkHttp在Android网络技术中的简单应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.面向切面编程(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()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值