Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android中通過注解代替findViewById方法

Android中通過注解代替findViewById方法

編輯:關於Android編程

 

這篇文章主要講解注解實現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 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));
        }
      }
    }
  }



}

好了,就寫到這裡吧,歡迎留言討論

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved