打造属于自己的IOC注解框架

  • 效果

这里写图片描述

  • 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;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值