標籤:android c style class blog code
轉自:http://www.2cto.com/kf/201405/302998.html
這篇文章主要講解註解實現findViewById的功能,首先我們來熟悉一下在java中怎麼定義一個註解和解析一個註解
註解的概念是在jdk5.0中提出來的,在java.lang的包中已經定義了三個註解:Override,Deprecated,SuppressWarnings
Override相信大家非常熟悉,就是表明這個方法是改寫了父類的方法
Deprecated表示在新版本的 jdk中已經不建議使用這個方法或者屬性
SuppressWarning就是屏蔽掉一些警告
知道了註解的概念後,我們就來自訂註解
註解的定義和介面的介面非常像,在interface的前面多了一個@
public @interface TestPerson{ }
千萬不能把前面的@符號弄掉了,弄掉了就成了介面的定義了,上面是一個最簡單註解的定義,當然註解和類一樣,也可以定義屬性,如下:
public @interface TestPerson{ //name既是這個註解的屬性,也是註解的方法,調用name()傳回值就是name String name() default gavin;}
我現在想定義兩個註解,一個註解用來說明某個類的意義,另一個註解用來說明類中的某個方法由誰測試的,便於追究責任,定義如下:
//用來標註某個類是用來幹嘛的public @interface ClassFunction{ String value() default ;} //用來標註類中的方法是被誰測試的public @interface TestPerson{ //name是屬性而不是方法,gavin是它的預設值,在定義的時候可以不用給定預設值 String name() default gavin;}
那麼怎麼限定一個註解是用在類上還是用在方法上?比如Override就是用在方法上的註解,Deprecated是既可以用在方法上面,也可以用在類上面,我們直接看看Override是怎麼實現的吧
@Target(ElementType.METHOD)@Retention(RetentionPolicy.SOURCE)public @interface Override {} @Documented@Retention(RetentionPolicy.RUNTIME)@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})public @interface Deprecated {}
我們發現這兩個註解在已定義流程中都使用了其他的註解,像Target和Retention這種註解叫做元註解,我們分別看看它們的意思吧
Target註解的功能就是表明你這個註解是用在什麼地方的,它的值是一個枚舉型
1.CONSTRUCTOR:用於描述構造器
2.FIELD:用於描述域
3.LOCAL_VARIABLE:用於描述局部變數
4.METHOD:用於描述方法
5.PACKAGE:用於描述包
6.PARAMETER:用於描述參數
7.TYPE:用於描述類、介面(包括註解類型) 或enum聲明
Retention註解的功能差不多說明的就是你的註解的生命週期吧,就是什麼時候失效,它的值如下
1.SOURCE:在源檔案中有效(即源檔案保留)
2.CLASS:在class檔案中有效(即class保留)
3.RUNTIME:在運行時有效(即運行時保留)
我就介紹這兩個元註解吧,其他的感覺也用的不是很多,如果你感興趣可以自己Google一下
那麼我們就完善我們自己的註解吧
@Target(ElementType.METHOD)//作用於方法@Retention(RetentionPolicy.RUNTIME)//在運行時有效(即運行時保留)public @interface TestPerson{ //name是屬性而不是方法,gavin是它的預設值,在定義的時候可以不用給定預設值 String name() default gavin;} @Target(ElementType.TYPE)//作用於類上@Retention(RetentionPolicy.RUNTIME)//在運行時有效(即運行時保留)public @interface ClassFunction{ String value() default ;}
那麼我們就來使用一下我們的註解吧
@ClassFunction(用於描述一個人的基本資料)public class Person{ private static final String TAG = Person; @TestPerson(name=jj) public void setName() { }}
這裡要說明一點就是:如果某個註解屬性使用value作為名稱如ClassFunction中的value,那麼賦值的時候可以直接@ClassFunction(用於描述一個人的基本資料),但是如果你使用的是其他名稱,那麼必須@TestPerson(name=jj)這樣調用
以上就是定義一個註解的過程,下面我們來解析一個註解
定義一個TestPerson註解
/** * com.annotation.TestPerson * @author yuanzeyao * create at 2014年5月21日 下午1:30:14 */@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface TestPerson { String name();}
然後在Person類中加入註解
public class Person { private static final String TAG = Person; @TestPerson(name=gavin) public void getName() { }}
解析註解
public class Main { private static final String TAG = Main; public static void main(String[] args) { Person person=new Person(); //獲得Person對應的Class Class<person> clazz=Person.class; try { //找到getName方法 Method method=clazz.getMethod(getName,null); //判斷是否被TestPerson標註 if(method.isAnnotationPresent(TestPerson.class)) { //調用getName方法 method.invoke(person, null); //得到TestPerson註解的執行個體 TestPerson test=method.getAnnotation(TestPerson.class); //獲得其name屬性 String name=test.name(); System.out.println(this method is test by-->+name); } } catch (SecurityException e) { } catch (NoSuchMethodException e) { } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } catch (InvocationTargetException e) { } }}
已經將定義註解和解析註解講解完了,下面來具體分析一下怎麼在Android中使用註解來代替findViewById
定義一個註解
@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface InjectView { //id就是控制項id,在某一個控制項上使用註解標註其id int id() default -1;}
在Activity中加入註解
public class MainActivity extends Activity { public static final String TAG=MainActivity; //標註TextView的id @InjectView(id=R.id.tv_img) private TextView mText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); try { autoInjectAllField(this); } catch (IllegalAccessException e) { } catch (IllegalArgumentException e) { } if(mText!=null) mText.setText(Hello Gavin); } public void autoInjectAllField(Activity activity) throws IllegalAccessException, IllegalArgumentException { //得到Activity對應的Class Class clazz=this.getClass(); //得到該Activity的所有欄位 Field []fields=clazz.getDeclaredFields(); Log.v(TAG, fields size-->+fields.length); for(Field field :fields) { //判斷欄位是否標註InjectView if(field.isAnnotationPresent(InjectView.class)) { Log.v(TAG, is injectView); //如果標註了,就獲得它的id InjectView inject=field.getAnnotation(InjectView.class); int id=inject.id(); Log.v(TAG, id--->+id); if(id>0) { //反射訪問私人成員,必須加上這句 field.setAccessible(true); //然後對這個屬性複製 field.set(activity, activity.findViewById(id)); } } } } }