日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > Android >内容正文

Android

Android 进阶 教你打造 Android 中的 IOC 框架 【ViewInject】 (下)

發(fā)布時(shí)間:2023/12/15 Android 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android 进阶 教你打造 Android 中的 IOC 框架 【ViewInject】 (下) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

上一篇博客我們已經(jīng)帶大家簡(jiǎn)單的吹了一下IoC,實(shí)現(xiàn)了Activity中View的布局以及控件的注入,如果你不了解,請(qǐng)參考:Android 進(jìn)階 教你打造 Android 中的 IOC 框架 【ViewInject】 (上)。

本篇博客將帶大家實(shí)現(xiàn)View的事件的注入。

1、目標(biāo)效果

上篇博客,我們的事件的代碼是這么寫的:

[java]?view plaincopy
  • package?com.zhy.zhy_xutils_test;??
  • ??
  • import?android.app.Activity;??
  • import?android.os.Bundle;??
  • import?android.view.View;??
  • import?android.view.View.OnClickListener;??
  • import?android.widget.Button;??
  • import?android.widget.Toast;??
  • ??
  • import?com.zhy.ioc.view.ViewInjectUtils;??
  • import?com.zhy.ioc.view.annotation.ContentView;??
  • import?com.zhy.ioc.view.annotation.ViewInject;??
  • ??
  • @ContentView(value?=?R.layout.activity_main)??
  • public?class?MainActivity?extends?Activity?implements?OnClickListener??
  • {??
  • ????@ViewInject(R.id.id_btn)??
  • ????private?Button?mBtn1;??
  • ????@ViewInject(R.id.id_btn02)??
  • ????private?Button?mBtn2;??
  • ??
  • ????@Override??
  • ????protected?void?onCreate(Bundle?savedInstanceState)??
  • ????{??
  • ????????super.onCreate(savedInstanceState);??
  • ??????????
  • ????????ViewInjectUtils.inject(this);??
  • ??
  • ????????mBtn1.setOnClickListener(this);??
  • ????????mBtn2.setOnClickListener(this);??
  • ????}??
  • ??
  • ????@Override??
  • ????public?void?onClick(View?v)??
  • ????{??
  • ????????switch?(v.getId())??
  • ????????{??
  • ????????case?R.id.id_btn:??
  • ????????????Toast.makeText(MainActivity.this,?"Why?do?you?click?me??",??
  • ????????????????????Toast.LENGTH_SHORT).show();??
  • ????????????break;??
  • ??
  • ????????case?R.id.id_btn02:??
  • ????????????Toast.makeText(MainActivity.this,?"I?am?sleeping?!!!",??
  • ????????????????????Toast.LENGTH_SHORT).show();??
  • ????????????break;??
  • ????????}??
  • ????}??
  • ??
  • }??

  • 光有View的注入能行么,我們寫View的目的,很多是用來(lái)交互的,得可以點(diǎn)擊神馬的吧。摒棄傳統(tǒng)的神馬,setOnClickListener,然后實(shí)現(xiàn)匿名類或者別的方式神馬的,我們改變?yōu)?#xff1a;

    [java]?view plaincopy
  • package?com.zhy.zhy_xutils_test;??
  • ??
  • import?android.view.View;??
  • import?android.widget.Button;??
  • import?android.widget.Toast;??
  • ??
  • import?com.zhy.ioc.view.annotation.ContentView;??
  • import?com.zhy.ioc.view.annotation.OnClick;??
  • import?com.zhy.ioc.view.annotation.ViewInject;??
  • ??
  • @ContentView(value?=?R.layout.activity_main)??
  • public?class?MainActivity?extends?BaseActivity??
  • {??
  • ????@ViewInject(R.id.id_btn)??
  • ????private?Button?mBtn1;??
  • ????@ViewInject(R.id.id_btn02)??
  • ????private?Button?mBtn2;??
  • ??
  • ????@OnClick({?R.id.id_btn,?R.id.id_btn02?})??
  • ????public?void?clickBtnInvoked(View?view)??
  • ????{??
  • ????????switch?(view.getId())??
  • ????????{??
  • ????????case?R.id.id_btn:??
  • ????????????Toast.makeText(this,?"Inject?Btn01?!",?Toast.LENGTH_SHORT).show();??
  • ????????????break;??
  • ????????case?R.id.id_btn02:??
  • ????????????Toast.makeText(this,?"Inject?Btn02?!",?Toast.LENGTH_SHORT).show();??
  • ????????????break;??
  • ????????}??
  • ????}??
  • ??
  • }??

  • 直接通過(guò)在Activity中的任何一個(gè)方法上,添加注解,完成1個(gè)或多個(gè)控件的事件的注入。這里我把onCreate搬到了BaseActivity中,里面調(diào)用了ViewInjectUtils.inject(this);

    2、實(shí)現(xiàn)

    1、注解文件

    [java]?view plaincopy
  • package?com.zhy.ioc.view.annotation;??
  • ??
  • import?java.lang.annotation.ElementType;??
  • import?java.lang.annotation.Retention;??
  • import?java.lang.annotation.RetentionPolicy;??
  • import?java.lang.annotation.Target;??
  • ??
  • @Target(ElementType.ANNOTATION_TYPE)??
  • @Retention(RetentionPolicy.RUNTIME)??
  • public?@interface?EventBase??
  • {??
  • ????Class<?>?listenerType();??
  • ??
  • ????String?listenerSetter();??
  • ??
  • ????String?methodName();??
  • }??

  • [java]?view plaincopy
  • package?com.zhy.ioc.view.annotation;??
  • ??
  • import?java.lang.annotation.ElementType;??
  • import?java.lang.annotation.Retention;??
  • import?java.lang.annotation.RetentionPolicy;??
  • import?java.lang.annotation.Target;??
  • ??
  • import?android.view.View;??
  • ??
  • @Target(ElementType.METHOD)??
  • @Retention(RetentionPolicy.RUNTIME)??
  • @EventBase(listenerType?=?View.OnClickListener.class,?listenerSetter?=?"setOnClickListener",?methodName?=?"onClick")??
  • public?@interface?OnClick??
  • {??
  • ????int[]?value();??
  • }??

  • EventBase主要用于給OnClick這類注解上添加注解,畢竟事件很多,并且設(shè)置監(jiān)聽(tīng)器的名稱,監(jiān)聽(tīng)器的類型,調(diào)用的方法名都是固定的,對(duì)應(yīng)上面代碼的:

    listenerType = View.OnClickListener.class, listenerSetter = "setOnClickListener", methodName = "onClick"

    Onclick是用于寫在Activity的某個(gè)方法上的:

    [java]?view plaincopy
  • @OnClick({?R.id.id_btn,?R.id.id_btn02?})??
  • ????public?void?clickBtnInvoked(View?view)??

  • 如果你還記得,上篇博客我們的ViewInjectUtils.inject(this);里面已經(jīng)有了兩個(gè)方法,本篇多了一個(gè):

    [java]?view plaincopy
  • public?static?void?inject(Activity?activity)??
  • ????{??
  • ????????injectContentView(activity);??
  • ????????injectViews(activity);??
  • ????????injectEvents(activity);??
  • ????}??

  • 2、injectEvents

    [java]?view plaincopy
  • /**?
  • ?????*?注入所有的事件?
  • ?????*??
  • ?????*?@param?activity?
  • ?????*/??
  • ????private?static?void?injectEvents(Activity?activity)??
  • ????{??
  • ??????????
  • ????????Class<??extends?Activity>?clazz?=?activity.getClass();??
  • ????????Method[]?methods?=?clazz.getMethods();??
  • ????????//遍歷所有的方法??
  • ????????for?(Method?method?:?methods)??
  • ????????{??
  • ????????????Annotation[]?annotations?=?method.getAnnotations();??
  • ????????????//拿到方法上的所有的注解??
  • ????????????for?(Annotation?annotation?:?annotations)??
  • ????????????{??
  • ????????????????Class<??extends?Annotation>?annotationType?=?annotation??
  • ????????????????????????.annotationType();??
  • ????????????????//拿到注解上的注解??
  • ????????????????EventBase?eventBaseAnnotation?=?annotationType??
  • ????????????????????????.getAnnotation(EventBase.class);??
  • ????????????????//如果設(shè)置為EventBase??
  • ????????????????if?(eventBaseAnnotation?!=?null)??
  • ????????????????{??
  • ????????????????????//取出設(shè)置監(jiān)聽(tīng)器的名稱,監(jiān)聽(tīng)器的類型,調(diào)用的方法名??
  • ????????????????????String?listenerSetter?=?eventBaseAnnotation??
  • ????????????????????????????.listenerSetter();??
  • ????????????????????Class<?>?listenerType?=?eventBaseAnnotation.listenerType();??
  • ????????????????????String?methodName?=?eventBaseAnnotation.methodName();??
  • ??
  • ????????????????????try??
  • ????????????????????{??
  • ????????????????????????//拿到Onclick注解中的value方法??
  • ????????????????????????Method?aMethod?=?annotationType??
  • ????????????????????????????????.getDeclaredMethod("value");??
  • ????????????????????????//取出所有的viewId??
  • ????????????????????????int[]?viewIds?=?(int[])?aMethod??
  • ????????????????????????????????.invoke(annotation,?null);??
  • ????????????????????????//通過(guò)InvocationHandler設(shè)置代理??
  • ????????????????????????DynamicHandler?handler?=?new?DynamicHandler(activity);??
  • ????????????????????????handler.addMethod(methodName,?method);??
  • ????????????????????????Object?listener?=?Proxy.newProxyInstance(??
  • ????????????????????????????????listenerType.getClassLoader(),??
  • ????????????????????????????????new?Class<?>[]?{?listenerType?},?handler);??
  • ????????????????????????//遍歷所有的View,設(shè)置事件??
  • ????????????????????????for?(int?viewId?:?viewIds)??
  • ????????????????????????{??
  • ????????????????????????????View?view?=?activity.findViewById(viewId);??
  • ????????????????????????????Method?setEventListenerMethod?=?view.getClass()??
  • ????????????????????????????????????.getMethod(listenerSetter,?listenerType);??
  • ????????????????????????????setEventListenerMethod.invoke(view,?listener);??
  • ????????????????????????}??
  • ??
  • ????????????????????}?catch?(Exception?e)??
  • ????????????????????{??
  • ????????????????????????e.printStackTrace();??
  • ????????????????????}??
  • ????????????????}??
  • ??
  • ????????????}??
  • ????????}??
  • ??
  • ????}??

  • 嗯,注釋盡可能的詳細(xì)了,主要就是遍歷所有的方法,拿到該方法省的OnClick注解,然后再拿到該注解上的EventBase注解,得到事件監(jiān)聽(tīng)的需要調(diào)用的方法名,類型,和需要調(diào)用的方法的名稱;通過(guò)Proxy和InvocationHandler得到監(jiān)聽(tīng)器的代理對(duì)象,顯示設(shè)置了方法,最后通過(guò)反射設(shè)置監(jiān)聽(tīng)器。

    這里有個(gè)難點(diǎn),就是關(guān)于DynamicHandler和Proxy的出現(xiàn),如果不理解沒(méi)事,后面會(huì)詳細(xì)講解。

    3、DynamicHandler

    這里用到了一個(gè)類DynamicHandler,就是InvocationHandler的實(shí)現(xiàn)類:

    [java]?view plaincopy
  • package?com.zhy.ioc.view;??
  • ??
  • import?java.lang.ref.WeakReference;??
  • import?java.lang.reflect.InvocationHandler;??
  • import?java.lang.reflect.Method;??
  • import?java.util.HashMap;??
  • ??
  • public?class?DynamicHandler?implements?InvocationHandler??
  • {??
  • ????private?WeakReference<Object>?handlerRef;??
  • ????private?final?HashMap<String,?Method>?methodMap?=?new?HashMap<String,?Method>(??
  • ????????????1);??
  • ??
  • ????public?DynamicHandler(Object?handler)??
  • ????{??
  • ????????this.handlerRef?=?new?WeakReference<Object>(handler);??
  • ????}??
  • ??
  • ????public?void?addMethod(String?name,?Method?method)??
  • ????{??
  • ????????methodMap.put(name,?method);??
  • ????}??
  • ??
  • ????public?Object?getHandler()??
  • ????{??
  • ????????return?handlerRef.get();??
  • ????}??
  • ??
  • ????public?void?setHandler(Object?handler)??
  • ????{??
  • ????????this.handlerRef?=?new?WeakReference<Object>(handler);??
  • ????}??
  • ??
  • ????@Override??
  • ????public?Object?invoke(Object?proxy,?Method?method,?Object[]?args)??
  • ????????????throws?Throwable??
  • ????{??
  • ????????Object?handler?=?handlerRef.get();??
  • ????????if?(handler?!=?null)??
  • ????????{??
  • ????????????String?methodName?=?method.getName();??
  • ????????????method?=?methodMap.get(methodName);??
  • ????????????if?(method?!=?null)??
  • ????????????{??
  • ????????????????return?method.invoke(handler,?args);??
  • ????????????}??
  • ????????}??
  • ????????return?null;??
  • ????}??
  • }??
  • 好了,代碼就這么多,這樣我們就實(shí)現(xiàn)了,我們事件的注入~~

    效果圖:


    效果圖其實(shí)沒(méi)撒好貼的,都一樣~~~

    3、關(guān)于代理

    那么,本文結(jié)束了么,沒(méi)有~~~關(guān)于以下幾行代碼,相信大家肯定有困惑,這幾行干了什么?

    [java]?view plaincopy
  • //通過(guò)InvocationHandler設(shè)置代理??
  • ????????????????????????DynamicHandler?handler?=?new?DynamicHandler(activity);??
  • ????????????????????????handler.addMethod(methodName,?method);??
  • ????????????????????????Object?listener?=?Proxy.newProxyInstance(??
  • ????????????????????????????????listenerType.getClassLoader(),??
  • ????????????????????????????????new?Class<?>[]?{?listenerType?},?handler);??

  • InvocationHandler和Proxy成對(duì)出現(xiàn),相信大家如果對(duì)Java比較熟悉,肯定會(huì)想到Java的動(dòng)態(tài)代理~~~

    關(guān)于InvocationHandler和Proxy的文章,大家可以參考:http://www.ibm.com/developerworks/cn/java/j-lo-proxy1/?ps:IBM的技術(shù)文章還是相當(dāng)不錯(cuò)的,畢竟有人審核還有獎(jiǎng)金~

    但是我們的實(shí)現(xiàn)有一定的區(qū)別,我為什么說(shuō)大家疑惑呢,比如反射實(shí)現(xiàn):

    mBtn2.setOnClickListener(this);這樣的代碼,難點(diǎn)在哪呢?

    1、mBtn2的獲取?so easy?

    2、調(diào)用setOnClickListener ? so easy?

    but , 這個(gè) this,這個(gè)this是OnClickListener的實(shí)現(xiàn)類的實(shí)例,OnClickListener是個(gè)接口~~你的實(shí)現(xiàn)類怎么整,聽(tīng)說(shuō)過(guò)反射newInstance對(duì)象的,但是你現(xiàn)在是接口!

    是吧~現(xiàn)在應(yīng)該明白上述幾行代碼做了什么了?實(shí)現(xiàn)了接口的一個(gè)代理對(duì)象,然后在代理類的invoke中,對(duì)接口的調(diào)用方法進(jìn)行處理。

    4、代碼是最好的老師

    光說(shuō)誰(shuí)都理解不了,你在這xx什么呢??下面看代碼,我們模擬實(shí)現(xiàn)這樣一個(gè)情景:

    Main類中實(shí)現(xiàn)一個(gè)Button,Button有兩個(gè)方法,一個(gè)setOnClickListener和onClick,當(dāng)調(diào)用Button的onClick時(shí),觸發(fā)的事件是Main類中的click方法

    涉及到4個(gè)類:

    Button

    [java]?view plaincopy
  • package?com.zhy.invocationhandler;??
  • ??
  • public?class?Button??
  • {??
  • ????private?OnClickListener?listener;??
  • ??
  • ????public?void?setOnClickLisntener(OnClickListener?listener)??
  • ????{??
  • ??
  • ????????this.listener?=?listener;??
  • ????}??
  • ??
  • ????public?void?click()??
  • ????{??
  • ????????if?(listener?!=?null)??
  • ????????{??
  • ????????????listener.onClick();??
  • ????????}??
  • ????}??
  • }??

  • OnClickListener接口

    [java]?view plaincopy
  • package?com.zhy.invocationhandler;??
  • ??
  • public?interface?OnClickListener??
  • {??
  • ????void?onClick();??
  • }??

  • OnClickListenerHandler , InvocationHandler的實(shí)現(xiàn)類

    [java]?view plaincopy
  • package?com.zhy.invocationhandler;??
  • ??
  • import?java.lang.reflect.InvocationHandler;??
  • import?java.lang.reflect.Method;??
  • import?java.util.HashMap;??
  • import?java.util.Map;??
  • ??
  • public?class?OnClickListenerHandler?implements?InvocationHandler??
  • {??
  • ????private?Object?targetObject;??
  • ??
  • ????public?OnClickListenerHandler(Object?object)??
  • ????{??
  • ????????this.targetObject?=?object;??
  • ????}??
  • ??
  • ????private?Map<String,?Method>?methods?=?new?HashMap<String,?Method>();??
  • ??
  • ????public?void?addMethod(String?methodName,?Method?method)??
  • ????{??
  • ????????methods.put(methodName,?method);??
  • ????}??
  • ??
  • ????@Override??
  • ????public?Object?invoke(Object?proxy,?Method?method,?Object[]?args)??
  • ????????????throws?Throwable??
  • ????{??
  • ??
  • ????????String?methodName?=?method.getName();??
  • ????????Method?realMethod?=?methods.get(methodName);??
  • ????????return?realMethod.invoke(targetObject,?args);??
  • ????}??
  • ??
  • }??

  • 我們的Main

    [java]?view plaincopy
  • package?com.zhy.invocationhandler;??
  • ??
  • import?java.lang.reflect.InvocationTargetException;??
  • import?java.lang.reflect.Method;??
  • import?java.lang.reflect.Proxy;??
  • ??
  • public?class?Main??
  • {??
  • ????private?Button?button?=?new?Button();??
  • ??????
  • ????public?Main()?throws?SecurityException,?IllegalArgumentException,?NoSuchMethodException,?IllegalAccessException,?InvocationTargetException??
  • ????{??
  • ????????init();??
  • ????}??
  • ??
  • ????public?void?click()??
  • ????{??
  • ????????System.out.println("Button?clicked!");??
  • ????}??
  • ??
  • ????public?void?init()?throws?SecurityException,??
  • ????????????NoSuchMethodException,?IllegalArgumentException,??
  • ????????????IllegalAccessException,?InvocationTargetException??
  • ????{??
  • ????????OnClickListenerHandler?h?=?new?OnClickListenerHandler(this);??
  • ????????Method?method?=?Main.class.getMethod("click",?null);??
  • ????????h.addMethod("onClick",?method);??
  • ????????Object?clickProxy?=?Proxy.newProxyInstance(??
  • ????????????????OnClickListener.class.getClassLoader(),??
  • ????????????????new?Class<?>[]?{?OnClickListener.class?},?h);??
  • ????????Method?clickMethod?=?button.getClass().getMethod("setOnClickLisntener",??
  • ????????????????OnClickListener.class);??
  • ????????clickMethod.invoke(button,?clickProxy);??
  • ??????????
  • ????}??
  • ??
  • ????public?static?void?main(String[]?args)?throws?SecurityException,??
  • ????????????IllegalArgumentException,?NoSuchMethodException,??
  • ????????????IllegalAccessException,?InvocationTargetException??
  • ????{??
  • ??
  • ????????Main?main?=?new?Main();??
  • ??????????
  • ????????main.button.click();??
  • ????}??
  • ??
  • }??

  • 我們模擬按鈕點(diǎn)擊:調(diào)用main.button.click(),實(shí)際執(zhí)行的卻是Main的click方法。

    看init中,我們首先初始化了一個(gè)OnClickListenerHandler,把Main的當(dāng)前實(shí)例傳入,然后拿到Main的click方法,添加到OnClickListenerHandler中的Map中。

    然后通過(guò)Proxy.newProxyInstance拿到OnClickListener這個(gè)接口的一個(gè)代理,這樣執(zhí)行這個(gè)接口的所有的方法,都會(huì)去調(diào)用OnClickListenerHandler的invoke方法。

    但是呢?OnClickListener畢竟是個(gè)接口,也沒(méi)有方法體~~那咋辦呢?這時(shí)候就到我們OnClickListenerHandler中的Map中大展伸手了:

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
    throws Throwable
    {

    String methodName = method.getName();
    Method realMethod = methods.get(methodName);
    return realMethod.invoke(targetObject, args);
    }

    我們顯示的把要執(zhí)行的方法,通過(guò)鍵值對(duì)存到Map里面了,等調(diào)用到invoke的時(shí)候,其實(shí)是通過(guò)傳入的方法名,得到Map中存儲(chǔ)的方法,然后調(diào)用我們預(yù)設(shè)的方法~。

    這樣,大家應(yīng)該明白了,其實(shí)就是通過(guò)Proxy得到接口的一個(gè)代理,然后在InvocationHandler中使用一個(gè)Map預(yù)先設(shè)置方法,從而實(shí)現(xiàn)Button的onClick,和Main的click關(guān)聯(lián)上。

    現(xiàn)在看我們InjectEvents中的代碼:

    [java]?view plaincopy
  • //通過(guò)InvocationHandler設(shè)置代理??
  • ????????????????????????DynamicHandler?handler?=?new?DynamicHandler(activity);??
  • ????????????????????????//往map添加方法??
  • ????????????????????????handler.addMethod(methodName,?method);??
  • ????????????????????????Object?listener?=?Proxy.newProxyInstance(??
  • ????????????????????????????????listenerType.getClassLoader(),??
  • ????????????????????????????????new?Class<?>[]?{?listenerType?},?handler);??

  • 是不是和我們init中的類似~~

    好了,關(guān)于如何把接口的回調(diào)和我們Activity里面的方法關(guān)聯(lián)上我們也解釋完了~~~


    注:部分代碼參考了xUtils這個(gè)框架,畢竟想很完善的實(shí)現(xiàn)一個(gè)完整的注入不是一兩篇博客就可以搞定,但是核心和骨架已經(jīng)實(shí)現(xiàn)了~~大家有興趣的可以繼續(xù)去完善~




    源碼點(diǎn)擊下載


    總結(jié)

    以上是生活随笔為你收集整理的Android 进阶 教你打造 Android 中的 IOC 框架 【ViewInject】 (下)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。