基础知识讲解

什么是DIP、IOC、DI、IOC容器

IOC容器的技术剖析

IOC中最基本的技术就是“反射(Reflection)”编程
我们可以把IOC容器的工作模式看做是工厂模式的升华,可以把IOC容器看作是一个工厂,这个工厂里要生产的对象都在配置文件中给出定义,然后利用编程语言的的反射编程,根据配置文件中给出的类名生成相应的对象。从实现来看,IOC是把以前在工厂方法里写死的对象生成代码,改变为由配置文件来定义,也就是把工厂和对象生成这两者独立分隔开来,目的就是提高灵活性和可维护性。

实际开发用法

技术解析
看到具体实现,有很多朋友一定会觉得很熟悉的,这不是butterknife么?那说明朋友们还是经常会用到这些技术,因为butterknife在3之前及3的部分都是运用的“反射”技术,还有我们常用的EventBus等等都用到了这项技术,但是一个三方框架,可能百分之八十的技术是我们用不到的。

目的与优缺点

  1. IOC 技术核心是解耦,降低模块之间的关联
  2. 优点:代码少,加速开发
  3. 缺点:反射产生性能损耗

具体开发实现

核心技术:反射
getMethod()与getDeclareMathods区别

  1. getMethod() 获取当前类和父类 public方法
  2. getDeclareMathods() 获取当前类所有方法

布局注解代码

package com.fly.newstart.ioc.annotetion;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** <pre>*           .----.*        _.'__    `.*    .--(Q)(OK)---/$\*  .' @          /$$$\*  :         ,   $$$$$*   `-..__.-' _.-\$/*         `;_:    `"'*       .'"""""`.*      /,  FLY  ,\*     //         \\*     `-._______.-'*     ___`. | .'___*    (______|______)* </pre>* 包    名 : com.fly.newstart.ioc* 作    者 : FLY* 创建时间 : 2019/4/24* 描述: 布局注入注解*/@Target(ElementType.TYPE) //该注解作用于什么之上 ,对应枚举标识 METHOD-标识为类之上
@Retention(RetentionPolicy.RUNTIME)//jvm在运行时通过反射获取注解的值
//RUNTIME-jvm在运行时通过反射来完成的过程
//CLASS-在编译时进行一些预操作,并且注解会在class存在
//SOURCE-源码级的,主要是做一些检查检测操作
public @interface ContentView {int value();
}

属性注解代码

package com.fly.newstart.ioc.annotetion;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** <pre>*           .----.*        _.'__    `.*    .--(Q)(OK)---/$\*  .' @          /$$$\*  :         ,   $$$$$*   `-..__.-' _.-\$/*         `;_:    `"'*       .'"""""`.*      /,  FLY  ,\*     //         \\*     `-._______.-'*     ___`. | .'___*    (______|______)* </pre>* 包    名 : com.fly.newstart.ioc.annotetion* 作    者 : FLY* 创建时间 : 2019/4/24* 描述: 属性的注解*/@Target(ElementType.FIELD) //该注解作用于什么之上 ,对应枚举标识 FIELD-标识为属性之上
@Retention(RetentionPolicy.RUNTIME)//jvm在运行时通过反射获取注解的值
public @interface InjectView {int value();
}

点击事件注解代码

package com.fly.newstart.ioc.annotetion;import android.view.View;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** <pre>*           .----.*        _.'__    `.*    .--(Q)(OK)---/$\*  .' @          /$$$\*  :         ,   $$$$$*   `-..__.-' _.-\$/*         `;_:    `"'*       .'"""""`.*      /,  FLY  ,\*     //         \\*     `-._______.-'*     ___`. | .'___*    (______|______)* </pre>* 包    名 : com.fly.newstart.ioc.annotetion* 作    者 : FLY* 创建时间 : 2019/4/24* 描述: 点击事件的注解*/@Target(ElementType.METHOD) //该注解作用于什么之上 ,对应枚举标识 METHOD-标识为方法之上
@Retention(RetentionPolicy.RUNTIME)//jvm在运行时通过反射获取注解的值
@EventBase(listenerSetter = "setOnClickListener", listenerType = View.OnClickListener.class, listenerCallBack = "onClick")
public @interface OnClick {int[] value();
}

长按事件注解代码

