Android-自定义注解-控件注解

作者: MonkeyLei | 来源:发表于2019-07-10 10:20 被阅读1次

<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();
                    }
                }
            }
        }
    }
}

使用一下下

MainActivity.java

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相关弄的)!

相关文章

  • Android-自定义注解-反射基础

    Let’s go 上一章Android-自定义注解-注解基础-自定义注解我们基本上入门了这个注解的基本的东西,具体...

  • Android-自定义注解-控件注解

    Give morning to myself 之前我们说了下反射的一些基础知识,基本已经可以来做一些简单的事情了。...

  • 反射与注解实现控件注入

    概述 本文主要分享基于注解和反射实现控件注入。 实现思路: 自定义BindView注解标记需要注入的控件 查找页面...

  • 注解学习笔记

    什么是注解注解分类注解作用分类 元注解 Java内置注解 自定义注解自定义注解实现及使用编译时注解注解处理器注解处...

  • 【JAVA】注解

    元注解 用来定义、声明注解的注解。 @Inherited注解 使用此注解声明出来的自定义注解,在使用此自定义注解时...

  • 2016.10.13-关于注解的自定义和注解的解析

    注解可以分为:1、标识性注解(没有成员变量) 2、注解 3、元注解(注解的注解) 1、注解的自定义 自定义注解的格...

  • Android进阶之自定义注解

    Android进阶之自定义注解 本篇文章内容包括: 注解的概念 元注解 自定义注解 Android自定义编译时注解...

  • 模仿java的@Test

    定义注解 使用自定义注解 解析注解

  • hibernate Validator自定义注解

    如何自定义注解,加入自己的校验逻辑 自定义注解 自定义注解校验类

  • Android-自定义注解-注解基础-元注解

    乱七八糟的准备一下 学习这个之前,以前很多时候都是搜视频,博客啥的。现在我们尽量从官方文档入手,再配合一些别的进行...

网友评论

    本文标题:Android-自定义注解-控件注解

    本文链接:https://www.haomeiwen.com/subject/vtsckctx.html