LinearLayout类中:
@IntDef({HORIZONTAL, VERTICAL})
@Retention(RetentionPolicy.SOURCE)
public @interface OrientationMode {}
public static final int HORIZONTAL = 0;
public static final int VERTICAL = 1;
private int mOrientation;
public void setOrientation(@OrientationMode int orientation) {
if (mOrientation != orientation) {
mOrientation = orientation;
requestLayout();
}
}
@OrientationMode
public int getOrientation() {
return mOrientation;
}
Java / kotlin注解定义对比:
//java 注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Test {}
//kotlin 注解
@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD, AnnotationTarget.FUNCTION)
@kotlin.annotation.Retention(AnnotationRetention.SOURCE)
annotation
class Test
Android中不使用枚举类(enum)替代为@IntDef @StringDef
使用注解代替枚举(enum)
enum在java中的实质是特殊单例的静态成员变量。在运行期,所有枚举类作为单例,全部加载到内存中。
所以,枚举增加了运行时的内存占用。
@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD, AnnotationTarget.FUNCTION)
@MustBeDocumented
@IntDef(Sex.MAN, Sex.WOMEN)
@kotlin.annotation.Retention(AnnotationRetention.SOURCE)
annotation
class Sex {
companion object {
const val MAN = 0x2
const val WOMEN = 0x3
}
}
//使用@IntDef/@StringDef + @interface来进行限定参数:
@IntDef({ItemState.ADD, ItemState.SUCCESS, ItemState.LOADING, ItemState.FAIL})
@Retention(RetentionPolicy.SOURCE)
public @interface ItemState {
int ADD = 0;
int SUCCESS = 1;
int LOADING = 2;
int FAIL = 3;
}
一、简单静态常量
import androidx.annotation.IntDef
class SexTest1 {
companion object {
private const val MAN = 101
private const val WOMEN = 102
}
private var sex: Int = 0
//设置性别
fun setSex(sex: Int) {
this.sex = sex
}
//获取性别
fun getSex(): String {
if (MAN == sex) return "男"
return if (WOMEN == sex) "女" else "未知"
}
}
//当我们定义了一个男女的final整型作为入参时,不一定保证入参的都是我们想要的入参
//这里就有一个 类型不安全 的问题出现,而枚举就可以解决这个问题
//fun main() {
// val sexTest1 = SexTest1()
// (102)
// val sex1 = ()
// println("====================================$sex1")
//}
二、枚举常量
Enum 是 java 中一种包含固定常数的类型
当我们需要预先定义一些值,并限定范围时,使用 Enum,来做到编写和编译都查错
-
Java 的 Enum 的实质是特殊单例的静态成员变量
-
Enum 可以在编写器,编译器做到各种静态检查防呆
-
Enum 在运行期,所有枚举类作为单例,全部加载到内存中
因为上述原因,Enum 增加了APK 的内存占用,比常量多5到10倍的内存占用
所以放弃枚举,就是关于安卓应用性能的内存占用部分的最佳实践方法之一
class SexTest2 {
private var sex: SexEnum? = null
enum class SexEnum {
MAN, WOMEN
}
//设置性别
fun setSex(sex: SexEnum) {
this.sex = sex
}
//获取性别
fun getSex(): String {
if (SexEnum.MAN == sex) return "男"
return if (SexEnum.WOMEN == sex) "女" else "未知"
}
}
//
//利用枚举,在 setSex() 方法里面对入参做了枚举Sex的限制
//对于想输入任何非枚举类Sex里面定义的枚举常量,编译都是不能通过的
//这就很好的限制了入参混乱的问题
//
//使用 Enum 的缺点
//
//每一个枚举值都是一个单例对象,在使用它时会增加额外的内存消耗,
// 所以枚举相比与 Integer 和 String 会占用更多的内存
//较多的使用 Enum 会增加 DEX 文件的大小,会造成运行时更多的IO开销,使我们的应用需要更多的空间
//特别是分dex多的大型APP,枚举的初始化很容易导致ANR
//fun main() {
// val sexTest2 = SexTest2()
// ()
// val sex2 = ()
// println("====================================$sex2")
//}
三、注解
众所周知,在Android中使用Enum枚举会极大的影响 性能,内存消耗大。原因如下:
Android官方文档中也有说明,enum中的每一个值其实都是一个Object对象,
每声明一个值就会创建一部分的内存以使它能够被引用到这个对象,相比于静态常量,enum会花费近2倍的内存空间。
通常使用定义静态常量来代替Enum使用。但是这种方式在用户不了解就会出现取值范围不清楚的问题,
调用者在不知道源码的情况下有可能会导致传值错误,而且也不知道从何处找到该常量,
为了解决这种方式google官方提供了另外一种很好的解决方式。
如果在需要用大量的Enum时,用这种方式替换相信内存占用及性能会好很多,而且也是google官方推荐的。
class SexTest3 {
//注解:核心
@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD, AnnotationTarget.FUNCTION)
@MustBeDocumented
@IntDef(MAN, WOMEN)
@kotlin.annotation.Retention(AnnotationRetention.SOURCE)
annotation
class Sex
@Sex
private var sex: Int = 0
fun setSex(@Sex sex: Int) {
this.sex = sex
}
fun getSex(): String {
if (MAN == sex) return "男"
return if (WOMEN == sex) "女" else "未知"
}
companion object {
const val MAN = 0x2
const val WOMEN = 0x3
}
}
//fun main() {
// val sexTest3 = SexTest3()
// ()
// val sex = ()
// println("===============================$sex")
//}
不使用枚举类型的解决方案
既然是因为参数的类型太泛了造成的类型不安全,那么我只要将参数限定在某一个类型集合里面
要将的@IntDef/@StringDef + @interface来进行限定参数
字符串也可以使用注解@StringDef:
class StringConstants {
@FlagDef
var flag = UNDEFINE
// 表示开启Doc文档
@MustBeDocumented
//限定为 ,
@StringDef(OK, ERROR)
//表示注解作用范围,参数注解,成员注解,方法注解
@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD, AnnotationTarget.FUNCTION)
//表示注解所存活的时间,在运行时,而不会存在 .class 文件中
@Retention(AnnotationRetention.SOURCE)
annotation class FlagDef//接口,定义新的注解类型
companion object {
const val UNDEFINE = "undefine"
const val OK = "ok"
const val ERROR = "error"
}
}
fun main() {
val stringConstants = StringConstants()
stringConstants.flag = StringConstants.OK
println("========================================${stringConstants.flag}")
}