android 常用ioc框架,Android进阶——框架之IOC框架

什么是IOC

IOC(Inversion of Control):控制反转。开发过程中类里面需要用到很多个成员变量

传统的写法:你要用这些成员变量的时候,那么你就new出来用

IOC的写法:你要用这些成员变量的时候,使用注解的方式自动注入进去

优点:代码量减少,加速开发

缺点:性能消耗加大,阅读性差,加速65535

框架的思路

框架例子

//实现Button自动findViewById的工作

@ViewById(R.id.bt_ioc)

private Button bt_ioc;1

实现思路

•创建自定义注解 @ViewById

•通过某个字节码文件获取对应的自定义注解

•通过反射,获取注解和注解的值 (R.id.bt_ioc)

•通过对注解的值做相应的操作,并设置回对象自身

实现内容

•实现通过Id找到控件的功能

•实现通过Id找到Color、String资源

•实现绑定view的点击事件、长按事件

•实现绑定SetContentView

•实现绑定网络的检测功能

框架的结构

31a3ba1d7aeb

20171020001616734.png

包含的注解介绍

OnClick:实现点击事件

OnLongClick:实现长按事件

ColorById:找到对应的Color值

ContentViewById:实现SetContentView

StringById:找到对应的String值

ViewById:实现findViewById

CheckNet:实现网络检查功能

框架的使用

下面的这个Activity实现了框架的所有内容

@ContentViewById(R.layout.activity_main)

public class MainActivity extends AppCompatActivity {

@ViewById(R.id.bt_ioc)

private Button bt_ioc;

@StringById(R.string.app_name)

private String app_name;

@ColorById(R.color.colorAccent)

private int color;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

//IOC演示

InjectManager.inject(this);

bt_ioc.setText(app_name);

bt_ioc.setBackgroundColor(color);

}

//支持数组形式的绑定,绑定多个控件

@OnClick({R.id.open_ioc})

@OnLongClick({R.id.open_ioc})

@CheckNet()

public void open_ioc() {

Toast.makeText(this, "网络可用", Toast.LENGTH_SHORT).show();

}

}1234567891011121314151617181920212223242526272829

框架的实现

框架的实现分为两步:自定义注解的创建和通过反射进行注入

一、自定义注解

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface OnClick {

int[] value();

}

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface OnLongClick {

int[] value();

}

@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

public @interface ColorById {

int value();

}

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

public @interface ContentViewById {

int value();

}

@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

public @interface StringById {

int value();

}

@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

public @interface ViewById {

int value();

}

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface CheckNet {

}

Target注解的介绍

@Target(ElementType.XXX):代表的是注解放在XXX位置

@Target(ElementType.TYPE):接口、类、枚举、注解

@Target(ElementType.FIELD):字段、枚举的常量

@Target(ElementType.METHOD):方法

@Target(ElementType.PARAMETER):方法参数

@Target(ElementType.CONSTRUCTOR):构造函数

@Target(ElementType.LOCAL_VARIABLE):局部变量

@Target(ElementType.ANNOTATION_TYPE):注解

@Target(ElementType.PACKAGE):包

Retention注解的介绍

@Retention(Policy.RUNTIME):代表运行时检测,class文件中存在

@Retention(Policy.CLASS):代表编译时检测,存在于class文件中,运行时无法获取

@Retention(Policy.SOURCE):代表在源文件中有效(在.java文件中有效)

二、注入步骤

从使用中可以看到,注入中最重要的步骤的是:InjectManager.inject(this),这里主要负责的事情有

•注入ContentView

•注入变量

•注入事件

···

