enum、static final 与 IntDef:Android 中实现枚举的方案选择

前述

曾经有一段时间,许多网上的 Android 性能调优的文章都提到,要尽可能避免在 Android 中使用 enum,由于使用 enum 会引入较大的性能损失。html

然而,最新的 Android 文档已经改变了这一说法。根据 Android VM 的开发者Elliot Hugues 的博客所述,过去的 Android 官网的性能优化指南并不许确,混杂了许多臆断。所以现在他们严格地依据事实,重写了Android 性能优化指南,开发者也应当以最新的文档为准。固然比较窘迫的是,Android 文档的更新并非同时改口,事实上就在同个 training 目录下的 管理应用内存一文中,就仍然保留了过期的避免使用 enum 的说法。java

最新的解释

之因此从新鼓励使用 enum ,其解释是:android

  1. Android 2.2 及如下系统上,使用 enum 的确会引起较大的性能损耗。主要是内存上的消耗,enum 远大于使用 static final int。安全

  2. 在 Android 2.3 及之后的系统中,以前的一些 enum 的性能问题已被 JIT 所优化。此时,虽然 enum 相比于 static final int,内存仍然有所增长,但已是能够接受的了。加之 Android 2.2 到现在的 Android 7.0,Android 手机的内存配置日新月异,从256MB跃升至6GB,enum 所带来的内存增长已经能够忽略。性能优化

强内存依赖的应用的枚举实现

尽管如此,在实际开发中仍然有可能遇到内存消耗较大的应用开发问题,那么此时,该如何优化枚举值的实现,以节约内存消耗呢?方案以下:ide

直接使用 static final int

然而,其问题在于,直接使用没法实现枚举变量赋值的类型安全。且没法把多个枚举值概括到同一个枚举类型下。好比:性能

private static final int MONDAY = 0;
private static final int TUESDAT= 1;
private static final int WEDNESDAY = 2;
private static final int THURSDAY = 3;
private static final int FRIDAY = 4;
private static final int SATURDAY = 5;
private static final int SUNDAY = 6;

private static final int JANUARY = 7;

private int day = JANUARY;

显然,此时 int 就未能实现赋值的类型检查,也未能把多个枚举值概括到同一个枚举类型下。优化

Android Proguard 优化

在 Android Proguard 中,能够在 proguard.cfg 中加入参数 -Doptimization class/unboxing/enum,从而自动将 enum 替换为 static final int。这样,也就无需担忧多余的内存问题了。this

使用 IntDef 注解替代 int

IntDef 能够用于替代 int,其价值在于用@IntDef int var限定赋值范围,实现类型安全。还用 @IntDef({SUNDAY, MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY})归集了散乱的 static final int 变量,以下代码所示:code

public class MainActivity extends Activity {
 
    public static final int SUNDAY = 0;
    public static final int MONDAY = 1;
    public static final int TUESDAY = 2;
    public static final int WEDNESDAY = 3;
    public static final int THURSDAY = 4;
    public static final int FRIDAY = 5;
    public static final int SATURDAY = 6;
 
    @IntDef({SUNDAY, MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY})
    @Retention(RetentionPolicy.SOURCE)
    public @interface WeekDays {}
 
    @WeekDays int currentDay = SUNDAY;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setCurrentDay(WEDNESDAY);
 
        @WeekDays int today = getCurrentDay();
 
        switch (today){
            case SUNDAY:
                break;
            case MONDAY:
                break;
            case TUESDAY:
                break;
            case WEDNESDAY:
                break;
            case THURSDAY:
                break;
            case FRIDAY:
                break;
            case SATURDAY:
                break;
            default:
                break;
        }
 
    }
 
    public void setCurrentDay(@WeekDays int currentDay) {
        this.currentDay = currentDay;
    }
 
    @WeekDays
    public int getCurrentDay() {
        return currentDay;
    }
}

然而,IntDef 的缺点在于没法优雅地把 int 转为 IntDef,尤为在一个枚举值是服务端下发的时候。强行的实现会变的极为尴尬:

@WeekDays
public int getDay(int value) {
        switch (value){
            case 0:
                return SUNDAY;
            case 1:
                return MONDAY;
            case 2:
                return TUESDAY;
            case 3:
                return WEDNESDAY;
            case 4:
                return THURSDAY;
            case 5:
                return FRIDAY;
            case 6:
               return SATURDAY;
}

此时,在枚举值较少的时候还能忍,较多的时候代码就会变得很是丑陋。本质是由于,@IntDef 缺乏像 Enum.values() Enum.ordinal() 等等 int 与 enum 与 String 互转的方法,所以在想换转换较多的场景下,不如采起第二种优化方法。

====================================

若是您以为个人文章对您有所启迪,请点击文末的推荐按钮,您的鼓励将会成为我坚持写做的莫大激励。 by DesGemini

相关文章
相关标签/搜索