package com.fly.newstart.ioc.annotetion;import android.view.View;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/*** <pre>*           .----.*        _.'__    `.*    .--(Q)(OK)---/$\*  .' @          /$$$\*  :         ,   $$$$$*   `-..__.-' _.-\$/*         `;_:    `"'*       .'"""""`.*      /,  FLY  ,\*     //         \\*     `-._______.-'*     ___`. | .'___*    (______|______)* </pre>* 包    名 : com.fly.newstart.ioc.annotetion* 作    者 : FLY* 创建时间 : 2019/4/24* 描述: 长按事件的注解*/@Target(ElementType.METHOD) //该注解作用于什么之上 ,对应枚举标识 METHOD-标识为方法之上
@Retention(RetentionPolicy.RUNTIME)//jvm在运行时通过反射获取注解的值
@EventBase(listenerSetter = "setOnLongClickListener", listenerType = View.OnLongClickListener.class, listenerCallBack = "onLongClick")
public @interface OnLongClick { //注解对应方法需要boolean返回值int[] value();
}

事件注解的注解代码

package com.fly.newstart.ioc.annotetion;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** <pre>*           .----.*        _.'__    `.*    .--(Q)(OK)---/$\*  .' @          /$$$\*  :         ,   $$$$$*   `-..__.-' _.-\$/*         `;_:    `"'*       .'"""""`.*      /,  FLY  ,\*     //         \\*     `-._______.-'*     ___`. | .'___*    (______|______)* </pre>* 包    名 : com.fly.newstart.ioc.annotetion* 作    者 : FLY* 创建时间 : 2019/4/24* 描述: 事件注解的注解 用于封装点击事件规律的对象*/@Target(ElementType.ANNOTATION_TYPE) //该注解作用于什么之上 ,对应枚举标识 ANNOTATION_TYPE-标识为注解之上
@Retention(RetentionPolicy.RUNTIME)//jvm在运行时通过反射获取注解的值
public @interface EventBase {//setxxxListenerString listenerSetter();//new View.xxxListenerClass<?> listenerType();//回调执行方法:onxxx()String listenerCallBack();}

注入管理类代码

package com.fly.newstart.ioc;import android.app.Activity;
import android.util.Log;
import android.view.View;import com.fly.newstart.ioc.annotetion.ContentView;
import com.fly.newstart.ioc.annotetion.EventBase;
import com.fly.newstart.ioc.annotetion.InjectView;import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** <pre>*           .----.*        _.'__    `.*    .--(Q)(OK)---/$\*  .' @          /$$$\*  :         ,   $$$$$*   `-..__.-' _.-\$/*         `;_:    `"'*       .'"""""`.*      /,  FLY  ,\*     //         \\*     `-._______.-'*     ___`. | .'___*    (______|______)* </pre>* 包    名 : com.fly.newstart.ioc* 作    者 : FLY* 创建时间 : 2019/4/24* 描述: 注入管理类*/public class InjectManager {/*** 注解的初始注入** @param activity*/public static void inject(Activity activity) {//布局的注入injectLayout(activity);//控件的注入injectView(activity);//事件的注入injectEvents(activity);}/*** 布局的注入** @param activity*/private static void injectLayout(Activity activity) {//获取类Class<? extends Activity> cla = activity.getClass();//获取类上的注解ContentView contentView = cla.getAnnotation(ContentView.class);//获取注解的值if (contentView != null) {int layoutId = contentView.value();// 执行方法:setContentView(R.layout.activity_ioc);// 方法一:activity.setContentView(layoutId);// 方法二:反射获取,高大上try {//setContentView 是父类的方法不能使用getDeclareMathods(),需要使用getMethod()Method method = cla.getMethod("setContentView", int.class);//执行方法method.invoke(activity, layoutId);} catch (Exception e) {e.printStackTrace();}}}/*** 控件的注入** @param activity*/private static void injectView(Activity activity) {//获取类Class<? extends Activity> cla = activity.getClass();//获取类的所有属性Field[] fields = cla.getDeclaredFields();// 循环 拿到每个属性if (fields == null || fields.length < 1) return;for (Field field : fields) {// 获取每个属性的注解InjectView injectView = field.getAnnotation(InjectView.class);if (injectView != null) { //并不是所有属性都有注解//获取注解的值int viewId = injectView.value();//执行方法:mBtn01 = findViewById(R.id.btnO1)try {Method method = cla.getMethod("findViewById", int.class); //findViewById 需要赋值//执行方法 获取返回值Object view = method.invoke(activity, viewId);//设置私有属性的访问权限,默认为falsefield.setAccessible(true);//给属性赋值field.set(activity, view);} catch (Exception e) {e.printStackTrace();}}}}/*** 事件的注入** @param activity*/private static void injectEvents(Activity activity) {//获取类Class<? extends Activity> cla = activity.getClass();//获取类的所有方法,事件注解肯定是当前类Method[] methods = cla.getDeclaredMethods();if (methods == null || methods.length < 1) return;for (Method method : methods) {//获取每个方法的注解Annotation[] annotations = method.getAnnotations();//一个可能有多个注解if (annotations == null || annotations.length < 1) continue;for (Annotation annotation : annotations) {//获取注解上的注解类型Class<? extends Annotation> annotationType = annotation.annotationType();if (annotationType != null) {//通过EventBase注解,获取3个重要的规律EventBase eventBase = annotationType.getAnnotation(EventBase.class);//事件的3个规律String listenerSetter = eventBase.listenerSetter();Class<?> listenerType = eventBase.listenerType();String listenerCallBack = eventBase.listenerCallBack();//获取注解的值try {// 通过运行annotationType获取OnClick注解的value值Method valueMethod = annotationType.getDeclaredMethod("value");//运行OnClick注解的value方法获取value值int[] viewIds = (int[]) valueMethod.invoke(annotation);//打包之后,代理处理后续工作,可以兼容多种事件方式,不需要写接口//创建拦截器ListenerInvocationHandler handler = new ListenerInvocationHandler(activity);handler.addMethod(listenerCallBack, method);//创建代理Object listene = Proxy.newProxyInstance(listenerType.getClassLoader(), new Class[]{listenerType}, handler);if (viewIds == null || viewIds.length < 1) continue;for (int viewId : viewIds) {//控件的赋值,保证控件没有赋值也可使用View view = activity.findViewById(viewId);//获取set方法Method setter = view.getClass().getMethod(listenerSetter, listenerType);//执行方法,传入代理setter.invoke(view, listene);}} catch (Exception e) {e.printStackTrace();}}}}}
}

