自定义Android注解Part3:绑定

clipboard.png

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

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

那么咱们仍是来看下butterknife-bind模板库的结构:git

clipboard.png

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

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

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

Bind

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

public class Butterknife {
 
    private Butterknife() {
 
    }
 
    private static <T extends Activity> 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方法,传入须要绑定的类便可。app

Use

到这里,因此的准备工做已经完成。接下来咱们能够开始在MainActivity中使用。首先将定义的库进行依赖ide

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

而后在MainActivity中使用ui

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类似的功能。this

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:代码自动生成

关注

公众号:怪谈时间到了

clipboard.png

相关文章
相关标签/搜索