public class InjectManager {

public static void inject(Activity activity) {

inject(new ViewManager(activity), activity);

}

public static void inject(Fragment fragment) {

inject(new ViewManager(fragment), fragment);

}

/**

* 注入

*

* @param viewManager

* @param object

*/

private static void inject(ViewManager viewManager, Object object) {

InjectManagerService.injectContentView(viewManager, object);

InjectManagerService.injectField(viewManager, object);

InjectManagerService.injectEvent(viewManager, object);

}

···

这里会使用到ViewManager辅助类,代码很简单,后面会用到

···

public class ViewManager {

private Activity mActivity;

private Fragment mFragment;

private View mView;

public ViewManager(Activity activity) {

this.mActivity = activity;

}

public ViewManager(View view) {

this.mView = view;

}

public ViewManager(Fragment fragment) {

this.mFragment = fragment;

}

/**

* 通过Id查询View

*

* @param resId

* @return

*/

public View findViewById(int resId) {

View view = null;

if (mActivity != null) {

view = mActivity.findViewById(resId);

}

if (mFragment != null) {

view = mFragment.getActivity().findViewById(resId);

}

if (mView != null) {

view = mView.findViewById(resId);

}

return view;

}

/**

* 设置根布局,仅限Activity

*

* @param resId

*/

public void setContentView(int resId) {

if (mActivity != null) {

mActivity.setContentView(resId);

}

}

/**

* 获取颜色

*

* @param resId

*/

public int getColor(int resId) {

int color = -1;

if (mActivity != null) {

color = mActivity.getResources().getColor(resId);

}

if (mFragment != null) {

color = mFragment.getActivity().getResources().getColor(resId);

}

return color;

}

/**

* 获取字符串

*

* @param resId

*/

public String getString(int resId) {

String str = "";

if (mActivity != null) {

str = mActivity.getString(resId);

}

if (mFragment != null) {

str = mFragment.getActivity().getString(resId);

}

return str;

}

···

在InjectManagerService中,也是上面的三个主要步骤,主要还是下面通过反射实现其真正的效果

···

public class InjectManagerService {

/**

* 注入根布局

*

* @param viewManager

* @param object

*/

public static void injectContentView(ViewManager viewManager, Object object) {

injectContentViewById(viewManager, object);

}

/**

* 注入变量

*

* @param viewManager

* @param object

*/

public static void injectField(ViewManager viewManager, Object object) {

injectFieldById(viewManager, object);

}

/**

* 注入事件

*

* @param viewManager

* @param object

*/

public static void injectEvent(ViewManager viewManager, Object object) {

injectOnClick(viewManager, object);

injectOnLongClick(viewManager, object);

}

/**

* 注入根布局

*

* @param viewManager

* @param object

*/

private static void injectContentViewById(ViewManager viewManager, Object object) {

Class> clazz = object.getClass();

ContentViewById contentView = clazz.getAnnotation(ContentViewById.class);

if (contentView != null) {

int layoutId = contentView.value();

viewManager.setContentView(layoutId);

}

}

/**

* 注入findViewById事件

*

* @param viewManager

* @param object

*/

public static void injectFieldById(ViewManager viewManager, Object object) {

//1. 获取Activity字节码,这里以Activity为例

Class> clazz = object.getClass();

//2. 获取字节码中所有的成员变量

Field[] fields = clazz.getDeclaredFields();

if (fields != null) {

//3. 遍历所有变量

for (Field field : fields) {

//4. 找到对应的注解

ViewById viewById = field.getAnnotation(ViewById.class);

StringById stringById = field.getAnnotation(StringById.class);

ColorById colorById = field.getAnnotation(ColorById.class);

if (viewById != null) {

//5. 获取注解中的值

int viewId = viewById.value();

//6. findViewById并设置访问权限

View view = viewManager.findViewById(viewId);

field.setAccessible(true);

try {

//7. 动态注入到变量中

field.set(object, view);

} catch (IllegalAccessException e) {

e.printStackTrace();

}

}

if (stringById != null) {

int viewId = stringById.value();

String string = viewManager.getString(viewId);

field.setAccessible(true);

try {

field.set(object, string);

} catch (IllegalAccessException e) {

e.printStackTrace();

}

}

if (colorById != null) {

int viewId = colorById.value();

int color = viewManager.getColor(viewId);

field.setAccessible(true);

try {

field.set(object, color);

} catch (IllegalAccessException e) {

e.printStackTrace();

}

}

}

}

}

/**

* 注入点击事件

*

* @param viewManager

* @param object

*/

public static void injectOnClick(ViewManager viewManager, Object object) {

Class> clazz = object.getClass();

Method[] methods = clazz.getDeclaredMethods();

if (methods != null) {

for (Method method : methods) {

OnClick onClick = method.getAnnotation(OnClick.class);

if (onClick != null) {

int[] viewIds = onClick.value();

for (int viewId : viewIds) {

View view = viewManager.findViewById(viewId);

//检查网络

boolean isCheckNet = method.getAnnotation(CheckNet.class) != null;

if (view != null) {

view.setOnClickListener(new DeclaredOnClickListener(method, object, isCheckNet));

}

}

}

}

}

}

/**

* 注入长按事件

*

* @param viewManager

* @param object

*/

public static void injectOnLongClick(ViewManager viewManager, Object object) {

Class> clazz = object.getClass();

Method[] methods = clazz.getDeclaredMethods();

if (methods != null) {

for (Method method : methods) {

OnLongClick onLongClick = method.getAnnotation(OnLongClick.class);

if (onLongClick != null) {

int[] viewIds = onLongClick.value();

for (int viewId : viewIds) {

View view = viewManager.findViewById(viewId);

//检查网络

boolean isCheckNet = method.getAnnotation(CheckNet.class) != null;

if (view != null) {

view.setOnLongClickListener(new DeclaredOnLongClickListener(method, object, isCheckNet));

}

}

}

}

}

}

···

这里用到两个点击事件,并且将检查网络作为参数传进去到事件中处理,由于长按事件和点击事件大同小异,这里只贴一处代码

···

public class DeclaredOnLongClickListener implements View.OnLongClickListener {

private Method mMethod;

private Object mObject;

private boolean mIsCheckNet;

public DeclaredOnLongClickListener(Method method, Object object, boolean isCheckNet) {

this.mMethod = method;

this.mObject = object;

this.mIsCheckNet = isCheckNet;

}

@Override

public boolean onLongClick(View v) {

if (mIsCheckNet) {

if (!NetUtils.isNetworkAvailable(v.getContext())) {

Toast.makeText(v.getContext(), "网络不可用", Toast.LENGTH_SHORT).show();

return true;

}

}

//执行点击事件

try {

mMethod.setAccessible(true);

mMethod.invoke(mObject, v);

} catch (Exception e) {

e.printStackTrace();

try {

mMethod.invoke(mObject, null);

} catch (Exception e1) {

e1.printStackTrace();

}

}

return true;

}

···

结语

到这里IOC框架就结束了,其中比较重要的两点是注解的自定义和通过反射获取属性值并注入,其实代码挺简单的,反复看看还是挺容易理解的,大家可以结合源码进行阅读,其实在IOC路上还有权限的申请等功能可以实现,不过已经有第三方框架已经做好了

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值