资讯专栏INFORMATION COLUMN

自定义Android注解Part3:绑定

harriszh / 3286人阅读

摘要:上一节我们已经将自动生成注解代码部分介绍完毕,今天这篇文章是自定义注解系列的最后一篇文章。该部分是对我们前面定义的注解变量与自动生成的代码进行绑定,即调用我们自动生成的代码。

上一节我们已经将自动生成注解代码部分介绍完毕,今天这篇文章是自定义Android注解系列的最后一篇文章。希望大家这一路走来有所收获。

经过前面的了解,我们三大部分:butterknife-annotations、butterknife-compiler与butterknife-bind。现在就剩下最后一部分butterknife-bind。该部分是对我们前面定义的注解变量与自动生成的代码进行绑定,即调用我们自动生成的代码。

那么我们还是来看下butterknife-bind模板库的结构:

只有Butterknife一个类,在这之前我们还需将前面我们已经定义好的module引入

dependencies {
    ...
    compile project(path: ":butterknife-annotations")
}

有了之前的基础,我们Make Project项目工程,之后就可以找到MainActivity$Binding类,或者直接在/app/build/generated/source/kapt/debug/目录下查找。

Bind

MainActivity$Binding在构造方法中就已经调用了我们的需要的bindView与setOnClickListener方法。所以我们需要使用的话只需实例化即可。但由于我们是该类是通过注解处理器自动生成的,所以我们并不知道它的类名全称(这里我们相当于查看了源码,才知道是以$Binding结尾)。这样我们是不能通过new关键字来实例化。如此,我们又该如何实例化它呢?这时我们再来看butterknife-bind中的唯一的类Butterknife

public class Butterknife {
 
    private Butterknife() {
 
    }
 
    private static  void initialization(T target, String suffix) {
        Class tClass = target.getClass();
        String className = tClass.getName();
        try {
            Class bindingClass = tClass.getClassLoader().loadClass(className + suffix);
            Constructor constructor = bindingClass.getConstructor(tClass);
            constructor.newInstance(target);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
 
    public static void bind(Activity activity) {
        initialization(activity, ConstantUtils.BINDING_BUTTERKNIFE_SUFFIX);
    }
}

在initialization方法中,我们通过java反射来实例化我们需要的MainActivity$Binding。既然我们已经知道自动生成的类是由原始类(MainActivity)+后缀($Binding)组成。所以可以很好的使用java反射来实例化所需的类。对于外界的调用只需使用bind方法,传入需要绑定的类即可。

Use

到这里,所以的准备工作已经完成。接下来我们可以开始在MainActivity中使用。首先将定义的库进行依赖

dependencies {
    ...
    implementation project(":butterknife-bind")
    kapt project(":butterknife-compiler")
}

然后在MainActivity中使用

class MainActivity : AppCompatActivity() {
 
    @BindView(R.id.public_service, R.string.public_service)
    lateinit var sName: TextView
 
    @BindView(R.id.personal_wx, R.string.personal_wx)
    lateinit var sPhone: TextView
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        Butterknife.bind(this)
    }
 
    @OnClick(R.id.public_service)
    fun nameClick(view: View) {
        Toast.makeText(this, getString(R.string.public_service_click_toast), Toast.LENGTH_LONG).show()
    }
 
    @OnClick(R.id.personal_wx)
    fun phoneClick(view: View) {
        Toast.makeText(this, getString(R.string.personal_wx_click_toast), Toast.LENGTH_LONG).show()
    }
}

我们使用@BindView绑定View的Id与默认值;使用@OnClick绑定点击事件;使用Butterknife.bind(this)绑定自定义的注解代码。这样我们已经完成了与开源库Butterknife相似的功能。

progurad

现在你在模拟器或者真机上跑着非常完美,然后你不小心切换到release版本并且开启了混淆功能。这时你会发现mmp居然没有效果。为什么呢?debug与release的区别,绝大数情况下都是混淆惹的祸。我们在实例化自动生成的类时使用的是java反射机制,所以一旦混淆了我们的java反射就找不到我们指定的类名,这样自然也就没有效果了。

那么我们现在又该如何解决呢?别急,是否还记得在系列的Part1我们自定义注解变量中定义了@Keep

在MainActivity$Binding类上我们使用了@Keep来标识该类,通过该标识告诉proguard不去混淆使用@Keep标记的类。要达到这种效果,我们还需经过以下两个步骤:

1.在butterknife-bind的proguard-rules.pro文件中添加如下代码

-keep class com.idisfkj.butterknife.annotations.Keep**
-keep @com.idisfkj.butterknife.annotations.Keep public class *
-keepclassmembers @com.idisfkj.butterknife.annotations.Keep class ** {*;}

2.为了是依赖库的混淆生效,我们还需使用consumerProguardFiles声明

