android ico学习笔记

本文详细介绍了一个基于Android平台的IOC框架实现原理及应用方法,包括如何通过反射机制动态加载布局、控件及其事件。

android ioc框架笔记。

最近在学习ioc框架,学习之后对自己的学习做一个简单的笔记。方便自己日后复习,以及再次使用。

概要:
通过反射机制,代理模式。去动态加载我们的布局,控件,以及事件。
源码实现:
首先我们需要一个注入帮助类InjectUtils。


首先我们提供一个可供外界访问public的方法,里面去实现我们的布局,控件,以及事件的注入方法。

public static void inject(Context context) {
       //动态加载布局 
        injectLayout(context);
         //加载控件
        Map<Integer, Object> injectView = injectView(context);
         //view 添加监听
        injectEvent(context, injectView);
   }

下面实现我们的布局加载
实现之前需要去定义我们的注解类@ContentView
新建一个注解类

package com.example.lq.test0420.frameWork.layout;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Created by Administrator on 2016-4-23.
 */
//指定作用范围   类上面
@Target(ElementType.TYPE)
//指定生命周期   当程序运行的时候  通过反射机制加载
@Retention(RetentionPolicy.RUNTIME)
public @interface ContentView {
    int value();
}

有了这个@ContentView注解类以后我们就可以实现我们的动态加载布局了。

 private static void injectLayout(Context context) {
        //首先   定义注解类 就是上面的@ContentView
        //通过反射机制注入布局
        Class<? extends Context> clazz = context.getClass();
        //获取contentView 注解类
        ContentView contentView = clazz.getAnnotation(ContentView.class);
        try {
            if (contentView != null) {//判断有没有配置注解
                //绑定布局

                //加载布局   ---activity里面用    LayoutInfalter  or   setContentView去加载
                //获取布局ID
                int layoutID = contentView.value();
                //获取加载布局的setContentView方法
                Method setContentViewMethod = clazz.getMethod("setContentView", int.class);
                setContentViewMethod.invoke(context, layoutID);//执行context 上的方法setcontentView
            }
        } catch (Exception e) {
            e.printStackTrace();
     }
 }

这一步做完之后,再把我们的控件也注入进去,和上面一样。首先需要一个控件的注入类,新建一个@ViewInject类

package com.example.lq.test0420.frameWork.view;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Created by Administrator on 2016-4-23.
 */
//范围
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewInject {
    int value();
}

有了注入类就可以去写我们注入控件的方法了。

