Android进阶 (一)打造一套自己的IOC注解框架
首先看看效果和library的最终结构:
项目最终结构:
1.在自己的项目--->右键new moudle--->Android Library,然后新建一个class,图片上注释很详细:
2.新建MaxBind类,用于绑定当前的Activity或Fragment或者自定义的View等:
public class MaxBind {
public static void bind(Activity activity){
bind(new ViewFinder(activity),activity);
}
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);
}
//兼容上面三个方法 object:反射需要执行的类
private static void bind(ViewFinder finder,Object object){
bindField(finder,object);//动态注入属性
bindEvent(finder,object);//动态注入事件
}
private static void bindEvent(ViewFinder finder, Object object) {
//1.获取类里面所有的方法
Class<?> clazz = object.getClass();
Method[] methods = clazz.getDeclaredMethods();
//2.获取BindOnClick的里面的value值
for (Method method : methods){
BindOnClick onClick = method.getAnnotation(BindOnClick.class);
if (onClick != null){
int[] valueIds = onClick.value();
for (int viewId : valueIds){
//3.findViewById()找到View
View viewById = finder.findViewById(viewId);
//检测网络
boolean isCheckNet = method.getAnnotation(CheckNet.class) != null;//有没有加这个注解
if (viewById != null){
//4.view.setOnClickListener
viewById.setOnClickListener(new DeclaredOnClickListener(method,object,isCheckNet));
}
}
}
}
}
private static void bindField(ViewFinder finder, Object object) {
//1.获取类里面所有属性
Class<?> clazz = object.getClass();
Field[] fields = clazz.getDeclaredFields();//获取所有属性包括公有和私有的
//2.获取findViewById()里面的value值
for (Field field : fields){
BindView bindView = field.getAnnotation(BindView.class);
if (bindView != null){
int id = bindView.value();//获取注解里面的id值(R.id.xxx)
//3.findViewById()找到View
View view = finder.findViewById(id);
if (view != null){
field.setAccessible(true);//能够注入所有的修饰符(private,protected,public等)
//4.动态的注入找到的View
try {
field.set(object,view);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
private static class DeclaredOnClickListener implements View.OnClickListener{
private Object object;
private Method method;
private boolean isCheckNet;
public DeclaredOnClickListener(Method method, Object object, boolean isCheckNet) {
this.object = object;
this.method = method;
this.isCheckNet = isCheckNet;
}
@Override
public void onClick(View v) {
//需要检测网络?
if (isCheckNet){
if (!networkAvailable(v.getContext())){
//这里别写死,外部配置
Toast.makeText(v.getContext(),"当前没网",Toast.LENGTH_SHORT).show();
return;
}
}
//最终点击会调这个方法
try {
method.setAccessible(true);
//5.反射执行方法
method.invoke(object,v);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
try {
method.invoke(object,null);//防止没传入View崩掉
} catch (IllegalAccessException | InvocationTargetException e1) {
e1.printStackTrace();
}
}
}
}
private static boolean networkAvailable(Context context){
ConnectivityManager connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (null != connectivity) {
NetworkInfo info = connectivity.getActiveNetworkInfo();
if (null != info && info.isConnected()) {
if (info.getState() == NetworkInfo.State.CONNECTED) {
return true;
}
}
}
return false;
}
}
3.新建ViewFinder辅助类,用于findViewById的辅助:
到这里为止,一个最基本的IOC注解框架就完成了,接下来是用法:
①:activity_ioc.xml: 就只有简单的几个控件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:id="@+id/iocFrameLayout">
</FrameLayout>
<Button
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_gravity="center_horizontal"
android:id="@+id/iocBtn"
/>
<ImageView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_gravity="center_horizontal"
android:id="@+id/iocIv"
android:src="@mipmap/ic_launcher"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:id="@+id/iocTv"
android:text="测试文字"
android:textSize="22sp"
/>
</LinearLayout>
②:IocActivity.class:
public class IocActivity extends AppCompatActivity {
@BindView(R.id.iocBtn)
Button iocBtn;
@BindView(R.id.iocIv)
private ImageView iocIv;
@BindView(R.id.iocTv)
protected TextView iocTv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ioc);
MaxBind.bind(this);
iocBtn.setText("佛祖保佑,永无BUG");
}
@BindOnClick({R.id.iocBtn,R.id.iocIv})
private void Click(View view){
switch (view.getId()){
case R.id.iocBtn:
ToastUtil.showShort(this,"Button被点击",1);
break;
case R.id.iocIv:
ToastUtil.showShort(this,"ImageView被点击",2);
break;
default:
break;
}
}
@BindOnClick(R.id.iocTv)
@CheckNet //没网就不执行
private void iocBtnClick(View view){
ToastUtil.showShort(this,iocTv.getText().toString(),3);
}
}
Fragment和自定义View里面也是类似的用法;