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

歡迎訪問 生活随笔!

生活随笔

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

Android

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

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

轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/lmj623565791/article/details/39269193,本文出自:【張鴻洋的博客】

1、概述

首先我們來吹吹牛,什么叫IoC,控制反轉(zhuǎn)(Inversion of Control,英文縮寫為IoC),什么意思呢?

就是你一個類里面需要用到很多個成員變量,傳統(tǒng)的寫法,你要用這些成員變量,那么你就new 出來用唄~~

IoC的原則是:NO,我們不要new,這樣耦合度太高;你配置個xml文件,里面標(biāo)明哪個類,里面用了哪些成員變量,等待加載這個類的時候,我?guī)湍阕⑷?#xff08;new)進(jìn)去;

這樣做有什么好處呢?

回答這個問題,剛好可以回答另一個問題,很多人問,項目分層開發(fā)是吧,分為控制層、業(yè)務(wù)層、DAO層神馬的。然后每一層為撒子要一個包放接口,一個包放實(shí)現(xiàn)呢?只要一個實(shí)現(xiàn)包不行么~剛好,如果你了解了IoC,你就知道這些個接口的作用了,上面不是說,你不用new,你只要聲明了成員變量+寫個配置文件,有人幫你new;此時,你在類中,就可以把需要使用到的成員變量都聲明成接口,然后你會發(fā)現(xiàn),當(dāng)實(shí)現(xiàn)類發(fā)生變化的時候,或者切換實(shí)現(xiàn)類,你需要做什么呢?你只要在配置文件里面做個簡單的修改。如果你用的就是實(shí)實(shí)在在的實(shí)現(xiàn)類,現(xiàn)在換實(shí)現(xiàn)類,你需要找到所有聲明這個實(shí)現(xiàn)類的地方,手動修改類名;如果你遇到了一個多變的老大,是吧,呵呵~

當(dāng)然了,很多會覺得,寫個配置文件,臥槽,這多麻煩。于是乎,又出現(xiàn)了另一種方案,得,你閑配置文件麻煩,你用注解吧。你在需要注入的成員變量上面給我加個注解,例如:@Inject,這樣就行了,你總不能說這么個單詞麻煩吧~~

當(dāng)然了,有了配置文件和注解,那么怎么注入呢?其實(shí)就是把字符串類路徑變成類么,當(dāng)然了,反射上場了;話說,很久很久以前,反射很慢啊,嗯,那是很久很久以前,現(xiàn)在已經(jīng)不是太慢了,當(dāng)然了肯定達(dá)不到原生的速度~~無反射,沒有任何框架。

如果你覺得注解,反射神馬的好高級。我說一句:Just Do It ,你會發(fā)現(xiàn)注解就和你寫一個普通JavaBean差不多;反射呢?API就那么幾行,千萬不要被震懾住~

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

得進(jìn)入正題了,Android IOC框架,其實(shí)主要就是幫大家注入所有的控件,布局文件什么的。如果你用過xUtils,afinal類的框架,你肯定不陌生~

注入View

假設(shè):我們一個Activity,里面10來個View。

傳統(tǒng)做法:我們需要先給這個Activity設(shè)置下布局文件,然后在onCreate里面一個一個的findViewById把~

目標(biāo)的做法:Activity類上添加個注解,幫我們自動注入布局文科;聲明View的時候,添加一行注解,然后自動幫我們findViewById;

于是乎我們的目標(biāo)類是這樣的:

