- 效果
-
java注解-ElementType详解
java中元注解有四个: @Retention @Target @Document @Inherited;
@Retention:注解的保留位置 (什么时候生效)
//注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.SOURCE)
//编译时注解: 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,
@Retention(RetentionPolicy.CLASS)
//运行时注解: 注解会在class字节码文件中存在,在运行时可以通过反射获取到
@Retention(RetentionPolicy.RUNTIME)
@Target:注解的作用目标
@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) ///包
@Document:说明该注解将被包含在javadoc中
@Inherited:说明子类可以继承父类中的该注解
- 布局注入注解
package tsou.cn.lib_hxgioc;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Created by huangxiaoguo on 2018/6/20 0020.
* <p>
* View 注解的Annotation
* <p>
* ElementType.FIELD
* 代表Annotation的位置,FIELD属性:字段、枚举的常量
*
* TYPE:接口、类、枚举、注解
* <p>
* RetentionPolicy.CLASS(什么时候生效)
* 编译时注解: 默认的保留策略,注解会在class字节码文件中存在,
* 但运行时无法获得
* RetentionPolicy.RUNTIME:运行时注解
* 注解会在class字节码文件中存在,在运行时可以通过反射获取到
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface HxgContentView {
//@HxgContentView(R.layout.activity_main)
int value();
}
- 属性 id注入注解
package tsou.cn.lib_hxgioc;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Created by huangxiaoguo on 2018/6/20 0020.
* <p>
* View 注解的Annotation
* <p>
* ElementType.FIELD
* 代表Annotation的位置,FIELD属性:字段、枚举的常量
* <p>
* RetentionPolicy.CLASS(什么时候生效)
* 编译时注解: 默认的保留策略,注解会在class字节码文件中存在,
* 但运行时无法获得
* RetentionPolicy.RUNTIME:运行时注解
* 注解会在class字节码文件中存在,在运行时可以通过反射获取到
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface HxgBind {
//@HxgBind(R.id.xxx)
int value();
}
- 方法注入注解(这里指的是点击事件)
package tsou.cn.lib_hxgioc;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Created by huangxiaoguo on 2018/6/20 0020.
* <p>
* View 事件注解的Annotation
* <p>
* ElementType.FIELD
* 代表Annotation的位置,FIELD属性:字段、枚举的常量
* METHOD:方法
* <p>
* RetentionPolicy.CLASS(什么时候生效)
* 编译时注解: 默认的保留策略,注解会在class字节码文件中存在,
* 但运行时无法获得
* RetentionPolicy.RUNTIME:运行时注解
* 注解会在class字节码文件中存在,在运行时可以通过反射获取到
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface HxgOnClick {
//@HxgOnClick(R.id.text_iv)
//@HxgOnClick({R.id.text_iv,R.id.btn})
int[] value();
}
- 方法注入注解(这里指的是检查网络)
package tsou.cn.lib_hxgioc;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Created by huangxiaoguo on 2018/6/20 0020.
* <p>
* View 事件注解的Annotation
* <p>
* ElementType.FIELD
* 代表Annotation的位置,FIELD属性:字段、枚举的常量
* METHOD:方法
* <p>
* RetentionPolicy.CLASS(什么时候生效)
* 编译时注解: 默认的保留策略,注解会在class字节码文件中存在,
* 但运行时无法获得
* RetentionPolicy.RUNTIME:运行时注解
* 注解会在class字节码文件中存在,在运行时可以通过反射获取到
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface HxgCheckNet {
int value();
}
- 定义注入接口
package tsou.cn.lib_hxgioc;
import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* Created by Administrator on 2018/6/20 0020.
*/
public interface HxgViewInjector {
/**
* 注入view
*
* @param view
*/
void inject(View view);
/**
* 注入activity
*
* @param activity
*/
void inject(Activity activity);
/**
* 注入view holder
*
* @param object view holder
* @param view
*/
void inject(View view,Object object);
/**
* 注入fragment
*
* @param fragment
* @param inflater
* @param container
* @return
*/
View inject(Object fragment, LayoutInflater inflater, ViewGroup container);
}
- FindViewById的辅助类
package tsou.cn.lib_hxgioc;
import android.app.Activity;
import android.view.View;
/**
* Created by Administrator on 2018/6/20 0020.
* <p>
* FindViewById的辅助类
*/
public class HxgViewHelper {
private Activity mActivity;
private View mView;
public HxgViewHelper(Activity activity) {
this.mActivity = activity;
}
public HxgViewHelper(View view) {
this.mView = view;
}
public View findViewById(int viewId) {
return mActivity != null ? mActivity.findViewById(viewId) : mView.findViewById(viewId);
}
}
- 实现注入方法
package tsou.cn.lib_hxgioc;
import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashSet;
import tsou.cn.lib_hxgioc.utils.NetUtils;
/**
* Created by Administrator on 2018/6/20 0020.
*/
public class HxgViewInjectorImpl implements HxgViewInjector {
private static final HashSet<Class<?>> IGNORED = new HashSet<Class<?>>();
static {
IGNORED.add(Object.class);
IGNORED.add(Activity.class);
IGNORED.add(android.app.Fragment.class);
try {
IGNORED.add(Class.forName("android.support.v4.app.Fragment"));
IGNORED.add(Class.forName("android.support.v4.app.FragmentActivity"));
} catch (Throwable ignored) {
}
}
private static HxgViewInjectorImpl instance;
private HxgViewInjectorImpl() {
}
public static void registerInstance() {
if (instance == null) {
synchronized (HxgViewInjectorImpl.class) {
if (instance == null) {
instance = new HxgViewInjectorImpl();
}
}
}
HxgViewUtils.hxgExt.setViewInjector(instance);
}
/**
* 注入view
*
* @param view
*/
@Override
public void inject(View view) {
inject(new HxgViewHelper(view), view);
}
/**
* 注入activity
*
* @param activity
*/
@Override
public void inject(Activity activity) {
inject(new HxgViewHelper(activity), activity);
}
/**
* 注入view holder
*
* @param object view holder
* @param view
*/
@Override
public void inject(View view, Object object) {
injectObject(new HxgViewHelper(view), object);
}
/**
* 注入fragment
*
* @param fragment
* @param inflater
* @param container
* @return
*/
@Override
public View inject(Object fragment, LayoutInflater inflater, ViewGroup container) {
View view = null;
Class<?> handlerType = fragment.getClass();
try {
HxgContentView contentView = findContentView(handlerType);
if (contentView != null) {
int viewId = contentView.value();
if (viewId > 0) {
view = inflater.inflate(viewId, container, false);
}
}
} catch (Throwable ex) {
ex.printStackTrace();
}
injectObject(new HxgViewHelper(view), fragment);
return view;
}
/**
* 兼容上面三个方法
* (注入view,注入activity,注入view holder)
*
* @param finder
* @param object 反射需要执行的类
*/
private static void inject(HxgViewHelper finder, Object object) {
inContentView(finder, object);
}
/**
* 注入ContentView
*
* @param finder
* @param object
*/
private static void inContentView(HxgViewHelper finder, Object object) {
Class<?> handlerType = object.getClass();
try {
HxgContentView contentView = findContentView(handlerType);
if (contentView != null) {
int viewId = contentView.value();
if (viewId > 0) {
Method setContentViewMethod = handlerType.getMethod("setContentView", int.class);
setContentViewMethod.invoke(object, viewId);
}
}
} catch (Throwable ex) {
ex.printStackTrace();
}
injectObject(finder, object);
}
/**
* 从父类获取注解View
*/
private static HxgContentView findContentView(Class<?> thisCls) {
if (thisCls == null || IGNORED.contains(thisCls)) {
return null;
}
HxgContentView contentView = thisCls.getAnnotation(HxgContentView.class);
if (contentView == null) {
return findContentView(thisCls.getSuperclass());
}
return contentView;
}
private static void injectObject(HxgViewHelper finder, Object object) {
if (object == null || IGNORED.contains(object)) {
return;
}
injectFiled(finder, object);
injectEvent(finder, object);
}
/**
* 注入属性
*
* @param finder
* @param object
*/
private static void injectFiled(HxgViewHelper finder, Object object) {
//1、获取类里面所有的属性
Class<?> aClass = object.getClass();
// 获取所有的属性包括私有和公有
Field[] fields = aClass.getDeclaredFields();
//2、获取viewById里面的value值
for (Field field : fields) {
HxgBind viewById = field.getAnnotation(HxgBind.class);
if (null != viewById) {
//获取注解里面的id值—>R.id.xxx
int viewId = viewById.value();
//3、findViewById找到View
View view = finder.findViewById(viewId);
if (null != view) {
//能够注入所有修饰符:private,public
field.setAccessible(true);
//4、动态的注入找到View
try {
field.set(object, view);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
/**
* 事件注入
*
* @param finder
* @param object
*/
private static void injectEvent(HxgViewHelper finder, Object object) {
//1、获取类里面所有的方法
Class<?> aClass = object.getClass();
Method[] methods = aClass.getDeclaredMethods();
//2、获取OnClick里面的value
for (Method method : methods) {
HxgOnClick onClick = method.getAnnotation(HxgOnClick.class);
if (null != onClick) {
int[] viewIds = onClick.value();
//能够注入所有方法:private,public
method.setAccessible(true);
for (int viewId : viewIds) {
//3、findViewById找到View
View view = finder.findViewById(viewId);
/**
* 扩展,检查网络
*/
HxgCheckNet checkNet = method.getAnnotation(HxgCheckNet.class);
int stringName = 0;
if (null != checkNet) {
stringName = checkNet.value();
}
boolean isCheckNet = checkNet != null;
if (null != view) {
//4、setOnClickListener
view.setOnClickListener(new DeclaredOnClickListner(method, object,
isCheckNet, stringName));
}
}
}
}
}
private static class DeclaredOnClickListner implements View.OnClickListener {
private Object mObject;
private Method mMethod;
private boolean mIsCheckNet;
private int mStringName;
public DeclaredOnClickListner(Method method, Object object, boolean isCheckNet, int stringName) {
this.mMethod = method;
this.mObject = object;
this.mIsCheckNet = isCheckNet;
this.mStringName = stringName;
}
@Override
public void onClick(View view) {
//检查网络
if (mIsCheckNet) {
if (!NetUtils.isNetworkConnected(view.getContext())) {
String context="网络不太给力~";
if (mStringName!=0){
context=view.getContext().getString(mStringName);
}
Toast.makeText(view.getContext(), context, Toast.LENGTH_LONG).show();
return;
}
}
//5、反射注入方法
try {
mMethod.invoke(mObject, view);
} catch (Exception e) {
e.printStackTrace();
//mMethod.invoke(mObject, null);
}
}
}
}
- 获得注入事件类
package tsou.cn.lib_hxgioc;
/**
* Created by Administrator on 2018/6/20 0020.
*/
public class HxgViewUtils {
private HxgViewUtils() {
}
public static HxgViewInjector getView() {
if (hxgExt.viewInjector == null) {
HxgViewInjectorImpl.registerInstance();
}
return hxgExt.viewInjector;
}
static class hxgExt{
private static HxgViewInjector viewInjector;
private hxgExt() {
}
public static void setViewInjector(HxgViewInjector viewInjector) {
hxgExt.viewInjector = viewInjector;
}
}
}
- Activity中使用
package tsou.cn.zidinyidemo;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;
import tsou.cn.lib_hxgioc.HxgBind;
import tsou.cn.lib_hxgioc.HxgCheckNet;
import tsou.cn.lib_hxgioc.HxgContentView;
import tsou.cn.lib_hxgioc.HxgOnClick;
import tsou.cn.lib_hxgioc.HxgViewUtils;
@HxgContentView(R.layout.activity_main)
public class MainActivity extends AppCompatActivity {
@HxgBind(R.id.text_iv)
private TextView mTextIv;
@HxgBind(R.id.fl_main)
private FrameLayout mFlMain;
private FragmentManager fragmentManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
HxgViewUtils.getView().inject(this);
mTextIv.setText("haungxiaoguo");
fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.fl_main, new MyFragment())
.commitAllowingStateLoss();
}
@HxgOnClick(R.id.text_iv)
@HxgCheckNet(R.string.net_net_string)
private void onClick(TextView view) {
Toast.makeText(this, "点击了TextView", Toast.LENGTH_LONG).show();
}
@HxgOnClick({R.id.btn})
private void onClick(Button view) {
Toast.makeText(this, "点击了Button", Toast.LENGTH_LONG).show();
}
}
- Fragment中使用
package tsou.cn.zidinyidemo;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import tsou.cn.lib_hxgioc.HxgBind;
import tsou.cn.lib_hxgioc.HxgCheckNet;
import tsou.cn.lib_hxgioc.HxgContentView;
import tsou.cn.lib_hxgioc.HxgOnClick;
import tsou.cn.lib_hxgioc.HxgViewUtils;
/**
* Created by Administrator on 2018/6/20 0020.
*/
@HxgContentView(R.layout.layout_fragent)
public class MyFragment extends Fragment {
@HxgBind(R.id.btn_frist)
private Button mBtnFrist;
@HxgBind(R.id.tv_frist)
private TextView mTvFrist;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View mView = HxgViewUtils.getView().inject(this, inflater, container);
mBtnFrist.setText("button");
mTvFrist.setText("textView");
return mView;
}
@HxgOnClick(R.id.btn_frist)
@HxgCheckNet(R.string.net_net_string)
private void onClick(Button button) {
Toast.makeText(getContext(), "点击了button", Toast.LENGTH_LONG).show();
}
@HxgOnClick(R.id.tv_frist)
private void onClick(TextView textView) {
Toast.makeText(getContext(), "点击了textView", Toast.LENGTH_LONG).show();
}
}
- 另附检查网络方法
package tsou.cn.lib_hxgioc.utils;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
/**
* Created by Administrator on 2018/6/20 0020.
*/
public class NetUtils {
/**
* 判断网络是否可用
*
* @param context
* @return
*/
public static boolean isNetworkConnected(Context context) {
if (context != null) {
ConnectivityManager mConnectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
if (mNetworkInfo != null) {
return mNetworkInfo.isAvailable();
}
}
return false;
}
}