最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android用注解與反射實(shí)現(xiàn)Butterknife功能

 更新時(shí)間:2022年11月24日 15:17:27   作者:發(fā)飆的蝸牛YR  
Butterknife是一個(gè)在android上實(shí)現(xiàn)ioc(控制反轉(zhuǎn))的一個(gè)庫。ioc的核心是解耦。解耦的目的是修改耦合對象時(shí)不影響另外一個(gè)對象,降低模塊之間的關(guān)聯(lián)。在Spring中ioc更多的是依靠xml的配置。而android上的IOC框架可以不使用xml配置

自定義注解

1) 先定義布局文件注入

//注解的作用域在類上
@Target(ElementType.TYPE)
//讓保持性策略為運(yùn)行時(shí)態(tài),將注解編碼到class文件中,讓虛擬機(jī)讀取
@Retention(RetentionPolicy.RUNTIME)
public @interface ContentView {
    int value();//使用時(shí)直接@ContentView(R.layout.xxx)指定的R.layout.xxx就是布局文件,會(huì)自動(dòng)注入布局文件
}

2) 布局中控件注入文件

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewInject {
    int value();
}

3) 控件的點(diǎn)擊響應(yīng)注入文件

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface OnClick {
    int[] value();
}

使用自定義注解

@ContentView(R.layout.activity_test)
public class TestActivity extends AppCompatActivity implements View.OnClickListener{
    @ViewInject(R.id.edit_text)
    EditText mEditText;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        injectContentView(this);
        injectView(this);
        injectEvent(this);
    }
    @OnClick(R.id.button)
    @Override
    public void onClick(View v) {
        Toast.makeText(TestActivity.this,"點(diǎn)擊成功"+mEditText.getText().toString(),Toast.LENGTH_SHORT).show();
    }
}

通過反射機(jī)制獲取注解參數(shù)

Method相關(guān)方法的介紹:

method.invoke(Object obj,Object args[])的作用就是調(diào)用method類代表的方法,其中obj是對象名,args是傳入method方法的參數(shù)

  • getMethods(): 獲得類的public類型的方法
  • getMethod(String name, Class[] params): 獲得類的特定方法,name參數(shù)指定方法的名字,params參數(shù)指定方法的參數(shù)類型
  • getDeclaredMethods(): 獲取類中所有的方法(public、protected、default、private)
  • getDeclaredMethod(String name, Class[] params): 獲得類的特定方法,name參數(shù)指定方法的名字,params參數(shù)指定方法的參數(shù)類型

