標籤:
Java的所有架構基本都是基於反射的,所以有句話是這麼說的,無反射,無架構。所以Android的注入架構也是基於反射的,接下來就簡單的介紹一下Android的注入架構你應該知道的一切。
註解簡介
註解(Annotation)在Java裡面是比較重要的一部分,但是通常很少接觸到這一部分,這裡就簡單的過一下。現在我們簡單的寫一個註解然後解釋它。
通過Eclipse右鍵->New->Annotation然後敲入下面的代碼。
@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interfaceTestAnnotation{int vauls();String test();}可以看到Target這個標註我們定義為FIELD就是類裡面的屬性的意思,Retention這個標註是表示是運行時的註解。每個註解的意思大家可以收一下自己看看。然後看看我們怎麼使用這個註解。我們隨便在某一個類裡面聲明一個對象。如下
@TestAnnotation(test="hello",vauls=12)private Button button3;
這樣就聲明好了我們的註解。然後就是註解的使用。也簡單的看一下怎麼使用的。
Class<?> clas = getClass();//擷取屬性Field fields[] = clas.getDeclaredFields();for(Field field : fields){ //擷取註解 TestAnnotation testAnnotation = field.getAnnotation(TestAnnotation.class); if(testAnnotation != null) { //得到註解裡面的值 String test = testAnnotation.test(); int id = testAnnotation.vauls(); System.out.println(test + id); }}
就這樣簡單的使用,如果需要深入的理解註解可以在查一下註解的資料。
關於注入架構你應該知道的一切
打造自己的注入架構
首先說一下我們這次要實現怎麼樣的一個東西,注入View和注入Onclick事件,首先我們先解決注入View的問題.
View的注入
首先我們還是建立一個註解,敲入以下代碼。
package com.edsheng.inject;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/**** Copyright (c) 2015, TNT All Rights Reserved.* View註解在聲明VIew控制項的時候進行註解就行了* @author bobo* @date 2015-6-9* @filename ViewInject.java**/@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interfaceViewInject { int value();}
然後我們在建立一個ViewInjectUtile類,在裡面實現這樣的一個方法。
/**** 注入控制項View* 簡單說一下注入控制項的流程* 1:根據Filed遍曆所有的Filed* 2:得到我們需要的註解* 3:根據註解拿到id* 4:通過反射去調用找查方法* 5:最後通過反射賦值** @param activity*/private staticvoidinjectView(Activity activity){Class<?> cls = activity.getClass();Field field[] = cls.getDeclaredFields();// 擷取所有的filedfor(Field field2 : field) {ViewInject inject = field2.getAnnotation(ViewInject.class);// 擷取註解if(inject != null) {int id = inject.value(); // 得到idtry { // findViewById Method method = cls.getMethod("findViewById", int.class); Object resView = method.invoke(activity, id);// 得到控制項 field2.setAccessible(true); field2.set(activity, resView);// 賦值給View}catch(Exception e) { e.printStackTrace();}}}}
注釋都寫的很清楚我就不解釋了,這樣就很簡單的實現了View的注入,使用也很簡單。
事件的注入
我們還是建立一個註解來完成我們的事件注入,敲入以下代碼。
/***** Copyright (c) 2015, TNT All Rights Reserved.* 方法的註解類在需要回調OnlickLisenler的時候進行註解就行了** @author bobo* @date 2015-6-9* @filename MethodInject.java**/@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interfaceMethodInject{int[] value();}
然後在ViewInjectUtile這個類裡面實現這樣一個方法。
/*** 注入監聽的方法 所有的架構基本都是基於反射來實現的,不是有一句話嗎?無反射無架構。* 簡單的說一下這個流程* 1:在我們的acitvity裡面注入方法* 2:產生動態代理* 3:通過東動態代理去回調我們注入的方法** @param activity*/private staticvoidinjectMethod(Activity activity){Class<?> cls = activity.getClass();Method methods[] = cls.getMethods();// 擷取這個類的public方法for(Method method : methods) { MethodInject meathdInject = method.getAnnotation(MethodInject.class); // 擷取方法上的註解 if(meathdInject != null) { // 當有註解的時候產生動態代理 Object proxy = (Object) Proxy.newProxyInstance(View.OnClickListener.class.getClassLoader(), newClass<?>[] { View.OnClickListener.class}, newDynaHanlder(activity, method)); int ids[] = meathdInject.value();// 擷取註解裡面的id try { Method findviewbyid = cls.getMethod("findViewById", int.class);// 得到方法 for(int id : ids) { Object view = findviewbyid.invoke(activity, id);// 根據方法擷取view Method onclickMethod = view.getClass().getMethod("setOnClickListener", View.OnClickListener.class); onclickMethod.invoke(view, proxy);// 調用setOnClickListener方法回調在動態類裡面 } } catch(Exception e) { e.printStackTrace(); } }}}
這裡需要注意的就是動態類的產生和代理,我們把View.OnClickListener這個的介面通過代理和反射來回調給註解的地方,我們來看看這個DynaHanlder怎麼實現的。
publicstaticclassDynaHanlder implementsInvocationHandler {Object target = null;Method method = null;public DynaHanlder(Object target, Method method) { super(); this.target = target; this.method = method;}/*** 這個函數就是動態註冊的回調方法*/@OverridepublicObject invoke(Object proxy, Method method, Object[] args) throws Throwable { // 這裡調用動注入的方法 return this.method.invoke(target, args);}}
也很簡單就是保持我們的方法的應用當通過代理回調我們的時候我們也通過反射去調用我們的方法。
最後再給外部暴露一個介面方法。
//外部調用介面static public void inject(Activity activity) { injectView(activity); injectMethod(activity);}
public class MainActivity extends Activity { @ViewInject(R.id.button) private Button button; @ViewInject(R.id.button2) private Button button2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.mainactivity); ViewInjectUtile.inject(this); button.setText("fuck"); button2.setText("asdfasdf"); } @MethodInject({ R.id.button, R.id.button2 }) public void onClick(View v) { switch(v.getId()) { case R.id.button: // System.out.println("asdfasdf"); Toast.makeText(this, "R.id.button", 0).show(); break; case R.id.button2: Toast.makeText(this, "R.id.button2", 0).show(); // System.out.println("asdf"); break; default: break; }}
當點擊按鈕會回調我們的方法,注入一開始就幫我們完成了id與控制項的綁定,這就是注入架構主要的精髓了,需要更好更強大的架構還需要自己慢慢完成。
Android注入架構你應該知道的一切——打造自己的注入架構