Android使用注解代替枚举从而节省系统使用的内存开销

时间:2022-09-05 17:58:50

  Java5以后开始支持枚举类型,枚举类型使用起来非常方便,其重要的作用是作为类型安全使用的。如果在不考虑系统内存开销的情况下大量的使用枚举也不会有什么问题。但是移动端还是需要注意的。

  android系统在应用启动后会给应用单独分配一块内存。应用的dex code、heap以及运行时的内存分配都会在这块内存中。而使用枚举类型的dex size是普通常亮的13倍以上。在运行时的内存分配,一个enum的声明至少要消耗掉20个bytes。从这两点就可以说明,在app中大量使用枚举的内存开销是非常大的。

  枚举最大的优势是类型安全。那么是不是又办法在不使用枚举的情况下做到类型安全呢?答案是肯定的,下面看看怎么干。

  goodle官方很早就发现了枚举对android系统带来的性能开销,所以在其官网上就已经提醒了开发者尽量少的使用枚举,而且还提供了注解的方式来检查类型安全。目前其提供了int和string两种注解方式。分别是:IntDef和StringDef。

  话不多说,直接上例子。ps:demo里面有详细的注释。

一、Int类型注解检查类型安全

package com.yw.enumproxylib;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import androidx.annotation.IntDef;

/**
 * 定义一个int类型的注解
 * 用注解代替枚举,做到类型安全
 * create by yangwei
 * on 2020-01-30 21:34
 */
public class EnumProxy {
    public static final int READ_CAR = 0;//红色的汽车
    public static final int GREEN_CAR = 1;//绿色的汽车
    public static final int YELLOW_CAR = 2;//黄色的汽车


    @IntDef({READ_CAR, GREEN_CAR, YELLOW_CAR})
    @Retention(RetentionPolicy.SOURCE)//源码级别
    public @interface CAR_Enum {

    }

    /**
     * 获取汽车类型
     *
     * @param car
     * @return
     */
    public static int getCar(@CAR_Enum int car) {
        switch (car) {
            case READ_CAR:
                return 0;
            case GREEN_CAR:
                return 1;
            case YELLOW_CAR:
                return 2;
        }
        return -1;
    }
}

二、String类型注解检查类型安全

package com.yw.enumproxylib;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import androidx.annotation.StringDef;

/**
 * 定义一个string类型的注解,用于检查星期的类型安全。
 * create by yangwei
 * on 2020-01-30 22:04 week
 */
public class StringEnum {

    public static final String MONDAY = "monday";
    public static final String TUESDAY = "tuesday";
    public static final String WENDESDAY = "wendesday";
    public static final String THURSDAY = "thursday";
    public static final String FRIDAY = "friday";
    public static final String SATURDAY = "saturday";
    public static final String WEEKDAY = "weekday";

    @StringDef({MONDAY, TUESDAY, WENDESDAY, THURSDAY, FRIDAY, SATURDAY, WEEKDAY})//此处定义注解的值只能是这几个
    @Retention(RetentionPolicy.SOURCE)//编译时注解,源码级检查
    public @interface Week {

    }

    /**
     * 获取日期
     *
     * @param week
     * @return
     */
    public static String getWeek(@Week String week) {
        switch (week) {
            case MONDAY:
                return "星期一";
            case TUESDAY:
                return "星期二";
            case WENDESDAY:
                return "星期三";
            case THURSDAY:
                return "星期四";
            case FRIDAY:
                return "星期五";
            case SATURDAY:
                return "星期六";
            case WEEKDAY:
                return "星期日";
        }
        return null;
    }
}

三、用来检查类型安全的MainActivity,从下面可以看到,当使用EnumProxy.getCar输入参数的时候,如果直接输入一个整数则编译不通过。当输入我们定义的EnumProxy.GREEN_CAR编译才通过。

  同理StringEnum也能检查类型安全。

package com.yw.enumproxy;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

import com.yw.enumproxylib.EnumProxy;
import com.yw.enumproxylib.StringEnum;

/**
 * 测试例子
 */
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        int car_black = 10;
        int bk = EnumProxy.getCar(car_black);//此处类型检查不通过
        int ck = EnumProxy.getCar(EnumProxy.GREEN_CAR);//类型检查通过


        String str = "friday";
        String week1 = StringEnum.getWeek(str);//直接赋值String时类型检查不通过
        String week2 = StringEnum.getWeek(StringEnum.FRIDAY);//赋值定义好的值时类型检查通过
    }
}

 

结束语:先写这么多,明天在把demo发到github上。疫情期间大家不要乱跑,出门记得戴口罩。中国加油、武汉加油。