[java]?view plaincopy
  • @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;??

  • 3、編碼


    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.TYPE)??
  • @Retention(RetentionPolicy.RUNTIME)??
  • public?@interface?ContentView??
  • {??
  • ????int?value();??
  • }??

  • ContentView用于在類上使用,主要用于標(biāo)明該Activity需要使用的布局文件。

    [java]?view plaincopy
  • @ContentView(value?=?R.layout.activity_main)??
  • public?class?MainActivity??

  • [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.FIELD)??
  • @Retention(RetentionPolicy.RUNTIME)??
  • public?@interface?ViewInject??
  • {??
  • ????int?value();??
  • }??

  • 在成員變量上使用,用于指定View的Id

    [java]?view plaincopy
  • @ViewInject(R.id.id_btn)??
  • ????private?Button?mBtn1;??

  • 簡單說一下注解:定義的關(guān)鍵字@interface ;?@Target表示該注解可以用于什么地方,可能的類型TYPE(類),FIELD(成員變量),可能的類型:

    [java]?view plaincopy
  • public?enum?ElementType?{??
  • ????/**?
  • ?????*?Class,?interface?or?enum?declaration.?
  • ?????*/??
  • ????TYPE,??
  • ????/**?
  • ?????*?Field?declaration.?
  • ?????*/??
  • ????FIELD,??
  • ????/**?
  • ?????*?Method?declaration.?
  • ?????*/??
  • ????METHOD,??
  • ????/**?
  • ?????*?Parameter?declaration.?
  • ?????*/??
  • ????PARAMETER,??
  • ????/**?
  • ?????*?Constructor?declaration.?
  • ?????*/??
  • ????CONSTRUCTOR,??
  • ????/**?
  • ?????*?Local?variable?declaration.?
  • ?????*/??
  • ????LOCAL_VARIABLE,??
  • ????/**?
  • ?????*?Annotation?type?declaration.?
  • ?????*/??
  • ????ANNOTATION_TYPE,??
  • ????/**?
  • ?????*?Package?declaration.?
  • ?????*/??
  • ????PACKAGE??
  • }??

  • 就是這些個枚舉。

    @Retention表示:表示需要在什么級別保存該注解信息;我們這里設(shè)置為運(yùn)行時。

    可能的類型:

    [java]?view plaincopy
  • public?enum?RetentionPolicy?{??
  • ????/**?
  • ?????*?Annotation?is?only?available?in?the?source?code.?
  • ?????*/??
  • ????SOURCE,??
  • ????/**?
  • ?????*?Annotation?is?available?in?the?source?code?and?in?the?class?file,?but?not?
  • ?????*?at?runtime.?This?is?the?default?policy.?
  • ?????*/??
  • ????CLASS,??
  • ????/**?
  • ?????*?Annotation?is?available?in?the?source?code,?the?class?file?and?is?
  • ?????*?available?at?runtime.?
  • ?????*/??
  • ????RUNTIME??
  • }??

  • 這些個枚舉~

    2、MainActivity

    [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;??
  • ????????}??
  • ????}??
  • ??
  • }??

  • 注解都寫好了,核心的代碼就是ViewInjectUtils.inject(this)了~

    3、ViewInjectUtils

    1、首先是注入主布局文件的代碼:

    [java]?view plaincopy
  • /**?
  • ?????*?注入主布局文件?
  • ?????*??
  • ?????*?@param?activity?
  • ?????*/??
  • ????private?static?void?injectContentView(Activity?activity)??
  • ????{??
  • ????????Class<??extends?Activity>?clazz?=?activity.getClass();??
  • ????????//?查詢類上是否存在ContentView注解??
  • ????????ContentView?contentView?=?clazz.getAnnotation(ContentView.class);??
  • ????????if?(contentView?!=?null)//?存在??
  • ????????{??
  • ????????????int?contentViewLayoutId?=?contentView.value();??
  • ????????????try??
  • ????????????{??
  • ????????????????Method?method?=?clazz.getMethod(METHOD_SET_CONTENTVIEW,??
  • ????????????????????????int.class);??
  • ????????????????method.setAccessible(true);??
  • ????????????????method.invoke(activity,?contentViewLayoutId);??
  • ????????????}?catch?(Exception?e)??
  • ????????????{??
  • ????????????????e.printStackTrace();??
  • ????????????}??
  • ????????}??
  • ????}??

  • 通過傳入的activity對象,獲得它的Class類型,判斷是否寫了ContentView這個注解,如果寫了,讀取它的value,然后得到setContentView這個方法,使用invoke進(jìn)行調(diào)用;

    有個常量:

    [java]?view plaincopy
  • private?static?final?String?METHOD_SET_CONTENTVIEW?=?"setContentView";??

  • 2、接下來是注入Views

    [java]?view plaincopy
  • private?static?final?String?METHOD_FIND_VIEW_BY_ID?=?"findViewById";??
  • ????/**?
  • ?????*?注入所有的控件?
  • ?????*??
  • ?????*?@param?activity?
  • ?????*/??
  • ????private?static?void?injectViews(Activity?activity)??
  • ????{??
  • ????????Class<??extends?Activity>?clazz?=?activity.getClass();??
  • ????????Field[]?fields?=?clazz.getDeclaredFields();??
  • ????????//?遍歷所有成員變量??
  • ????????for?(Field?field?:?fields)??
  • ????????{??
  • ??????????????
  • ????????????ViewInject?viewInjectAnnotation?=?field??
  • ????????????????????.getAnnotation(ViewInject.class);??
  • ????????????if?(viewInjectAnnotation?!=?null)??
  • ????????????{??
  • ????????????????int?viewId?=?viewInjectAnnotation.value();??
  • ????????????????if?(viewId?!=?-1)??
  • ????????????????{??
  • ????????????????????Log.e("TAG",?viewId+"");??
  • ????????????????????//?初始化View??
  • ????????????????????try??
  • ????????????????????{??
  • ????????????????????????Method?method?=?clazz.getMethod(METHOD_FIND_VIEW_BY_ID,??
  • ????????????????????????????????int.class);??
  • ????????????????????????Object?resView?=?method.invoke(activity,?viewId);??
  • ????????????????????????field.setAccessible(true);??
  • ????????????????????????field.set(activity,?resView);??
  • ????????????????????}?catch?(Exception?e)??
  • ????????????????????{??
  • ????????????????????????e.printStackTrace();??
  • ????????????????????}??
  • ??
  • ????????????????}??
  • ????????????}??
  • ??
  • ????????}??
  • ??
  • ????}??
  • 獲取聲明的所有的屬性,遍歷,找到存在ViewInject注解的屬性,或者其value,然后去調(diào)用findViewById方法,最后把值設(shè)置給field~~~

    好了,把這兩個方法寫到inject里面就好了。

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

  • 本文主要了解了如何打造這么個框架,下一篇,將教大家如何注入事件 ,不要再寫什么setXXXListener了~~~


    效果圖:



    源碼點(diǎn)擊下載

    總結(jié)

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

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