在Android Support Library19.1版本中治筒,Android工具小組引入了幾個(gè)很酷的注解類型,供開發(fā)者在工程中使用股缸。Support Library自身也使用這些注解,這是一個(gè)好兆頭。就讓我們好好研究下歇僧。 通過gradle可以很容易的把這些注解添加到我們的工程中:
compile 'com.android.support:support-annotations:20.0.0'
有三種類型的注解可供我們使用:
- Nullness注解;
- 資源類型注解锋拖;
- IntDef和StringDef注解诈悍;
我們將通過代碼例子來講解每一種類型的作用以及在工程中如何使用它們。
Nullness注解
使用@NonNull注解修飾的參數(shù)不能為null兽埃。在下面的代碼例子中侥钳,我們有一個(gè)取值為null的name變量,它被作為參數(shù)傳遞給sayHello函數(shù)柄错,而該函數(shù)要求這個(gè)參數(shù)是非null的String類型:
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String name = null;
sayHello(name);
}
void sayHello(@NonNull String s) {
Toast.makeText(this, "Hello " + s, Toast.LENGTH_LONG).show();
}
}
由于代碼中參數(shù)String s使用@NonNull注解修飾舷夺,因此IDE將會(huì)以警告的形式提醒我們這個(gè)地方有問題:
如果我們給name賦值苦酱,例如String name = “Our Lord Duarte”,那么警告將消失给猾。使用@Nullable注解修飾的函數(shù)參數(shù)或者返回值可以為null躏啰。假設(shè)User類有一個(gè)名為name的變量,使用User.getName()訪問耙册,那么我們可以編寫如下代碼:
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
User user = new User("Our Lord Duarte");
Toast.makeText(this, "Hello " + getName(user), Toast.LENGTH_LONG).show();
}
@Nullable
String getName(@NonNull User user) {
return user.getName();
}
}
因?yàn)間etName函數(shù)的返回值使用@Nullable修飾给僵,所以調(diào)用:
Toast.makeText(this, "Hello " + getName(user), Toast.LENGTH_LONG).show();
沒有檢查getName的返回值是否為空,將可能導(dǎo)致crash详拙。
資源類型注解
是否曾經(jīng)傳遞了錯(cuò)誤的資源整型值給函數(shù)帝际,還能夠愉快的得到本來想要的整型值嗎?資源類型注解可以幫助我們準(zhǔn)確實(shí)現(xiàn)這一點(diǎn)饶辙。在下面的代碼中蹲诀,我們的sayHello函數(shù)預(yù)期接受一個(gè)字符串類型的id,并使用@StringRes注解修飾:
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sayHello(R.style.AppTheme);
}
void sayHello(@StringRes int id) {
Toast.makeText(this, "Hello " + getString(id), Toast.LENGTH_LONG).show();
}
}
而我們傳遞了一個(gè)樣式資源id給它弃揽,這時(shí)IDE將提示警告如下:
類似的脯爪,我們把警告的地方使用一個(gè)字符串資源id代替警告就消失了:
sayHello(R.string.name);
IntDef和StringDef注解
我們要介紹的最后一種類型的注解是基于Intellij的“魔術(shù)常量”檢查機(jī)制(http://blog.jetbrains.com/idea/2012/02/new-magic-constant-inspection/) (我們不需要詳細(xì)了解這個(gè)機(jī)制具體是如何實(shí)現(xiàn)的,想了解的話可以點(diǎn)擊鏈接)矿微。
很多時(shí)候痕慢,我們使用整型常量代替枚舉類型(性能考慮),例如我們有一個(gè)IceCreamFlavourManager類涌矢,它具有三種模式的操作:VANILLA掖举,CHOCOLATE和STRAWBERRY。我們可以定義一個(gè)名為@Flavour的新注解娜庇,并使用@IntDef指定它可以接受的值類型塔次。
public class IceCreamFlavourManager {
private int flavour;
public static final int VANILLA = 0;
public static final int CHOCOLATE = 1;
public static final int STRAWBERRY = 2;
@IntDef({VANILLA, CHOCOLATE, STRAWBERRY})
public @interface Flavour {
}
@Flavour
public int getFlavour() {
return flavour;
}
public void setFlavour(@Flavour int flavour) {
this.flavour = flavour;
}
}
這時(shí)如果我們使用錯(cuò)誤的整型值調(diào)用IceCreamFlavourManager.setFlavour時(shí),IDE將報(bào)錯(cuò)如下:
IDE甚至?xí)崾疚覀兛梢允褂玫挠行У娜≈担?/p>
我們也可以指定整型值作為標(biāo)志位名秀,也就是說這些整型值可以使用’|’或者’&’進(jìn)行與或等操作励负。如果我們把@Flavour定義為如下標(biāo)志位:
@IntDef(flag = true, value = {VANILLA, CHOCOLATE, STRAWBERRY})
public @interface Flavour {
}
那么可以如下調(diào)用:
iceCreamFlavourManager.setFlavour(IceCreamFlavourManager.VANILLA & IceCreamFlavourManager
.CHOCOLATE);
StringDef用法和@IntDef基本差不多,只不過是針對(duì)String類型而已匕得。