private static Map<Integer, Object> injectView(Context context) {
        //创建ViewInject注解类
        //通过反射机制绑定View
        Class<? extends Context> clazz = context.getClass();
        Field[] fields = clazz.getDeclaredFields();//拿到所有属性
        Map<Integer, Object> viewMap = new HashMap<Integer, Object>();

        try {
            for (Field field : fields) {
                //获取属性注解
                ViewInject viewInject = field.getAnnotation(ViewInject.class);
                if (viewInject != null) {
                    //获取控件ID
                    int viewID = viewInject.value();
                    //加载控件   activity  findViewByid
                    Method findViewByidMethod = clazz.getMethod("findViewById", int.class);
                    //绑定   加载VIEW
                    Object view = findViewByidMethod.invoke(context, viewID);
                    field.setAccessible(true);//设置访问权限
                    //给属性赋值
                    field.set(context, view);//给Actiovity 的view 赋值
                    viewMap.put(viewID, view);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return viewMap;
    }

现在我们的布局以及控件的注入就Ok了。我们可以在我们的activity里面测试一下。

package com.example.lq.test0420;

import android.app.Activity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.example.lq.test0420.frameWork.InjectUtils;
import com.example.lq.test0420.frameWork.event.OnClick;
import com.example.lq.test0420.frameWork.layout.ContentView;
import com.example.lq.test0420.frameWork.view.ViewInject;

@ContentView(R.layout.activity_main)//注入布局
public class MainActivity extends Activity {
    @ViewInject(R.id.btn_title)//注入控件
    private Button btn_titile;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        InjectUtils.inject(this);//这一步一定要有,否则没法注入的
        if (btn_titile != null) {
            Toast.makeText(this, "哈哈", Toast.LENGTH_LONG).show();
        }
    }
   }

到这一步就可以看到我们的布局控件已经显示在我们的手机上啦。有点小激动呢。
到这一歩还没完,难点是在我们的事件的动态加载。下面我们实现一下我们事件的动态加载方法。
跟上面一样哈,也是需要我们的注解类.首先我们需要思考一下。事件很多哎,那么我们就需要找出他的共性。叫做xxx三要素。
frist 事件源也就是我们的view second回调方法 third 监听器。
有事件就会有这三个玩意哈。
所以我们需要来一个基类把这三个都放进去。

package com.example.lq.test0420.frameWork.event;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Created by Administrator on 2016-4-23.
 */
//作用在注解上
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface BaseEvent {
    //事件三要素
    // 事件源--view
    String listenerSetter();

    // 回调方法 --xxclick
    String callBackMethod();

    // 监听器----xxlistener
    Class<?> listenerType();
}

然后我们就去搞我们的事件注解类

package com.example.lq.test0420.frameWork.event;

import android.view.View;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Created by Administrator on 2016-4-23.
 */
@Target(ElementType.METHOD)//指定方法上
@Retention(RetentionPolicy.RUNTIME)
//指定事件三要素
@BaseEvent(listenerSetter = "setOnClickListener",callBackMethod = "onClick",listenerType = View.OnClickListener.class)
public @interface OnClick {
    int[] value();

}

在这里我们的注解类就搞定了,下面就是我们动态加载事件方法的实现了。这里学的很蒙,如果有啥不对的地方,欢迎斧正。

  /**
     * 事件三要素   事件源--view   回调方法 --xxclick  监听器----xxlistener
     *
     * @param context
     * @param injectView
     */
    private static void injectEvent(Context context, Map<Integer, Object> injectView) {
        //创建注解文件
        //绑定监听
        Class<? extends Context> clazz = context.getClass();
        //获取所有的方法
        Method[] methods = clazz.getMethods();
        try {
            for (Method method : methods) {//遍历所有的方法去拿注解
                //获取方法上面的所有注解
                Annotation[] annotations = method.getAnnotations();
                if (annotations != null) {
                    for (Annotation annotation : annotations) {
                        //拿到BaseEvent注解  获取事件三要素
                        Class<? extends Annotation> annotationType = annotation.annotationType();
                        if (annotationType != null) {
                            BaseEvent baseEvent = annotationType.getAnnotation(BaseEvent.class);
                            if (baseEvent != null) {
                                //说明注解是onclick注解
                                //获取事件三要素
                                String listenerSetter = baseEvent.listenerSetter();
                                String callBackMethod = baseEvent.callBackMethod();
                                Class<?> listenerType = baseEvent.listenerType();
                                //获取控件ID
                                Method valueMethod = annotationType.getDeclaredMethod("value");
                                int[] viewsID = (int[]) valueMethod.invoke(annotation);//执行annotaion方法
                                //动态代理模式(java 自带动态代理类)
                                ListenerInvocationHandler listenerInvocationHandler =
                                        new ListenerInvocationHandler(context);
                                listenerInvocationHandler.addMehtod(callBackMethod, method);
                                //执行代理
                                //返回对象为  on--xxxlistener
                                Object listener = Proxy.newProxyInstance(listenerType.getClassLoader(),//类加载器
                           new Class[]{listenerType},//代理的类
                listenerInvocationHandler) //绑定监听
            for (int i : viewsID) {
                 Object view = injectView.get(i);
                 //获取setOnxxlistener()
               Method setOnXXXlistenerMethod =
                                            view.getClass().getMethod(listenerSetter, listenerType);
                                    setOnXXXlistenerMethod.invoke(view, listener);//执行view上的监听方法

                                }

                            }
                        }
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

到此我们的动态加载事件就搞定。下面去act里面实现一下。

 @OnClick({R.id.btn_title})
    public void show(View v) {
        Toast.makeText(this, "你好啊", Toast.LENGTH_LONG).show();
    }

写完这一句以后,你就可以点击下试试有没有点击事件的出现咯。如果出现了,说明成功了。
学了这个才知道移动构架师能赚那么多钱不是白赚的哈,努力奋斗吧。
——-致和我一样的码农

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值