在這邊文章以前你首先須要對java 的註解部分有一個基本的瞭解(不須要太過的深刻)。html
簡單來講,註解這個東西就是用於輔助咱們開發java代碼的,註解自己沒法干擾java源代碼的執行。java
在android 裏面 註解主要用來幹這麼幾件事:android
1.和編譯器一塊兒給你一些提示警告信息。spring
2.配合一些ide 能夠更加方便快捷 安全有效的編寫java代碼。谷歌出的support-annotations這個庫 就是主要幹這個的。express
3.和反射一塊兒 提供一些相似於spring 可配置的功能,方便簡潔(這部分有過j2ee 開發經驗的能夠直接跳過了)。安全
首先來看一下官方提供的庫吧。首先在build文件裏 增長一句話app
compile 'com.android.support:support-annotations:22.2.0'
這個地方要注意,我如今是取得version22.2的版本,大家引用的時候若是有更新,android studio可能會提示你sync失敗,這個時候你要本身去谷歌官網查詢一下最新的版本號本身替換。less
而後咱們就能夠看看這個谷歌的註解庫 爲咱們提供了哪些功能。ide
http://tools.android.com/tech-docs/support-annotations 這個是官方的文檔 我也是主要根據這個來說解這個庫的使用。函數
首先來看 Nullness 註解 這個主要是有兩種@Nullable 和 @NonNull。
前者表示能夠爲空 後者表示不能爲空。
我只演示後者(前者能夠本身測試)定義一個函數
而後咱們去調用他 看看。
1 String a=null; 2 sayHello(a);
這個時候IDE就自動會給咱們警告信息了(其實ide 的警告信息多數也是從編譯器而來)
1 Argument 'a' might be null less... (Ctrl+F1) 2 This inspection analyzes method control and data flow to report possible conditions that are always true or false, expressions whose value is statically proven to be constant, and situations that can lead to nullability contract violations. 3 Variables, method parameters and return values marked as @Nullable or @NotNull are treated as nullable (or not-null, respectively) and used during the analysis to check nullability contracts, e.g. report possible NullPointerException errors. 4 More complex contracts can be defined using @Contract annotation, for example: 5 @Contract("_, null -> null") — method returns null if its second argument is null @Contract("_, null -> null; _, !null -> !null") — method returns null if its second argument is null and not-null otherwise @Contract("true -> fail") — a typical assertFalse method which throws an exception if true is passed to it 6 The inspection can be configured to use custom @Nullable 7 @NotNull annotations (by default the ones from annotations.jar will be used)
再介紹一下
定義一個方法
1 private String sayHello(@StringRes int resId) { 2 return ""; 3 }
而後調用
1 sayHello(R.layout.activity_main);
這個地方這個註解的意思是你只能傳string 類型的id進去 而咱們傳了layout類型的,若是你不加那個註解的話 ide和編譯器是沒有反應的,到運行期纔會有錯誤。
可是你加了之後就會發現
IDE也是直接報錯的!
再好比這樣一段代碼
1 class TestAnoataion { 2 3 public void testAnoation() { 4 Log.v("main", "test anoation"); 5 } 6 } 7 8 class TestAnoataion2 extends TestAnoataion 9 { 10 public void testAnoation() 11 { 12 13 } 14 }
假使咱們父類的設計的時候本意是 若是你要重寫testAnoation這個方法必定得調用父類的testAnation這個方法。就跟咱們activity的oncreate方法同樣。
哪若是子類沒有寫super.testAnoation的話 你根本就不知道 就很容易報錯。可是若是你加了註解。那麼ide就會很明確的提示你錯誤
是否是很強大?當你調用了super語句之後 一切就和諧了!
那這個support庫 就暫時介紹到這裏,我的建議你們有時間必定要本身過一遍一個官方文檔。
這裏定義的註解 對提升你們的代碼質量 會很是很是有幫助。必定要掌握學會。
最後再上一個小例子吧,不少android 開發者都喜歡依賴注入的一些開源庫,來綁定你的控件id。
這樣寫法不但優雅並且好用。
這個開源庫你們必定不少人都用過,我就寫一個小demo 來演示一下這些庫的原理,其實還蠻簡單的。
須要注意的是 要理解這個小demo 須要你除了知道註解的基礎知識之外還須要有反射的基礎知識。
關於反射我好久以前也寫過一個教程
http://www.cnblogs.com/punkisnotdead/p/3384464.html
不會的能夠趕忙補一下。
首先定義一個InjectView註解
1 package com.example.administrator.testfab; 2 3 import java.lang.annotation.ElementType; 4 import java.lang.annotation.Retention; 5 import java.lang.annotation.RetentionPolicy; 6 import java.lang.annotation.Target; 7 8 /** 9 * Created by Administrator on 2015/8/5. 10 */ 11 12 @Target(ElementType.FIELD) 13 @Retention(RetentionPolicy.RUNTIME) 14 public @interface InjectView { 15 //id就表示哪些控件,-1就表示取不到時候的默認值 16 int id() default -1; 17 }
而後定義一個解釋器
1 package com.example.administrator.testfab; 2 3 import android.app.Activity; 4 import android.view.View; 5 6 import java.lang.reflect.Field; 7 8 /** 9 * Created by Administrator on 2015/8/5. 10 */ 11 public class InjectViewParser { 12 13 public static void inject(Object object) { 14 15 try { 16 parse(object); 17 } catch (Exception e) { 18 e.printStackTrace(); 19 } 20 } 21 22 public static void parse(Object object) throws Exception { 23 final Class<?> clazz = object.getClass(); 24 View view = null; 25 Field[] fields = clazz.getDeclaredFields(); 26 for (Field field : fields) { 27 if (field.isAnnotationPresent(InjectView.class)) { 28 InjectView injectView = field.getAnnotation(InjectView.class); 29 int id = injectView.id(); 30 if (id < 0) { 31 throw new Exception("id must not be null"); 32 } else { 33 field.setAccessible(true); 34 if (object instanceof View) { 35 view = ((View) object).findViewById(id); 36 } else if (object instanceof Activity) { 37 view = ((Activity) object).findViewById(id); 38 } 39 field.set(object, view); 40 } 41 42 } 43 44 } 45 46 } 47 }
最後在actity裏使用便可
1 package com.example.administrator.testfab; 2 3 import android.os.AsyncTask; 4 import android.os.Bundle; 5 import android.support.annotation.CallSuper; 6 import android.support.annotation.NonNull; 7 import android.support.annotation.Nullable; 8 import android.support.annotation.StringRes; 9 import android.support.v7.app.AppCompatActivity; 10 import android.util.Log; 11 import android.view.Menu; 12 import android.view.MenuItem; 13 import android.widget.Button; 14 15 public class MainActivity extends AppCompatActivity { 16 17 @InjectView(id = R.id.bt) 18 private Button bt; 19 20 21 @Override 22 protected void onCreate(Bundle savedInstanceState) { 23 super.onCreate(savedInstanceState); 24 setContentView(R.layout.activity_main); 25 //開始注入 26 InjectViewParser.inject(this); 27 //這個主要是測試注入id 成功沒有 成功了就不會報錯~ 28 bt.setText("inject done"); 29 30 31 } 32 33 34 @Override 35 public boolean onCreateOptionsMenu(Menu menu) { 36 // Inflate the menu; this adds items to the action bar if it is present. 37 getMenuInflater().inflate(R.menu.menu_main, menu); 38 return true; 39 } 40 41 @Override 42 public boolean onOptionsItemSelected(MenuItem item) { 43 // Handle action bar item clicks here. The action bar will 44 // automatically handle clicks on the Home/Up button, so long 45 // as you specify a parent activity in AndroidManifest.xml. 46 int id = item.getItemId(); 47 48 //noinspection SimplifiableIfStatement 49 if (id == R.id.action_settings) { 50 return true; 51 } 52 53 return super.onOptionsItemSelected(item); 54 } 55 56 57 58 }