IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android APT的学习和使用(二) -> 正文阅读

[移动开发]Android APT的学习和使用(二)

实现类似ButterKnife 为控制绑定id

前言

??之前写的第一篇文章 Android APT的学习和使用(一)初步了解kotlin下怎么编写注解并自动生成代码,这次继续实践一下,实现类似BufferKnife 在字段前添加注解自动为我们完成绑定id的功能,在此记录一下。

一、概览

1. 想要实现的效果

在这里插入图片描述
??我们使用注解,在里面传入控件的id,然后就会自动为我们绑定控件,我们在代码里就不用再写findViewById(R.id.xx)这样的代码了.

2. 项目结构

因为是在我这个打算代代相传的demo项目里编写的,所以上一篇文章的项目结构一致
在这里插入图片描述

3.使用kotlinpoet生成的最终代码

??这个代码需要实现的功能、名字、传入的参数等等都要提前想好,保证能够正确执行,最好先自己建个类,然后手动调用该类,确保能够准确执行了,然后再将该代码作为模板,在BindViewProcessor中用kotlinpoet生成代码。

public class AptActivityBinding {
  public fun bind(activity: AptActivity): Unit {
    activity.textView1 = activity.findViewById(2131230798)
    activity.button1 = activity.findViewById(2131230797)
  }
}

二、实现

1. 定义注解

因为是在字段上使用,所以Target用AnnotationTarget.FIELD

@Retention(AnnotationRetention.SOURCE)
@Target(AnnotationTarget.FIELD)
annotation class BindView(val value: Int)

2. 继承AbstractProcessor处理注解并生成我们想要的代码

@AutoService(Processor::class)
@SupportedOptions("MODULE_NAME")
@SupportedAnnotationTypes("com.wzy.apt_annotation.BindView")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
class BindViewProcessor : AbstractProcessor() {
    private var mFiler: Filer? = null

    override fun init(processingEnvironment: ProcessingEnvironment?) {
        super.init(processingEnvironment)
        processingEnvironment?.apply {
            mFiler = filer
        }
    }

    override fun process(p0: MutableSet<out TypeElement>?, p1: RoundEnvironment?): Boolean {
        if (p0.isNullOrEmpty()) return false

        // 构建一个kt文件存放生成的类
        val ktFile = FileSpec.builder("com.wzy.demo", "BindViewAutoCreateFile")

        //获取全部的类
        p1?.rootElements?.forEach {
            //获取类的包名
            val packageName = it.enclosingElement.toString()
            //获取类的名字
            val className = it.simpleName.toString()
            //构建新的类: 原类名+Binding
            val newClassName = ClassName(packageName,"${className}Binding")

            //构建bind(activity: XXXActivity)函数
            val bindFuncitonBuilder = FunSpec.builder("bind")
                .addModifiers(KModifier.PUBLIC)
                .returns(Unit::class)
                .addParameter("activity", ClassName(packageName, className))

            //判断该类下是否使用了BindView注解从而判断是否需要生成代码
            var skip = true
            it.enclosedElements.forEach { enclosedElemnet ->
                if (enclosedElemnet.kind == ElementKind.FIELD) {
                    enclosedElemnet.getAnnotation(BindView::class.java)?.let { bindViewAnnotation ->
                        skip = false
                        bindFuncitonBuilder.addStatement(
                            "activity.%N = activity.findViewById(%L)",
                            enclosedElemnet.simpleName,bindViewAnnotation.value
                        )
                    }
                }
            }

            //是否跳过生成代码
            if (!skip) {
                //构建新的类
                val classBuilder = TypeSpec.classBuilder(newClassName)
                    .addFunction(bindFuncitonBuilder.build())

                //往BindViewAutoCreateFile.kt文件中写入该类
                ktFile.addType(classBuilder.build())
            }

        }

        try {
            mFiler?.let {
                ktFile.build().writeTo(it)
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }

        return true
    }

}

3. 编译项目

查看是否生成我们想要的代码
在这里插入图片描述
在这里插入图片描述
? ?代码已经生成好了,只要传入activity对象,我们就可以拿到View,然后手动调用findViewById()方法为他们绑定id。
?

4. 封装Api

??上面说到我们需要调用生成的XXXActivityBinding的bind()方法,并且传入activity就算完成。这种操作肯定不需要我们自己去写,不然每个Activity会生成自己的Binding类,每次调用都要new一个XXXActivityBinding类,然后还要调用该方法。虽然说不是不可以,但是ButterKnife只需要在执行一行代码ButterKnife.bind(this)就可以完成自动绑定,根本不需要管是哪个类,这种api调用明显方便的多。
??所以我们可以写一个api,利用反射帮我们去new XXXActivityBinding,然后执行bind()方法。

object ButterKnifeApi {
    fun bind(activity: Activity) {
        try {
            //获取注解为我们生成的Binding类
            val activityBinding = Class.forName("${activity.packageName}.${activity.javaClass.simpleName}Binding")
            //拿到bind()方法
            val bindFunction = activityBinding.getMethod("bind", activity.javaClass)
            //调用该方法
            bindFunction.invoke(activityBinding.newInstance(), activity)
        } catch (e: Exception) {
            e.printStackTrace()
        }

    }
}

使用和ButterKnife一样,调用ButterKnifeApi.bind(this)就可以了。

5.示例

class AptActivity : AppCompatActivity() {

    @BindView(R.id.aptTextView1)
    lateinit var textView1: TextView

    @BindView(R.id.aptButton1)
    lateinit var button1: Button

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_apt)
        initViewByBinding()
    }

    private fun initViewByBinding() {
        ButterKnifeApi.bind(this)
        button1.setOnClickListener {
            textView1.text = "绑定成功"
        }
    }
}

在这里插入图片描述

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-07-10 11:35:50  更:2021-07-10 11:36:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 10:12:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码