资讯专栏INFORMATION COLUMN

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

yuanzhanghu / 2264人阅读

摘要:比如显然,此时就未能实现赋值的类型检查,也未能把多个枚举值归纳到同一个枚举类型下。强行的实现会变的极为尴尬此时,在枚举值较少的时候还能忍,较多的时候代码就会变得非常丑陋。

前述

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

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

最新的解释

之所以重新鼓励使用 enum ,其解释是:

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

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

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

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

直接使用 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。这样,也就无需担心多余的内存问题了。

使用 IntDef 注解替代 int

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

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/66086.html

相关文章

  • 进击Android工程师之Java基础: 注解

    摘要:基本语法我们通过注解的定义来切入注解的语法。跟定义接口差不多,就是用到的是,然后加上了元注解。那么元注解的作用是什么呢元注解元注解说明了注解所修饰对象的类型。也就是标识该注解可以被继承。的内置注解重写了父类的方法表示已过时,不推荐使用。 在Android开发中我们经常会用到注解,例如@Override Butterknife中的BindView等。这里主要记录下注解怎么写和简单的使用。...

    muddyway 评论0 收藏0
  • 性能优化(三)看完这篇文章,至少解决 APP 中 90 % 内存异常问题

    摘要:不能满足被回收的条件,尽管调用也还是不能得到回收这就造成了内存泄漏。种解决单例中的内存泄漏将引用置为销毁监听使用弱引用将监听器放入弱引用中从弱引用中取出回调通过第七小点就能完美的解决单例中回调引起的内存泄漏。我们为什么要优化内存 showImg(https://user-gold-cdn.xitu.io/2019/5/12/16aac64e31d8c501); 在 Android 中我们写的...

    Elle 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<