您的位置:首页 > 其它

安卓进阶之自己实现 ViewInject框架

2015-05-18 11:12 148 查看
以前做web开发的时候经常用得到的就是SSH框架,即struts2、spring、hibernate三大框架,他们分别负责了不同的层的业务逻辑,其中spring框架是我觉得最猛的一个框架,它几乎贯穿到整个web开发中,而它的特色功能就是IOC、AOP等,AOP是面向切面编程,根据动态代理技术来动态管理我们的java代码,功能非常强大。IOC是控制反转,为什么叫控制反转呢?因为我们一般实例化一个对象都是自己手动通过new来实现,而spring通过自己的IOC技术就可以通过配置或者注解的方法来帮助我们new一个对象,使我们不用关注实例化对象的方法,从而注重程序的业务逻辑,在一方面也能达到很好的解耦作用。

现在安卓中也引入了IOC技术,可以在网上下载到ViewInject项目来使用我们的IOC功能,于是我们又多了一个新技能,使用别人写的ViewInject框架。程序员中有一句话叫做不要重复的制造轮子,我们大多数程序员都是拿来主义,只要功能实现就行,而不去管其中的原理,不自己是考虑一下怎么实现的,但叫自己做的话能不能实现呢?于是我决定动手实现ViewInject框架,虽然比较简陋,但是自己的东西写出来才是硬道理哇。

要实现ViewInject框架需要了解一下java中反射的概念,所谓反射其实就是通过非new的方式来获取我们的属性、方法等内容,同时也可以通过反射来实例化一个对象,功能非常强大,是设计框架的必备良药。通过几个例子来说明:

//有一个A类,我们传统的可以通过new A来获取对象,并且调用里面的方法或者属性
//主要有一个name属性,它是私有的,如果通过new的方法还能调用吗?
class A {
private int age = 100;
private String name = "私有属性";

public void sayHellow() {
System.out.println("你好");
}

}
//如果需要调用里面的私有属性或者私有方法,则需要通过法神来实现:
public static void main(String[] args) throws Exception {
Class<A> clazz = A.class;
// 实例化一个A对象
A a = clazz.newInstance();
// 获取所有的属性(包括私有属性),也可以使用getFields方法,但是这样不能
// 获取到私有属性
Field[] fileds = clazz.getDeclaredFields();
for (Field f : fileds) {
// 如果需要访问私有属性,这里必须要设置为true
f.setAccessible(true);
System.out.println(f.get(a));
}
// 获取所有的方法(包括私有方法),也可以使用getMethods方法,但是这样不能
// 获取到私有方法
Method[] methods = clazz.getDeclaredMethods();
for (Method m : methods) {
// 如果需要访问私有方法,这里必须要设置为true
m.setAccessible(true);
m.invoke(a, null);
}
}
打印结果:
100
私有属性
你好


可以看到通过反射能够正常访问私有属性,私有方法等,非常厉害!

我们在整合SSH框架的时候有时候为了简化经常使用注解的方式,注解英文名幼教Annotation,非常好用,用法也很简单,这里略过。。。

下面就是实现自己的ViewInject框架了

首先看一下我们使用自己的框架的代码:

@ContentView(R.layout.activity_main)//这里使用了注解
public class MainActivity extends Activity {
@ViewInject(R.id.tv1)//这里使用了注解
private TextView tv;
@ViewInject(R.id.btn1)//这里使用了注解
private Button btn;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewUtil.inject(this);//自定义的工具类
tv.setText("通过自定义矿建实现的");
}

@OnClick({ R.id.btn1, R.id.btn2 })//这里使用了注解
public void btn(View view) {
switch (view.getId()) {
case R.id.btn1:
Toast.makeText(getApplicationContext(), "点击了按钮1",
Toast.LENGTH_SHORT).show();
break;
case R.id.btn2:
Toast.makeText(getApplicationContext(), "点击了按钮2",
Toast.LENGTH_SHORT).show();
break;
}
}

}


可以看到我们总共有三个注解类型:ContentView、ViewInject、OnClick以及一个ViewUtil工具类

首先定义自己的ContentView注解类型:

//运行环境,此处是运行时
@Retention(RetentionPolicy.RUNTIME)
// 此处表示注解可以存放的位置,此处设置为在类上
@Target(ElementType.TYPE)
public @interface ContentView {
int value();
}


定义ViewInject类型:

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


定义OnClick类型:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface OnClick {
//此处返回一个数据表示可以通过定义多个
int[] value();
}


最后使我们的核心控制类:

/**
* 核心控制类
*
* @author leilu
*
*/
public class ViewUtil {

/**
* 开始注解
*
* @param activity
*/
public static void inject(Activity activity) {
// 判断对应的Activity上面是否使用了ContentView注解
if (activity.getClass().isAnnotationPresent(ContentView.class)) {
// 如果加了注解则转换为ContentView注解
ContentView contentView = activity.getClass().getAnnotation(
ContentView.class);
int layoutResID = contentView.value();// 获取布局的资源id
activity.setContentView(layoutResID);// 设置布局内容
findView(activity);// 绑定view
registEvent(activity);// 注册点击事件
}
}

/**
* 注册点击事件
*
* @param activity
*/
private static void registEvent(final Activity activity) {
// 获取所有的方法
Method[] method = activity.getClass().getMethods();
for (final Method m : method) {
// 判断方法上面使用存在OnClick注解
if (m.isAnnotationPresent(OnClick.class)) {
// 如果存在则转换
OnClick on = m.getAnnotation(OnClick.class);
int[] values = on.value();// 获取需要绑定点击事件的控件id
for (int i = 0; i < values.length; i++) {
final View view = activity.findViewById(values[i]);
// 给其设置点击事件
view.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
try {
m.invoke(activity, view);// 调用activity里面的方法
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
}
}

/**
* 绑定view控件
*
* @param activity
*/
private static void findView(Activity activity) {
// 获取所有属性
Field[] fields = activity.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
// 判断属性上面是否存在ViewInject注解
if (field.isAnnotationPresent(ViewInject.class)) {
ViewInject vi = field.getAnnotation(ViewInject.class);
int resourceId = vi.value();// 获取控件资源id
try {
field.set(activity, activity.findViewById(resourceId));// 绑定控件
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}


OK,自定义框架实现完毕!看看效果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: