<h2>Give morning to myself</h2>
之前我们说了下反射的一些基础知识,基本已经可以来做一些简单的事情了。我们就在Android里面去尝试下怎么给控件做注解,实现类似Butterknife那样@BindView(R.id.xxx)public xxxType xxx;这样的控件注解...
开始之前我们了解几个概念:
1.之前我们通过反射获取到了Field,那么这个时候就需要知道如何给这个Field赋值
2.我们都知道,使用第三方控件需要implementation引入第三方(可能还需要添加jcenter等)或者直接使用jar包的方式(然后添加依赖) - 至于如何制作自己的开源项目并放到开源依赖仓库(bintray 发布相关)里面给别人用,后面再去学习这块! 这里我们先学习下创建自己的本地Module,然后专门实现注解模块,并提供init方法供注解使用-就仿Butterknife.bind(context);
第一个问题比较简单,Field的set方法就可以了
image
<h2>从工程开始</h2>
1.创建基本的Android工程(这个就不用怎么说了)
2.创建Android Library
image
image
3. app module引入模块,然后就可以使用第三方模块下面的相关api了
image
<h2>骚年Start</h2>
布局增加一个id
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/testSB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
然后mylibrary里面新建一个注解类for控件
image
BindView.java
package com.example.mylibrary;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Author: hl
* Time: 2018/5/23 11:12
* Des: This is BindView for widget.
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BindView {
int viewId();
}
App添加mylibrary模块依赖
image
MainActivity里面使用注解
package com.example.lieyun_android.myapplication;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import com.example.mylibrary.BindView;
public class MainActivity extends AppCompatActivity {
@BindView(viewId = R.id.testSB)
private TextView sb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
新建一个ButterKnife.java, 实现绑定注解,代码里面也增加了注释说明;一开始难理解可以多看看官方文档介绍,然后多记,多联系,自己多练习的时候尽量靠自己的理解去实现代码...
package com.example.mylibrary;
import android.app.Activity;
import android.content.Context;
import java.io.File;
import java.lang.reflect.Field;
/**
* Author: hl
* Time: 2018/5/23 11:21
* Des: This is not really ButterKnife
*/
public class ButterKnife {
/**
* 注解绑定
* @param context
*/
public static void bind(final Context context) {
///< 0\. 获取Class类
Class classObj = context.getClass();
///< 1.获取Field数组
//Field[] fields = classObj.getFields(); ///< 只能获取public声明的,ButterKnife用的应该是这种
Field[] fields = classObj.getDeclaredFields(); ///< public和private的都可以获取
for (Field field : fields){
///< 2.判断是否添加了BindView注解,如果是我们则可以获取控件id
if (field.isAnnotationPresent(BindView.class)){
///< 3.获取注解实例
BindView bindView = field.getAnnotation(BindView.class);
///< 4.获取上面的控件id
int viewId = bindView.viewId();
///< 判断下上下文类型吧!(真正的Butterknife在不同类型界面使用方法有区别)
if (context instanceof Activity){
///< 5.我们暂时用以前常用的findviewbyid来获取控件吧
Object viewObj = ((Activity)context).findViewById(viewId);
try {
///< 6.将获取的控件设置到file上面
///< 注意,如果控件类型声明的是private的,这里需要添加;
///< 如果是public的,可以不用添加;
//field.setAccessible(true);
field.set(context, viewObj);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
}
使用一下下
package com.example.lieyun_android.myapplication;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import com.example.mylibrary.BindView;
import com.example.mylibrary.ButterKnife;
public class MainActivity extends AppCompatActivity {
@BindView(viewId = R.id.testSB)
private TextView sb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
///< 注解绑定
ButterKnife.bind(this);
///< 使用下控件,么么哒
sb.setText("fuck sb");
}
}
到此搞定...
image
怎么可以像@BindView(R.id.xxx)那样,不要前面的viewId=?前面章节我们讲过,直接 int viewId() 修改为value
package com.example.mylibrary;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Author: hl
* Time: 2018/5/23 11:12
* Des: This is BindView for widget.
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BindView {
int value();
}
相应注解实现的地方
//int viewId = bindView.viewId();
int viewId = bindView.value();
定义就可以和ButterKnife一样了
//@BindView(viewId = R.id.testSB)
@BindView(R.id.testSB)
private TextView sb;
<h2>骚年Start Two</h2>
之前我们获取控件是通过直接findViewBy来的(还需要把context转换为activity),怎么通过反射来搞?
我们看下Method里面有个方法getMethod(String name, Class<?>... parameterTypes),可以获取指定的某个方法,第二个是参数需要传入参数类型
image
然后通过invoke执行这个方法获取控件
///< 5.我们暂时用以前常用的findviewbyid来获取控件吧
//Object viewObj = ((Activity)context).findViewById(viewId);
try {
///< 5.two 用反射获取方法,进而执行获取控件
Method method = classObj.getMethod("findViewById", int.class);
Object viewObj = method.invoke(context, viewId);
///< 6.将获取的控件设置到file上面
///< 注意,如果控件类型声明的是private的,这里需要添加;
///< 如果是public的,可以不用添加;
field.setAccessible(true);
field.set(context, viewObj);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
就是酱紫,我们的控件注解基本就从效果上仿了仿ButterKnife...这篇暂时先到这里,后面我们开始看下方法部分如何搞(最后部分已经提到了Invoke,后面也是重点围绕invoke相关弄的)!








网友评论