本框架可以在Activity和Dialog中使用,并且已有代码示例。fragment读者自己加上就可以了,没写代码
package com.example.lsn_34;
import android.app.Activity;
import android.os.Bundle;
public class BaseActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//多态,继承BaseActivity类的类就不用重写了。
InjectUtils.inject(this);
}
}
package com.example.lsn_34;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
/**
* Created by david on 2017/8/21.
*/
public class BaseDialog extends Dialog {
public BaseDialog(@NonNull Context context) {
super(context);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
InjectUtils.inject(this);
}
}
package com.example.lsn_34;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)//运行时候有效,程序运行过程中要访问注解
@Target(ElementType.TYPE)//写到类上 面
public @interface ContentView {
//调用该方法就可以拿到MainActivity上面注解,即:@ContentView(R.layout.activity_main) 中的括号内的内容
int value();
}
package com.example.lsn_34;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 相当于java父类,
*/
@Retention(RetentionPolicy.RUNTIME)
//该注解在另外一个注解上使用
@Target(ElementType.ANNOTATION_TYPE)
public @interface EventBase {
// setOnClickListener 订阅
String listenerSetter();
// 事件以及他的类型
/**
* 事件监听的类型
* @return
*/
Class<?> listenerType();
/**
* 事件处理
* @return
*/
String callbackMethod();
}
package com.example.lsn_34;
import android.view.View;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//注入工具类,相当于我们的女朋友,负责找资源,把找到的资源交给Activity类。
public class InjectUtils {
//这个方法给Activity用
public static void inject(Object context){
//注入布局
injectLayout(context);
//注入组件
injectView(context);
//注入事件
injectClick(context);
}
/**
* 事件注入,事件注入比较复杂,因为android的事件不只一种。既要知道是哪一个控件,也要知道是哪一个事件
* 已OnCLick事件为例,我们分析下事件的三个要素
* textView.setOnClickListener(new View.OnClickListener() {
* @Override
* public void onClick(View v) {
* }
* });
* 事件源:TextView
* 事件:new View.OnClickListener()
* 事件处理:onClick
* 每个要素都要单独提取出来
* 另外有事件的订阅setOnClickListenner();
*/
private static void injectClick(Object context) {
//拿到Activity
Class<?> clazz=context.getClass();
//拿到该Activity所有的方法,然后遍历所有的方法,看看哪个方法有相关注解
Method[] methods=clazz.getDeclaredMethods();
for (Method method:methods)
{
// OnClick onClick = method.getAnnotation(OnClick.class);//这就写死了,不具备通用性
//得到方法上的所有注解
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation : annotations) {
// annotation ===OnClick OnClick.class
//得到注解的种类
Class<?> annotionClass=annotation.annotationType();
//是否能得到@EventBase的注解
EventBase eventBase = annotionClass.getAnnotation(EventBase.class);
//如果没有eventBase,则表示当前方法不是一个处理事件的方法
if(eventBase==null)
{
continue;
}
//开始获取事件处理的相关信息,即三要素
// 用于确定是哪种事件(onClick还是onLongClick)以及由谁来处理
//订阅
String listenerSetter=eventBase.listenerSetter();
//事件(事件监听的类型)
Class<?> listenerType=eventBase.listenerType();
//事件处理 事件被触发之后,执行的回调方法的名称
String callBackMethod=eventBase.callbackMethod();
/**
* 拿到三要素之后,我们就想办法执行这个事件
* textView.setOnClickListener(new View.OnClickListener() {
* @Override
* public void onClick(View v) {
*
* }
* });
* listenerSetter和callBackMethod是两个字符串,需要通过反射得到,同时要反射得到textView
*/
// int[] value1=OnClick.value();//这就写死了
Method valueMethod= null;
try {
//反射得到ID,再根据ID号得到对应的VIEW
valueMethod = annotionClass.getDeclaredMethod("value");
//得到在Activity的方法中标示的所有的ID,如@OnLongClick({R.id.app_text,R.id.app_text1})
int[] viewId= (int[]) valueMethod.invoke(annotation);
//每一个ID都需要事件绑定
for (int id : viewId) {
Method findViewById=clazz.getMethod("findViewById",int.class);
View view= (View) findViewById.invoke(context,id);
if(view==null)
{
continue;
}
//得到ID对应的VIEW以后
//开始在这个VIEW上执行监听,使用动态代理,将代码转移到Activity上的onClick(添加自定义注解的方法)上
//
//activity==context click==method
ListenerInvocationHandler listenerInvocationHandler = new ListenerInvocationHandler(context, method);
//proxy======View.OnClickListener()对象
Object proxy=Proxy.newProxyInstance(listenerType.getClassLoader(), new Class[]{listenerType}, listenerInvocationHandler);
//执行方法 setOnClickListener,new View.OnClickListener()
Method onClickMethod = view.getClass().getMethod(listenerSetter, listenerType);
onClickMethod.invoke(view, proxy);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
/**
* 控件注入
* @param context
*/
private static void injectView(Object context) {
//拿到对应的Activity
Class<?> aClass=context.getClass();
//拿到所有的成员变量,然后一一判断,判断哪些字段添加了 @ViewInject(R.id.app_text)注解
Field[] fields=aClass.getDeclaredFields();
//遍历成员变量
for (Field field:fields)
{
ViewInject viewInject = field.getAnnotation(ViewInject.class);
if (viewInject != null) {
int valueId = viewInject.value();
try {
Method method=aClass.getMethod("findViewById",int.class);
View view = (View) method.invoke(context, valueId);
// View view= mainActivity.findViewById(valueId);
field.setAccessible(true);
//Activity身上的字段field等于view即:context.field = view;
field.set(context,view);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
/**
* 布局注入
* @param context
*/
private static void injectLayout(Object context) {
int layoutId=0;//要注入的布局ID
//拿到MainActivity上面的注解,即:@ContentView(R.layout.activity_main)
/**
*我们知道在Java中一切都是对象,我们一般所使用的对象都直接或间接继承自Object类。
Object类中包含一个方法名叫 getClass,利用这个方法就可以获得一个实例的类型类。
类型类指的是代表一个类型的类,因为一切皆是对象,
类型也不例外,在Java使用类型类来表示一个类型。所有的类型类都是Class类的实例。
*
*/
Class<?> clazz=context.getClass();
ContentView contentView = clazz.getAnnotation(ContentView.class);
if (contentView != null) {
//得到Activity类的注解@ContentView(R.layout.activity_main)中括号内的信息
layoutId = contentView.value();
try {
//反射执行setContentView.
//int.class:参数是整数
// getMethod方法则根据方法名称和相关参数,来定位需要查找的Method对象并返回。
Method method = context.getClass().getMethod("setContentView", int.class);
//context 参数:实例化后的对象
method.invoke(context, layoutId);
} catch ( Exception e) {
e.printStackTrace();
}
}
}
}
package com.example.lsn_34;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 代理类
* 代理下面这段代码
* public boolean click(View view) {
* }
* 主体是Activity,要执行的是click动作
*/
public class ListenerInvocationHandler implements InvocationHandler {
// OnClickListener 1
// MainActivity 2
private Object activity;
//要执行的方法
private Method activityMethod;
public ListenerInvocationHandler(Object activity, Method activityMethod) {
this.activity = activity;
this.activityMethod = activityMethod;
}
/**
*按钮点下去就执行这个方法
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//在这里去调用被注解了的click()
return activityMethod.invoke(activity,args);
}
}
package com.example.lsn_34;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
@ContentView(R.layout.activity_main)
public class MainActivity extends BaseActivity {
@ViewInject(R.id.app_text)
private Button textView;
private Button textView1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Deprecated
@OnClick({R.id.app_text,R.id.app_text1})
public boolean click(View view) {
Toast.makeText(this,"---->"+textView,Toast.LENGTH_SHORT).show();
NewsDialog newsDialog = new NewsDialog(this);
newsDialog.show();
return false;
}
@OnLongClick({R.id.app_text,R.id.app_text1})
public boolean longClick(View view) {
Toast.makeText(this, "长按了", Toast.LENGTH_SHORT).show();
return true;
}
}
package com.example.lsn_34;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.Toast;
/**
* Created by david on 2017/8/21.
*/
@ContentView(R.layout.dialog_news)
public class NewsDialog extends BaseDialog {
@ViewInject(R.id.dialogBtn)
Button dialogBtn;
public NewsDialog(@NonNull Context context) {
super(context);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Toast.makeText(getContext(), "dialogBtn "+dialogBtn, Toast.LENGTH_SHORT).show();
}
@OnClick(R.id.dialogBtn)
public void click(View view) {
Toast.makeText(getContext(), " dialog点击啦", Toast.LENGTH_SHORT).show();
}
@Override
public void show() {
super.show();
/**
* 设置宽度全屏,要设置在show的后面
*/
WindowManager.LayoutParams layoutParams = getWindow().getAttributes();
layoutParams.gravity= Gravity.BOTTOM;
layoutParams.width= WindowManager.LayoutParams.MATCH_PARENT;
layoutParams.height= WindowManager.LayoutParams.WRAP_CONTENT;
getWindow().getDecorView().setPadding(0, 0, 0, 0);
getWindow().setAttributes(layoutParams);
}
}
package com.example.lsn_34;
import android.view.View;
import com.example.lsn_34.EventBase;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)//注解写在方法上
@EventBase(listenerSetter = "setOnClickListener"
, listenerType = View.OnClickListener.class
, callbackMethod = "onClick")
public @interface OnClick {
int[] value() default -1;
}
package com.example.lsn_34;
import android.view.View;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@EventBase(listenerSetter = "setOnLongClickListener", listenerType = View.OnLongClickListener.class, callbackMethod = "onLongClick")
public @interface OnLongClick {
int[] value() default -1;
}
package com.example.lsn_34;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Created by david on 24/2/2017.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)//写到成员变量上面
public @interface ViewInject {
int value();
}