Java反射与注解(二)实战

一、前言

我们在安卓开发中,初始学习时我们可能会写findViewById写的想吐,而后来我们可能会使用Xutils或ButterKnife优化findViewById,但是使用别人的库往往不能定制开发,因此我们在掌握了解反射和注解,在学习本文。

二、优化findViewById和点击事件

(1)创建点击注解类,这里可以传入id集合

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface OnClick {
    int[] value();
}

(2)创建绑定id类

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

(3)findViewById类,针对Activity和View区分

/**
 * findViewById
 */
public class ViewFinder {
    private Activity mActivity;
    private View mView;

    public ViewFinder(Activity activity) {
        mActivity = activity;
    }

    public ViewFinder(View view) {
        mView = view;
    }

    public View findViewById(int viewId) {
        return mActivity != null ? mActivity.findViewById(viewId) : mView.findViewById(viewId);
    }
}

(4)工具类,调用此方法,才会将事件进行绑定,可以调用

public class BindUtils {

    //绑定至Activity中
    public static void bind(Activity activity) {
        bind(new ViewFinder(activity), activity);
    }

    //绑定至View中
    public static void bind(View view) {
        bind(new ViewFinder(view), view);
    }

    //绑定至Fragment中
    public static void bind(View view, Object object) {
        bind(new ViewFinder(view), object);
    }

    //通用方法
    public static void bind(ViewFinder viewFinder, Object object) {
        bindFiles(viewFinder, object);
        bindMethods(viewFinder,object);
    }

    //处理点击按钮事件
    private static void bindMethods(ViewFinder viewFinder, final Object object) {
        //获取Class对象
        Class aClass = object.getClass();
        //反编译获取所以方法
        Method[] methods = aClass.getDeclaredMethods();
        if (null!=methods){
            for (final Method method : methods) {
                //获取Annotation
                final OnClick onClick = method.getAnnotation(OnClick.class);
                if (null!=onClick){
                    int[] values = onClick.value();
                    for (int value : values) {
                        View view = viewFinder.findViewById(value);
                        view.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                try {
                                    //解除私有限制
                                    method.setAccessible(true);
                                    //执行点击事件
                                    method.invoke(object,v);
                                } catch (IllegalAccessException e) {
                                    e.printStackTrace();
                                } catch (InvocationTargetException e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                    }

                }
            }
        }
    }

//绑定属性
    private static void bindFiles(ViewFinder viewFinder, Object object) {
        Class aClass = object.getClass();
        Field[] fields = aClass.getDeclaredFields();
        if (null != fields) {
            for (Field field : fields) {
                BindView bindView = field.getAnnotation(BindView.class);
                if (null != bindView) {
                    int viewId = bindView.value();
                    View view = viewFinder.findViewById(viewId);
                    if (null != view) {
                        try {
                            field.setAccessible(true);
                            field.set(object, view);
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}

(5)在Activity、View、Fragment中调用BindUtils,这里的布局就是一个文本2个按钮。

public class MainActivity extends AppCompatActivity {

    @BindView(R.id.tv_msg)
    private TextView mTvMsg;

    @OnClick({R.id.btn_click1, R.id.btn_click2})
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn_click1:
                Toast.makeText(this, "toast1", Toast.LENGTH_SHORT).show();
                break;
            case R.id.btn_click2:
                Toast.makeText(this, "toast2", Toast.LENGTH_SHORT).show();
                break;
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        BindUtils.bind(this);
        mTvMsg.setText("测试BindViw!!!");
    }
}

三、扩展

扩展这块具体不多整理,例如我们可以写长按事件,我们还可以在点击前进行网络判断,权限判断申请等操作,根据个人需求进行扩展。

另外,现在目前的方式总归造成了软件的性能降低,因此我们可以使用annotationProcessor替代这种方式。

你可能感兴趣的:(Java反射与注解(二)实战)