事件处理拦截器代码

package com.fly.newstart.ioc;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;/*** <pre>*           .----.*        _.'__    `.*    .--(Q)(OK)---/$\*  .' @          /$$$\*  :         ,   $$$$$*   `-..__.-' _.-\$/*         `;_:    `"'*       .'"""""`.*      /,  FLY  ,\*     //         \\*     `-._______.-'*     ___`. | .'___*    (______|______)* </pre>* 包    名 : com.fly.newstart.ioc* 作    者 : FLY* 创建时间 : 2019/4/24* 描述: 事件处理拦截器*/
public class ListenerInvocationHandler implements InvocationHandler {//需要拦截的对象private Object target;//需要拦截的方法集合private HashMap<String, Method> methodhMap = new HashMap<>();public ListenerInvocationHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (target != null) {//获取需要拦截的方法名String methodName = method.getName();//重新赋值,将拦截的方法换为了自定义的方法method = methodhMap.get(methodName);//从集合中判断是否需要拦截if (method != null) {//确定找到了需要拦截的的方法,才执行自定义方法if (method.getParameterTypes().length == 0) { //判断有无参数return method.invoke(target);} else return method.invoke(target, args);}}return null;}/*** 将需要拦截的方法加入集合** @param methodName 需要拦截的方法名* @param method     执行自定义的方法*/public void addMethod(String methodName, Method method) {methodhMap.put(methodName, method);}
}

测试Activity代码