    defaultConfig {
        ...
        consumerProguardFiles "proguard-rules.pro" //依赖库混淆生效
    }

完成这两步后我们在重新构建release版本,这时程序完美运行。终于可以轻松的休息会了!

End

自定义Android注解系列完美收工,希望通过这三部曲能够帮助大家学会如何实现注解库。最后希望大家点赞支持一下,谢谢!

文章中的代码都可以在Github中获取到。使用时请将分支切换到feat_annotation_processing

相关文章

自定义Android注解Part1:注解变量

自定义Android注解Part2:代码自动生成

关注

公众号:怪谈时间到了

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/14312.html

相关文章

  • 定义Android注解Part3:绑定

    摘要:上一节我们已经将自动生成注解代码部分介绍完毕,今天这篇文章是自定义注解系列的最后一篇文章。该部分是对我们前面定义的注解变量与自动生成的代码进行绑定,即调用我们自动生成的代码。 showImg(https://segmentfault.com/img/bVbdEsh?w=1200&h=720); 上一节我们已经将自动生成注解代码部分介绍完毕,今天这篇文章是自定义Android注解系列的最...

    王晗 评论0 收藏0
  • 定义Android注解Part1:注解变量

    摘要:下面我们会自己实现与注解,实现中的对应注解功能。带大家一起来声明注解变量。知道了它的作用范围之后,我们在自定义注解时就要尽量较小注解的作用范围,提高项目的编译与运行速度。它们代表自定义的注解能够作用的对象。总结库中的自定义注解就完成了。 showImg(https://segmentfault.com/img/bVbc08a?w=740&h=416); 对于Android注解,或多或少...

    yunhao 评论0 收藏0
  • 定义Android注解Part1:注解变量

    摘要:下面我们会自己实现与注解,实现中的对应注解功能。带大家一起来声明注解变量。知道了它的作用范围之后,我们在自定义注解时就要尽量较小注解的作用范围,提高项目的编译与运行速度。它们代表自定义的注解能够作用的对象。总结库中的自定义注解就完成了。 showImg(https://segmentfault.com/img/bVbc08a?w=740&h=416); 对于Android注解,或多或少...

    KavenFan 评论0 收藏0
  • Android Architecture Components Part3:Lifecycle

    摘要:代表生命事件,是由层分发过来的,这些事件与中的生命回调相匹配。代表当前追踪的组件所处的生命状态。内部通过来注册了生命周期状态。减少逻辑处理与不必要的异常发生。 showImg(https://segmentfault.com/img/bVbcpqU?w=800&h=367); 上期文章我们讲解了LiveData,知道它是一个可观察容器同时具备生命感知能力。那么它的生命感知能力又是如何实...

    denson 评论0 收藏0
  • 定义Android注解Part2:代码动生成

    摘要:使用来绑定该,主要是用来实例化自动生成的类。该部分下篇文章将提及我们自己定义的绑定注解库已经完成了,接下来我们将实现它的代码自动生成部分。也是注解库代码自动生成的核心部分。该方法的作用就是获取到有我们自定义注解的。 showImg(https://segmentfault.com/img/bVbdAzO?w=960&h=640); 上一期我们已经把butterknife-annotat...

    xiaotianyi 评论0 收藏0

发表评论

0条评论

harriszh

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<