1. 布局文件獲取

    public static void injectContentView(Activity activity){
        //獲取activity的類實(shí)例
        Class<? extends Activity> clazz = activity.getClass();
        //獲取到activity的ContentView注解
        ContentView contentView = clazz.getAnnotation(ContentView.class);
        if(contentView!=null){
            //如果activity上面存在這個(gè)注解的話,就取出這個(gè)注解對應(yīng)的value值,就是前面設(shè)置的布局
            int layoutId=contentView.value();
            try {
                //利用反射調(diào)用setContentView方法,完成注入
                Method setViewMethod = clazz.getMethod("setContentView", int.class);
                setViewMethod.invoke(activity,layoutId);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

2. 控件獲取實(shí)現(xiàn)

    private static void injectView(Activity activity){
        //獲取activity的類實(shí)例
        Class<? extends Activity> clazz = activity.getClass();
        //獲取activity的所有成員變量
        Field[] fields = clazz.getDeclaredFields();
        //遍歷成員變量,獲取成員變量上的ViewInject注解
        for(Field field:fields){
            //獲取字段上面的注解對象,同有則繼續(xù)下一個(gè)字段
            ViewInject viewInject = field.getAnnotation(ViewInject.class);
            if(viewInject!=null){
                //獲取ViewInject注解的View的id
                int viewId = viewInject.value();
                //獲取控件
                View view = activity.findViewById(viewId);
                try {
                    //設(shè)置field為可訪問,就算私有的也能訪問到,能夠提高效率
                    field.setAccessible(true);
                    //將該控件設(shè)置給field對象
                    field.set(activity,view);//將activity對象的view控件設(shè)置給屬性對應(yīng)上面的例子是mEditText=findViewById(viewId)
                }catch (IllegalAccessException e){
                    e.printStackTrace();
                }
            }
        }
    }

3. 控件點(diǎn)擊響應(yīng)

    private static void injectEvent(final Activity activity) {
        Class<? extends Activity> clazz = activity.getClass();
        //獲取所有方法(私有方法也可以獲取到)
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            //獲取方法上面的OnClick注解
            OnClick click = method.getAnnotation(OnClick.class);
            //有則繼續(xù)下面代碼
            if (click != null) {
                //獲取注解中的數(shù)據(jù),因可以給多個(gè)button綁定點(diǎn)擊事件,因此定義的注解類時(shí)使用的是int[]數(shù)據(jù)類型
                int[] viewId = click.value();
                //在需要發(fā)射時(shí)將method的setAccessible設(shè)置為true,可以提高反射速度,原因是設(shè)置為true后則跳過了訪問檢查,即使private修飾的也可以訪問。
                method.setAccessible(true);
                //設(shè)置一個(gè)代理對象,當(dāng)調(diào)用setOnClickListener時(shí),把代理對象傳進(jìn)去,當(dāng)點(diǎn)擊發(fā)生時(shí),就會(huì)invoke方法,可以調(diào)用帶有onClick注解的method方法
               //此時(shí)的listener就是actvivty實(shí)現(xiàn)View.OnClickListener接口,并實(shí)現(xiàn)其接口中onClick方法的對象,其實(shí)也就是返回的invoke對象。
                Object listener = Proxy.newProxyInstance(View.OnClickListener.class.getClassLoader(),
                        new Class[]{View.OnClickListener.class}, new InvocationHandler() {
                    //這個(gè)invoke,其實(shí)就是調(diào)用的意思,第一個(gè)參數(shù)就是被代理的對象,第二個(gè)參數(shù)就是調(diào)用的方法,第三個(gè)參數(shù)是被調(diào)用方法的參數(shù)數(shù)組。
                            @Override
                            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                                Log.d(TAG, "method"+method);
                                Log.d(TAG, "args "+args);
                                //執(zhí)行activity對象,參數(shù)args的方法,activity對象就是當(dāng)前的Activity,并且已經(jīng)實(shí)現(xiàn)View.OnClickListener
                                //也就是說如果點(diǎn)擊了控件將會(huì)執(zhí)行實(shí)現(xiàn)了View.OnClickListener的Activity的onClick方法
                                Object invoke = method.invoke(activity, args);
                                return invoke;
                            }
                        });
                 //listener是一個(gè)OnClickListener類的對象,因?yàn)閙ethod傳的是activity,所以是當(dāng)前類的OnClickListener對象
                //method是onClick方法
                try {
                    for (int id : viewId) {
                        //獲取相應(yīng)的控件
                        View v = activity.findViewById(id);
                        //"setOnClickListener"是方法名,View.OnClickListener.class方法參數(shù)的類型
                        Method setClickListener = v.getClass().getMethod("setOnClickListener", View.OnClickListener.class);
                        Log.d(TAG, "injectEvent: "+listener+"v.getClass()"+v);
                        //View類中的setOnClickListener方法需要一個(gè)OnClickListener類型的參數(shù)也就是我們的代理對象
                        //我們需要將對應(yīng)的控件進(jìn)行設(shè)置
                        //這時(shí)當(dāng)我們點(diǎn)擊v(也就是我們找到的控件)時(shí)就會(huì)調(diào)用代理對象的onClick方法。而代理對象的onClick方法就是Activity中實(shí)現(xiàn)接口的onClick方法。相當(dāng)于執(zhí)行方法setOnClickListener(listener)。而這個(gè)listener就是我們上面代理(當(dāng)前activity實(shí)現(xiàn)OnClicker接口的對象)對象。
                        setClickListener.invoke(v, listener);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

上面的實(shí)現(xiàn)都是在運(yùn)行時(shí)通過反射完成注入,但它會(huì)對性能有一定損耗,而Butterknife用的是APT(Annotation Processing Tool)編譯時(shí)解析技術(shù)。它在Java代碼編譯成Java字節(jié)碼時(shí)就已經(jīng)處理了@Bind, @OnClick這些注解。它的原理是讀入Java源代碼,解析注解,生成新的Java代碼,新生成的Java代碼最后被編譯成Java字節(jié)碼。

到此這篇關(guān)于Android用注解與反射實(shí)現(xiàn)Butterknife功能的文章就介紹到這了,更多相關(guān)Android Butterknife內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Android 手機(jī)屏幕適配解決辦法

    Android 手機(jī)屏幕適配解決辦法

    這篇文章主要介紹了Android 手機(jī)屏幕適配的相關(guān)資料,在開發(fā)Android 手機(jī)開發(fā)的時(shí)候經(jīng)常會(huì)有很多手機(jī)品牌和手機(jī)屏幕尺寸問題,需要的朋友可以參考下
    2016-10-10
  • Android Studio如何獲取SQLite數(shù)據(jù)并顯示到ListView上

    Android Studio如何獲取SQLite數(shù)據(jù)并顯示到ListView上

    這篇文章主要介紹了Android Studio獲取SQLite數(shù)據(jù)并顯示到ListView上,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-03-03
  • Android通話記錄備份實(shí)現(xiàn)代碼

    Android通話記錄備份實(shí)現(xiàn)代碼

    其實(shí)就是解析文件,存入數(shù)據(jù)庫;或者查詢數(shù)據(jù)庫,存入文件而已,特分享下,方便需要的朋友
    2013-05-05
  • Android源代碼倉庫及其管理工具Repo分析詳解

    Android源代碼倉庫及其管理工具Repo分析詳解

    本篇文章主要介紹了Android源代碼倉庫及其管理工具Repo分析詳解,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-01-01
  • Android自定義輪播圖效果

    Android自定義輪播圖效果

    這篇文章主要為大家詳細(xì)介紹了Android自定義輪播圖效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • Android給通知channel靜音的方法實(shí)例

    Android給通知channel靜音的方法實(shí)例

    這篇文章主要給大家介紹了關(guān)于Android如何給通知channel靜音的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2022-02-02
  • Android實(shí)現(xiàn)登錄郵箱的自動(dòng)補(bǔ)全功能

    Android實(shí)現(xiàn)登錄郵箱的自動(dòng)補(bǔ)全功能

    這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)登錄郵箱的自動(dòng)補(bǔ)全功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-04-04
  • 深入理解Android中的建造者模式

    深入理解Android中的建造者模式

    建造者模式將一個(gè)復(fù)雜的構(gòu)建與其表示相分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。所以這篇文章主要介紹了Android中的建造者模式,有需要的朋友們可以參考借鑒。
    2016-09-09
  • Android 服務(wù)端將位置信息發(fā)送給客戶端的實(shí)現(xiàn)

    Android 服務(wù)端將位置信息發(fā)送給客戶端的實(shí)現(xiàn)

    這篇文章主要介紹了Android 服務(wù)端將位置信息發(fā)送給客戶端的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • Android實(shí)現(xiàn)在屏幕上移動(dòng)圖片的方法

    Android實(shí)現(xiàn)在屏幕上移動(dòng)圖片的方法

    這篇文章主要介紹了Android實(shí)現(xiàn)在屏幕上移動(dòng)圖片的方法,實(shí)例分析了Android操作圖片的相關(guān)技巧,需要的朋友可以參考下
    2015-06-06

最新評論

炎陵县| 维西| 侯马市| 崇州市| 玉田县| 浙江省| 瑞昌市| 浙江省| 天津市| 吴堡县| 项城市| 阿拉善右旗| 称多县| 台安县| 瑞昌市| 海丰县| 汾阳市| 新昌县| 日土县| 徐闻县| 陇西县| 明光市| 广元市| 马边| 香港 | 泸溪县| 临桂县| 南涧| 中西区| 玉田县| 江华| 错那县| 莱阳市| 融水| 剑阁县| 宜宾县| 乌恰县| 佛冈县| 平武县| 桃园市| 荣昌县|