package com.fly.newstart.ioc.text;import android.view.View;
import android.widget.Button;
import android.widget.Toast;import com.fly.newstart.R;
import com.fly.newstart.common.base.BaseActivity;
import com.fly.newstart.ioc.annotetion.ContentView;
import com.fly.newstart.ioc.annotetion.InjectView;
import com.fly.newstart.ioc.annotetion.OnClick;
import com.fly.newstart.ioc.annotetion.OnLongClick;// setContentView(R.layout.activity_ioc);
@ContentView(R.layout.activity_ioc)
public class IOCActivity extends BaseActivity {@InjectView(R.id.btnO1) //mBtn01 = findViewById(R.id.btnO1)private Button mBtn01;@InjectView(R.id.btnO2)private Button mBtn02;@Overrideprotected void onResume() {super.onResume();Toast.makeText(this, mBtn01.getText().toString(), Toast.LENGTH_SHORT).show();}// mBtn01.setOnClickListener(new View.OnClickListener() {@Override public void onClick(View v) { //  }});@OnClick({R.id.btnO1, R.id.btnO2})public void show(View view) {Toast.makeText(this, "shwo(View view)", Toast.LENGTH_SHORT).show();}// mBtn01.setOnLongClickListener(new View.OnLongClickListener() {@Override public boolean onLongClick(View v) {   return false;  }});@OnLongClick({R.id.btnO1, R.id.btnO2})public boolean showLong(View view) {Toast.makeText(this, "shwoLong(View view)", Toast.LENGTH_SHORT).show();return false;}//    @OnClick({R.id.btnO1,R.id.btnO2}) //proxy 代理
//    public void show(){
//        Toast.makeText(this, mBtn01.getText().toString(), Toast.LENGTH_LONG).show();
//    }public void initView() {//用注解实现,需要代理完成,监听回调的过程//Android监听事件是有规律的//setxxxListener//new View.xxxListener//回调执行方法:onxxx()//将规律打包成一个对象,用代理去完成这个事件//还需要用到AOP  面向切面的技术mBtn01.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {}});mBtn02.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {}});mBtn01.setOnLongClickListener(new View.OnLongClickListener() {@Overridepublic boolean onLongClick(View v) {return false;}});}
}

baseActivity代码

package com.fly.newstart.common.base;import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.app.AppCompatDelegate;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;import com.fly.newstart.R;
import com.fly.newstart.ioc.InjectManager;/***           .----.*        _.'__    `.*    .--(Q)(OK)---/$\*  .' @          /$$$\*  :         ,   $$$$$*   `-..__.-' _.-\$/*         `;_:    `"'*       .'"""""`.*      /,  FLY  ,\*     //         \\*     `-._______.-'*     ___`. | .'___*    (______|______)* </pre>* 包    名 : com.fly.newstart.common.base* 作    者 : FLY* 创建时间 : 2017/8/7* <p>* 描述: Activity的基类*/public class BaseActivity extends AppCompatActivity {@Overrideprotected  void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 帮助所有子类完成注入工作InjectManager.inject(this);}}

难点剖析

布局注入与属性注入都比较简单,只是运用反射的基本知识,但是方法的注入就比较难以理解,其中还运用了Prixy(代理)和InvocationHandler(拦截)的技术。

代理的原理与用法

Android监听事件规律-三部曲

将规律打包成一个对象,用代理去完成这个事件,但是这样任然不能完成我们需要的功能,还需要用到AOP 面向切面的技术。

AOP原理和拦截

小结

  1. 主要了解IOC注入框架,含义及基础使用
  2. 注解的基本使用
  3. “反射”的常规用法,七种常用且基础的API理解
  4. 代理的思路与原理
  5. AOP原理与拦截

