編輯:關於android開發
一般我們在寫android Activity的時候總是會在onCreate方法中加上setContentView方法來加載layout,通過findViewById來實現控件的綁定,每次寫這麼多代碼總覺得很煩躁。近來看了下android中有Annotation來實現這方面的簡化,對於java不是很了解,就簡單的看了下。上次玩web的時候,springmvc也有很多的注解,不知道怎麼實現的,這裡其實基本上類似。
Annotation注解這裡主要還是講講怎麼使用吧,單純的原理會把人繞進去的,沒辦法,java基礎只能後面再補了,c搞久了,很多面向對象的思想只停留在大學的時候,除了linux內核的一些面向對象的思想。說了那麼多的廢話,接著繼續我們的Annotation的學習吧,先新建工程emAnnotationStudy,新建EMLayoutBinder.java,代碼如下:
package com.jared.emannotationstudy; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Created by jared on 16/3/10. */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface EMLayoutBinder { int value(); }這裡的@Target,@Retention和@interface,先來簡單的介紹下這幾個內容吧。
@Target:說明了Annotation修飾的對象范圍,Annotation可被用於packages、types等類,接口,枚舉,Annotation類型;還可以是類成員方法,構造方法,成員變量,枚舉值;方法參數和本地變量等。其一般有如下幾種類型:
ElementType.CONSTRUCTOR: 構造器聲明;
ElementType.FIELD: 成員變量、對象、屬性;
ElementType.LOCAL_VARIABLE: 局部變量聲明;
ElementType.METHOD: 方法聲明;
ElementType.PACKAGE: 包聲明;
ElementType.PARAMETER: 參數聲明;
ElementType.TYPE: 類、接口(包括注解類型)或enum聲明;
這用到了TYPE。
@Retention:表示在什麼級別保存該注解信息。其一般級別如下:
RetentionPolicy.SOURCE: 停留在java源文件,編譯器被丟掉。
RetentionPolicy.CLASS: 停留在class文件中,但會被VM丟棄。
RetentionPolicy.RUNTIME:內存中的字節碼,VM將在運行時也保留注解,因此可以通過反射機制讀取注解的信息。
這裡給了最高級別RUNTIME。
@interface:這個就表示注解了,和interface很像,不過多了一個@符號。
int value():表示傳入的參數是int類型的。
好了,既然定義好了那麼怎麼使用呢?單單一個注解怎麼個搞搞?其實注解一般都是和java的反射原理一起使用的。還是簡單學習下java的反射吧,網上資料很多,這裡就簡單理解理解了。在java中的反射機制,被稱為Reflection,它允許運行中的java程序對自身進行檢查,並能直接操作程序的內部屬性或方法。
利用Reflection APIs可以獲取任何已知名稱的類的內部信息,包括package、type parameters、superclass、implemented interfaces、inner classes、outer classes、fields constructors、methods、modifiers等。
Class: 表示某個具體的類或接口
Object: 每個類都使用Object 做為超類,所有對象都實現這個類的方法
Constructor:封裝了Class的構造方法
Field: 提供有關類或接口的屬性信息,以及對它的動態訪問權限
Method: 提供類或者接口上的方法的信息
Modifier: 封裝了Class(method、fields)的修飾域。
簡單了解下java的發射機制,其實反射就是通過反向調用類的一些功能,可能會覺得很難理解,還是繼續我們的學習吧,新建EMAnnotationParser類:
package com.jared.emannotationstudy; import android.app.Activity; import android.view.View; import java.lang.reflect.Field; /** * Created by jared on 16/3/10. */ public class EMAnnotationParser { public static void injectActivity(Activity activity) { if (null == activity) { return; } Class activityClass = (Class) activity.getClass(); if (isEMLayoutBinder(activityClass)) { EMLayoutBinder layout = activityClass.getAnnotation(EMLayoutBinder.class); activity.setContentView(layout.value()); } View decorView = activity.getWindow().getDecorView(); } private static boolean isEMLayoutBinder(Class c) { return c.isAnnotationPresent(EMLayoutBinder.class); }
這裡實現了injectActivity的方法,通過getClass獲取當前的Activity的class,然後通過isAnnotationPresent查看該Annotation,再通過getAnnotation獲取該注解,接著就是把注解傳入的那個layout通過activity的setContentView方法來加載到activity 中了。好了,那麼我們來實現下MainActivity吧:
package com.jared.emannotationstudy; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; @EMLayout(R.layout.activity_main) public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); EMAnnotationParser.injectActivity(this); //setContentView(R.layout.activity_main); } }去掉了setContentView,直接一個@EMLayout就搞定了,是不是很方便,這裡通過EMAnnotationParser的injectActivity方法。其實一般項目中會定義一個BaseActivity,MainActivity通過繼承BaseActivity來實現,那樣看上去會更加的清晰,那就實現下BaseActivity吧:
package com.jared.emannotationstudy; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; /** * Created by jared on 16/3/10. */ public class BaseActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); EMAnnotationParser.injectActivity(this); } }然後實現MainActivity繼承BaseActivity:
package com.jared.emannotationstudy; import android.os.Bundle; import android.widget.Button; import android.widget.TextView; @EMLayoutBinder(R.layout.activity_main) public class MainActivity extends BaseActivity { @EMViewBinder(R.id.hello) private TextView mHello; @EMViewBinder(R.id.test1) private Button mTest1; @EMViewBinder(R.id.test2) private Button mTest2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mHello.setText("Hello Annotation!"); } }
運行後依然沒有任何問題。既然layout通過注解了,那麼控件也是可以通過注解的,接下去就去實現下了。首先新建Annotation為EMViewBinder:
package com.jared.emannotationstudy; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Created by jared on 16/3/10. */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface EMViewBinder { int value(); }
package com.jared.emannotationstudy; import android.app.Activity; import android.view.View; import java.lang.reflect.Field; /** * Created by jared on 16/3/10. */ public class EMAnnotationParser { public static void injectActivity(Activity activity) { if (null == activity) { return; } Class activityClass = (Class) activity.getClass(); if (isEMLayoutBinder(activityClass)) { EMLayoutBinder layout = activityClass.getAnnotation(EMLayoutBinder.class); activity.setContentView(layout.value()); } View decorView = activity.getWindow().getDecorView(); initViews(activityClass.getDeclaredFields(), decorView, activity); } private static boolean isEMLayoutBinder(Class c) { return c.isAnnotationPresent(EMLayoutBinder.class); } private static boolean isEMViewBinder(Field filed) { return filed.isAnnotationPresent(EMViewBinder.class); } private static void initViews(Field[] fields, View view, Object object) { View view1; for (Field field : fields) { if(isEMViewBinder(field)) { EMViewBinder emView = field.getAnnotation(EMViewBinder.class); view1 = view.findViewById(emView.value()); if(null != view1) { try { field.setAccessible(true); field.set(object, view1); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } } } } } }
<!--{cke_protected}{C}%3C!%2D%2D%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%2D%2D%3E--> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:layout_margin="10dp" tools:context="com.jared.emannotationstudy.MainActivity"> <textview android:id="@+id/hello" android:text="Hello World!" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textsize="20sp" android:layout_gravity="center"><button android:id="@+id/test1" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test1" android:textallcaps="false"></button><button android:id="@+id/test2" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="test2" android:textallcaps="false"></button></textview></linearlayout>接著我們在MainActivity中添加代碼如下:
package com.jared.emannotationstudy; import android.os.Bundle; import android.widget.Button; import android.widget.TextView; @EMLayoutBinder(R.layout.activity_main) public class MainActivity extends BaseActivity { @EMViewBinder(R.id.hello) private TextView mHello; @EMViewBinder(R.id.test1) private Button mTest1; @EMViewBinder(R.id.test2) private Button mTest2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mHello.setText("Hello Annotation!"); } }運行看下效果如下:
完全達到了我們的預期,而且編寫代碼十分方便,不需要再引入一大堆的findViewById了。即使再添加更多的控件也輕松搞定。既然控件綁定好了,那麼接下去還需要做的就是事件的綁定了。這裡主要實現button的事件,新建EMOnClickBinder:
package com.jared.emannotationstudy; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Created by jared on 16/3/10. */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface EMOnClickBinder { int[] value(); }這裡實現的是方法,所以使用了METHOD,而且button可能很多,所以用了int[] 數組。接著我們實現具體的反射:
private static boolean isEMOnClickBinder(Method method) { return method.isAnnotationPresent(EMOnClickBinder.class); } private static void initOnClick(Method[] allMethod, View root, Object object) { for (Method method : allMethod) { if (isEMOnClickBinder(method)) { EMOnClickBinder onClick = method.getAnnotation(EMOnClickBinder.class); MyOnClickListener click = new MyOnClickListener(method, object); int[] ids = onClick.value(); for (int id : ids) { root.findViewById(id).setOnClickListener(click); } } } } static class MyOnClickListener implements View.OnClickListener { private Method mMethod; private Object mReceiver; public MyOnClickListener(Method method, Object receiver) { mMethod = method; mReceiver = receiver; } @Override public void onClick(View v) { try { mMethod.setAccessible(true); mMethod.invoke(mReceiver, v); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }這裡使用ID查找,調用setOnClickListener方法來注冊方法,通過MyOnClickListener來實現具體的操作。當有事件觸發的時候會調用onClick方法,進而調用method的invoke方法。就會調用到注解下的自定義方法了,這裡傳入的就是View。接著具體MainActivity的實現如下:
package com.jared.emannotationstudy; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView; @EMLayoutBinder(R.layout.activity_main) public class MainActivity extends BaseActivity { @EMViewBinder(R.id.hello) private TextView mHello; @EMViewBinder(R.id.test1) private Button mTest1; @EMViewBinder(R.id.test2) private Button mTest2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mHello.setText("Hello Annotation!"); } @EMOnClickBinder({R.id.test1, R.id.test2}) public void myOnClick(View view) { switch (view.getId()) { case R.id.test1: mHello.setText("I am test1"); break; case R.id.test2: mHello.setText("I am test2"); default: break; } } }是不是非常的簡單清晰,以後把這幾個文件當作工具,簡單封裝下,就可以不用每次寫那麼多的findViewById和setOnClickListener了。基本上Annotation就先學習到這裡了。
Android_LIFE幫(基於最新百度地圖API的開源項目) 越來越多的APP用到了地圖API,所以本人依賴百度地圖提供的API做了一個簡單的項目,希望大家多多支持和s
將學校擺在桌面上-實時更新校內數據的Android桌面部件,校內android項目地址: https://github.com/hwding/AeolosXDUWidge
由於Android模擬器是Android開發的必備工具,所以在我們開始Andr
《Android源碼設計模式解析與實戰》讀書筆記(十九) 第十九章、組合模式 組合模式也稱為部分-整體模式,結構型設計模式之一。 1.定義 將對象組合成樹形結構以表