Android 从枚举到注解最佳实践

背景

前几天看到秋百万的一篇文章Android 中的 Enum 到底占多少内存?该如何用?,其实对这个东西还是很敏感的,因为最近就在Android的项目中就用到了一个枚举类。不是不知道枚举的坏处,而是枚举具有很好的约束能力,所以才选择了它。

但是似乎在Android平台上其约束能力体现出来的优点还不足以抵消它的缺点,恰恰其带来的内存消耗牺牲更大。当然我是知道这一点的,但是并没有对具体的数值做过测试,因为之前认为这在一个可以接受的范围内。看了秋百万的文章后,即使觉得不碍大事,但是在Android里使用枚举是一个不好的习惯,毕竟Android不是Web,因此有必要重构一发代码。

枚举

首先来看看我这个枚举类是什么,这是一个涉及到http接口环境的类。这个类的大致内容如下。

public enum Environment {
    /**
     * 正式环境http
     */
    RELEASE_HTTP("http://gw.release.domain.com"),
    /**
     * 预发环境http
     */
    PRE_HTTP("http://gw.pre.domain.com"),
    /**
     * 测试环境http
     */
    DAILY_HTTP("http://gw.daily.domain.com"),
    /**
     * 正式环境https
     */
    RELEASE_HTTPS("https://gw.release.domain.com"),

    /**
     * 预发环境https
     */
    PRE_HTTPS("https://gw.pre.domain.com"),

    /**
     * 测试环境https
     */
    DAILY_HTTPS("https://gw.daily.domain.com");


    /**
     * url
     */
    String mEnvironmentHost;

    /**
     * @param environmentHost
     */
    Environment(String environmentHost) {
        this.mEnvironmentHost = environmentHost;
    }

    //根据Environment获得url
    public String getEnviromentHost() {
        return mEnvironmentHost;
    }

    /**
     * 根据url返回Environment枚举类
     * @param host
     * @return
     */
    public static Environment fromHost(String host) {
        for (Environment value : values()) {
            if (value.getEnviromentHost().equals(host)) {
                return value;
            }
        }
        return null;
    }
}

之所以使用枚举类,是因为我想约束这个url为这个6个url中的其中一个,并不想让开发者传入这6个环境以外的其他任意一个环境。环境分为http和https,并且都具有日常,预发,线上三者,2*3=6,刚好6种。

真正使用时,直接使用枚举类限定参数类型,这样就起到了很好的约束能力。

private Environment environment;
public void setEnvironment(Environment environment) {
    this.environment = environment;
}

其实在写这个类的时候,我再三考虑要不要使用枚举,但是最终我用了,因为我使用常量的话,就起不到这个约束能力了。

注解

之前看到Android源码中有使用注解进行约束,比如资源的约束就有这么一些注解:@ColorRes、@RawRes、@StringRes、@LayoutRes、@AnimatorRes、@AnimRes、@ArrayRes、@AttrRes、@BoolRes、@DimenRes、@DrawableRes、@IdRes等等。

其实看到过一段源码,是设置View的Visibility属性的。

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

当时知道可以通过注解来约束这个参数,但是没有跟进去看这个注解到底是什么。其实这个注解用了另一个注解@IntDef,其作用就是让加上了@Visibility注解的参数约束为@IntDef中定义的数组的值,这里就是约束为了VISIBLE, INVISIBLE, GONE三个int常量

public static final int VISIBLE = 0x00000000;
public static final int INVISIBLE = 0x00000004;
public static final int GONE = 0x00000008;
@IntDef({VISIBLE, INVISIBLE, GONE})
@Retention(RetentionPolicy.SOURCE)
public @interface Visibility {}

而这个@IntDef注解是在support-annotations包中。

compile 'com.android.support:support-annotations:23.3.0'
}

除了@IntDef注解外,这个包中还有很多注解,作用其实都是为了起到一定程度的约束作用。

最佳实践

于是,我准备用该包中的注解进行对枚举类的改造。其实用到的就一个注解,即@StringDef注解。

首先建立一个@Environment注解,在里面定义6个字符串常量,即不同的环境。

public @interface Environment {
    /**
     * 正式环境http
     */

    public static final String RELEASE_HTTP = "http://gw.release.domain.com";
    /**
     * 预发环境http
     */
    public static final String PRE_HTTP = "http://gw.pre.domain.com";
    /**
     * 测试环境http
     */
    public static final String DAILY_HTTP = "http://gw.daily.domain.com";
    /**
     * 正式环境https
     */
    public static final String RELEASE_HTTPS = "https://gw.release.domain.com";
    /**
     * 预发环境https
     */
    public static final String PRE_HTTPS = "https://gw.pre.domain.com";
    /**
     * 测试环境https
     */
    public static final String DAILY_HTTPS = "https://gw.daily.domain.com";
}

然后在该注解上加上@StringDef注解,约束为定义的6个常量

@StringDef({Environment.RELEASE_HTTP, Environment.PRE_HTTP, Environment.DAILY_HTTP, Environment.DAILY_HTTPS, Environment.PRE_HTTPS, Environment.RELEASE_HTTPS})

为了让注解只在源码级别存在,我们还需要加入下面的元注解

@Retention(RetentionPolicy.SOURCE)

最后就是修改设置环境的代码,在其入参上加入注解限制。

private String environment;

public void setEnvironment(@Environment String environment) {
    this.environment = environment;
}

这时候,如果你使用的不是注解约束的6个环境,那么就会报一个提示,并且是红色的下划线,提示你这里需要修改。

这里写图片描述

于是你必须像这么使用

core.setEnvironment(Environment.DAILY_HTTP);
core.setEnvironment(Environment.PRE_HTTP);
core.setEnvironment(Environment.RELEASE_HTTP);
core.setEnvironment(Environment.DAILY_HTTPS);
core.setEnvironment(Environment.PRE_HTTPS);
core.setEnvironment(Environment.RELEASE_HTTPS);     

这样以来,在一定程度上能起到约束作用。But,如果你无视了该警告,编译仍然是可以通过的哟~,这一点需要特别注意哦。

其实这个support-annotation包中还有很多很有用的注解,有兴趣的可以自己一一去看一下。

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值