Android内存优化:用注解的方式替代枚举

1. 问题起源

那天写代码的过程中,switch使用枚举类作为条件时,突然出现了一个报错

枚举 switch case 标签必须为枚举常量的非限定名称

public class UsbMsg {

    private MsgType mMsgType;

	// 这是我的枚举
    public enum MsgType {
        MOUNT,
        UNMOUNT,
        BAD_REMOVAL,
        REMOVED
    }

	public MsgType getMsgType {
		return mMsgType;
	}
}

// 这是使用时的代码
switch (usbMsg.getMsgType()) {
    case MsgType.MOUNT:  // 报错行
    case MsgType.UNMOUNT: {
        showUsbList(volumes);
        break;
    }
}

[黑人问号脸.jpg] 这是哪儿错了???一番百度之后发现,人家写的很明白了,直接用enum里面的名称,把MsgType去掉,不用限定,因为你的switch里面已经限定是这个枚举类里面的值了!
后来就跟同事吐槽了一下,然后同事为我打开了新世界大门,他说他一般不用枚举,用注解的方式!仿照android原生VISIBLE/INVISIBLE/GONE的写法!!高级了一下!

2. 为什么不使用枚举?

找了一篇文章==>Android官方不建议使用枚举的原因,大概原因就是因为枚举本身是一个类,编译后会对每一种定义的类型生成相应对象,相对于静态常量来讲,消耗了很多内存。如果只是单纯的想做类型限定的话,完全没必要使用枚举。

3. 如何使用注解替代枚举?

下面我们来看一下,android原生是怎么写的?

    /** @hide */
    @IntDef({VISIBLE, INVISIBLE, GONE}) // Visibility的类型限定
    @Retention(RetentionPolicy.SOURCE) // 注解只存在于源码编译期
    public @interface Visibility {}

    /**
     * This view is visible.
     * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
     * android:visibility}.
     */
    public static final int VISIBLE = 0x00000000;

    /**
     * This view is invisible, but it still takes up space for layout purposes.
     * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
     * android:visibility}.
     */
    public static final int INVISIBLE = 0x00000004;

    /**
     * This view is invisible, and it doesn't take any space for layout
     * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
     * android:visibility}.
     */
    public static final int GONE = 0x00000008;

首先定义了几个常量类型,之后定义了一个注解名为Visibility,使用了两个注解,@IntDef用来限定Visibility中int类型常量的值(默认情况下值不可重复,会有编译报错,若一定要重复如更新一个变量名,但又要保持向下兼容,就可以使用@SuppressLint(“UniqueConstants”)拒绝类型检查),@Retention用来限定该注解存在于源码时期,一般用来做一些源码检查操作。
在使用时,我们可以像下面一样将注解加在参数上,这样就可以像Enum一样对参数进行类型限制。值得注意的是,这样的类型检查只会在编译器中进行提醒,并不会影响编译过程,如果你无视提醒直接运行那么也是不会报错的。

public void setVisibility(@Visibility int visibility) {
        setFlags(visibility, VISIBILITY_MASK);
}

那么下面我们仿照Android原生的代码修改一下之前的代码,就会变成这样

public class UsbMsg {

    private int mMsgType;

	// 这是我的注解
    @IntDef({MOUNT, UNMOUNT, BAD_REMOVAL, REMOVED})
    @Retention(RetentionPolicy.SOURCE)
    public @interface MsgType {
    }
    public static final int MOUNT = 0x0;
    public static final int UNMOUNT = 0x2;
    public static final int BAD_REMOVAL = 0x4;
    public static final int REMOVED = 0x8;

    @MsgType
    public int getMsgType() {
        return mMsgType;
    }

}

switch (usbMsg.getMsgType()) {
    case UsbMsg.MOUNT: {
        break;
    }
    case UsbMsg.UNMOUNT: {
        break;
    }
    default: {
        break;
    }
}

注意到@IntDef这个注解并不是默认提供的,是在support包中的,所以使用的话需要引入一下包compileOnly ‘com.android.support:support-annotations:28.0.0’,包版本根据你的compileSdkVersion来,另外他还有个好兄弟可以做String类型的限定 - @StringDef。最后查找资料过程中发现一个写的不错的文章,推荐下==>Android中不使用枚举类(enum)替代为@IntDef @StringDef

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章