自我提升之二 揭秘IOC注入框架,轻松实现布局、属性、事件注入相关推荐

  1. spring单元测试无法注入bean_Spring容器启动@Value属性无法注入?

    点击上方☝SpringForAll社区 轻松关注!及时获取有趣有料的技术文章 本文来源:http://yeming.me/2017/04/16/springValueAnnotation/ 问题 一个 ...

  2. (二)TestNG测试框架之注解及属性概览

    前言 TestNG提供了诸多注解,允许开发/测试人员灵活地组织强大的测试用例. 注解概览 注解/属性 描述 @BeforeSuite @AfterSuite @BeforeTest @AfterTes ...

  3. Koin--适用于Kotlin的超好用依赖注入框架,Dagger替代者,Koin史上最详细解说,一篇就够了,妈妈再也不用担心我不会依赖注入了

    今年呆在家中实在无聊,外面太危险了,还是在家学习比较安全可持续. 过年期间,我又复习了几遍依赖注入框架Dagger. 诶,什么是依赖注入? 说白了就是降低跟类对象之间的耦合,当需要修改类对象的时候,能 ...

  4. Google Guice 一个轻量级的依赖注入框架

    1.美图 2.概述 2.1 背景 在做项目的时候,看见有段代码直接是使用Google Guice 注入了avaitor表达式. 2.1 官网 Github 主页:https://github.com/ ...

  5. 《撸代码 学习 IOC注入技术1 》—— 布局注入 与 控件注入

    不诗意的女程序媛不是好厨师~ 转载请注明出处,From李诗雨-https://blog.csdn.net/cjm2484836553/article/details/104539874 [源代码下载地 ...

  6. bean注入属性_摆脱困境:将属性值注入配置Bean

    bean注入属性 Spring Framework对将从属性文件中找到的属性值注入到bean或@Configuration类中提供了很好的支持. 但是,如果将单个属性值注入这些类中,则会遇到一些问题. ...

  7. 摆脱困境:将属性值注入配置Bean

    Spring Framework对将从属性文件中找到的属性值注入到bean或@Configuration类中提供了很好的支持. 但是,如果将单个属性值注入这些类中,则会遇到一些问题. 这篇博客文章指出 ...

  8. 【SSM框架系列】Spring IoC(控制反转) DI(依赖注入)注解开发

    Spring注解开发 Spring是轻代码重配置的框架,配置比较繁重,会影响开发效率.这个时候可以通过注解开发,注解代替xml配置文件可以简化配置,提高开发效率. Spring原始注解 注解分为原始注 ...

  9. 王学岗移动架构34——IOC注入框架设计

    本框架可以在Activity和Dialog中使用,并且已有代码示例.fragment读者自己加上就可以了,没写代码 package com.example.lsn_34;import android. ...

  10. ASP.NET Core技术研究-探秘依赖注入框架

    ASP.NET Core在底层内置了一个依赖注入框架,通过依赖注入的方式注册服务.提供服务.依赖注入不仅服务于ASP.NET Core自身,同时也是应用程序的服务提供者. 毫不夸张的说,ASP.NET ...

最新文章

  1. Docker火遍全球!Docker(Inc)这家公司却要死了???
  2. java 单例设计模式 [
  3. 8.Java有关变量的面试题
  4. 登陆状态购物车数据结构
  5. Halcon:模版匹配
  6. [Java基础]复制文件的异常处理try...catch...finally的做法
  7. 【2017年第1期】大数据能力开放平台创新和发展
  8. python 画风场 scipy_Python库之SciPy教程
  9. html设置桌面背景win7,怎么让电脑桌面背景动起来 win7设置动态背景桌面的方法...
  10. go语言 liteIDE 错误: 进程无法启动.
  11. java给数组排序_java数组如何排序
  12. laravel faker数据填充详解
  13. amd显卡多屏识别了 但是屏幕不亮_最近发布:针对AMD显卡多屏显示设置的完整解决方案。ppt28...
  14. 当原图片加载失败时,如何让图片加载上我们默认给的图片
  15. 玩转Ubuntu(磁盘管理工具GParted)
  16. 计算机网络读书笔记(二)
  17. 儿童学计算机编程好处,儿童编程课学了有好处吗?4大优势家长要知道
  18. 亚马逊广告授权流程说明
  19. 2019全国大学生软件测试比赛,原创 安恒信息圆满支撑“2019全国大学生软件测试大赛”...
  20. 通过response返回json数据到前端

热门文章

  1. WINRAR青绿色透明主题皮肤 Vista/win 7下效果极佳
  2. java从地址串中解析提取省市区-完美匹配中国所有地址
  3. 21天学通python-21天学通Python(第2版)_PDF电子书
  4. 斐讯k2刷无线打印服务器,斐讯K2全版本刷机教程
  5. eeprom和编程器固件 k2_瞎鸡儿折腾之K2/K2P刷机,刷入第三方固件,傻吊教程!
  6. ACR122U读写器真假判断
  7. python webkit内核_GitHub - yufengsoft/wke: 基于Webkit精简的纯C接口的浏览器内核,可用于桌面UI、浏览器。...
  8. Flash Player离线安装包下载指南
  9. 北邮数电 爱课堂答案 Verilog专题
  10. xp sp3不让dword shoot