范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

APTTransform实现多模块应用Application生命周期分发

  前言
  组件化开发过程中,各个模块内往往需要感知Application的生命周期,以获取context完成初始化工作等,业务上模块间或存在初始化顺序要求,比较常规的做法有:
  在common模块定义   AppLifecycleCallback  interface AppLifecycleCallback {    fun getPriority(): Int = 0    fun onCreate(context: Context)}复制代码
  各个模块实现   AppLifecycleCallback   ,如Home模块  class HomeAppLifecycle : AppLifecycleCallback {    override fun getPriority(): Int = 0        override fun onCreate(context: Context) {        //todo    }}复制代码
  然后在   MainApplication   中实现生命周期分发  class MainApplication : Application() {    private val callbacks = mutableListOf()        override fun onCreate() {        super.onCreate()        callbacks.add(HomeAppLifecycle())        callbacks.add(UserAppLifecycle())        // add whatever you want        // 排序实现模块顺序分发        callbacks.sortBy { it.getPriority() }        callbacks.forEach { it.onCreate(this) }    }    }复制代码
  这样能实现需求,但每增加一个模块,就得回到MainApplication中添加一个,不够优雅不够装,这时候就可以用上   APT + Transform  实现原理各模块创建AppLifecycleCallback实现类,添加注解,apt为其生成代理类,以"_Proxy"结尾  构造   AppLifecycleManager   对外API,统一管理Proxyc allbacks  gradle transform遍历.class文件,找到"_Proxy"的所有类,保存类路径,使用   asm   将代理类"加入"到AppLifecycleManager中
  此方案主要是为了解学习apt,gradle transform,实际上有更好的实现方案。各位大佬畅所欲言,提出此方案的短板  实现过程一、 AppLifecycle API
  创建android-library,定义   AppLifecycleCallback   、   AppLifecycleManager
  interface AppLifecycleCallback {    fun getPriority(): Int = 0    fun onCreate(context: Context)}复制代码
  AppLifecycleManager中   onCreate   是对外的API,在MainAppkication中调用;   registerAppLifecycleCallback   则是在transform阶段使用asm在AppLifecycleManager的构造方法中调用,将代理类路径传入,最终通过反射存储在callbacks中  object AppLifecycleManager {    private var callbacks: MutableList? = null    fun onCreate(context: Context) {        callbacks?.run {            sortBy { it.getPriority() }            forEach { it.onCreate(context) }        }    }    private fun registerAppLifecycleCallback(name: String) {        try {            if (callbacks == null) {                callbacks = mutableListOf()            }            val instance = Class.forName(name).getConstructor().newInstance()            if (instance is AppLifecycleCallback && !callbacks!!.contains(instance)) {                callbacks!!.add(instance)            }        } catch (e: Exception) {            e.printStackTrace()        }    }}复制代码二、 APT创建kotlin-library,定义annotation
  @Target(AnnotationTarget.CLASS)@Retention(AnnotationRetention.SOURCE)annotation class AppLifecycle()复制代码创建kotlin-library,定义Processor,获取所有 @AppLifecycle注解类,使用   KotlinPoet   生成Proxy类
  @AutoService(Processor::class)class AppLifecycleProcessor : AbstractProcessor() {    // 省略部分代码    override fun process(p0: MutableSet?, environment: RoundEnvironment?): Boolean {        environment?.run {            getElementsAnnotatedWith(AppLifecycle::class.java)                .filter { it.kind == ElementKind.CLASS }                .filter {                    (it as TypeElement).interfaces.contains(                        elements.getTypeElement(callbackName).asType()                    )                }                .forEach {                    AppLifecycleProxyBuilder(it as TypeElement, elements).build().writeTo(filer)                }        }        return true    }}复制代码
  KotlinPoet生成Proxy类  class AppLifecycleProxyBuilder(private val typeElement: TypeElement, elements: Elements) {    // 省略部分代码    fun build(): FileSpec {        return FileSpec.builder(packageName, fileName)            .addType(getTypeSpec())            .build()    }    private fun getTypeSpec(): TypeSpec {        return TypeSpec.classBuilder(fileName)            .addProperty(getProperty())            .addSuperinterface(superInterface)            .addFunction(getOnCreate())            .addFunction(getPriority())            .build()    }    private fun getProperty(): PropertySpec {        // 对应注解类实例        return PropertySpec.builder("callback", typeElement.asClassName(), KModifier.PRIVATE)            .initializer("%T()", typeElement.asType())            .build()    }    private fun getOnCreate(): FunSpec {        // onCreate(context: Context)        return FunSpec.builder("onCreate")            .addModifiers(KModifier.OVERRIDE)            .addParameter("context", contextType)            .addStatement("callback.onCreate(context)")            .build()    }    private fun getPriority(): FunSpec {        // getPriority(): Int        return FunSpec.builder("getPriority")            .addModifiers(KModifier.OVERRIDE)            .returns(Int::class)            .addStatement("return callback.getPriority()")            .build()    }}复制代码
  注:kotlin使用apt,要在build.gradle要有以下两个声明  plugins {    id "kotlin-kapt"}dependencies {    kapt (project(":processor"))}复制代码三、 Gradle Transform
  创建kotlin-library
  定义AppLifecyclePlugin,继承Transform,实现Project接口  class AppLifecyclePlugin : Transform(), Plugin {    private val appLifecycleClassNames = mutableListOf()    private var appLifecyclesJar:File? = null        override fun transform(transformInvocation: TransformInvocation?) {        // transform中遍历.class文件,类名以"_Proxy"结尾并且实现AppLifecycleCallback        ...        if (name.endsWith(proxySuffix) && classReader.interfaces.contains(callbackInfo)) {            appLifecycleClassNames.add(name)        }        ...        // 定位到包含 ApplifecycleManager的JarEntry        if(jarEntity.name == managerClassFile){            appLifecyclesJar = outputJar        }        // 最终使用ClassVistor将所有Proxy类加入到Manager中的callbacks里        val cv: ClassVisitor = AppLifecycleVisitor(classWriter,appLifecycleClassNames)        classReader.accept(cv, ClassReader.EXPAND_FRAMES)        classWriter.toByteArray()    }}复制代码
  AppLifecycleVisitor  class AppLifecycleVisitor(classVisitor: ClassVisitor,private val callbacks: List) : ClassVisitor(Opcodes.ASM9,classVisitor) {    override fun visitMethod(        access: Int,        name: String?,        descriptor: String?,        signature: String?,        exceptions: Array?    ): MethodVisitor {        var visitor = super.visitMethod(access, name, descriptor, signature, exceptions)        if ("" == name && "()V" == descriptor && access and Opcodes.ACC_PRIVATE != 0) {            visitor = object : AdviceAdapter(ASM9, visitor, access, name, descriptor) {                override fun onMethodExit(opcode: Int) {                    for (item in callbacks) {                        mv.visitVarInsn(ALOAD, 0)                        mv.visitLdcInsn(item.replace("/", "."))                        mv.visitMethodInsn(                            INVOKESPECIAL,                            "com/lauter/applifecycle/AppLifecycleManager",                            "registerAppLifecycleCallback",                            "(Ljava/lang/String;)V",                            false                        )                    }                }            }        }        return visitor    }}复制代码
  创建完AppLifecyclePlugin,创建文件src/main/resources/META-INF/gradle-plugins/lauter.applifecycle.properties  implementation-class=com.lauter.applifecycle.AppLifecyclePlugin复制代码
  到此,工作基本完成。只需要将plugin发布到本地,就可以测试功能了  四、 发布测试
  在上文创建的plugin项目下build.gradle中添加:  plugins {    ...    // 添加publish    id "maven-publish"}...// 发布到本地publishing {    publications {        mavenJava(MavenPublication) {            from components.java            groupId = "io.github.chenlauter"            artifactId = "applifecycle"            version = "1.0"        }    }    repositories {        mavenLocal()        maven {            url = "../local-plugin-repository"        }    }}复制代码
  在gradle中执行publish,发布完成后项目中会新增   local-plugin-repository   文件夹
  在project的build.gradle中添加依赖  buildscript {    repositories {        ...        // 添加依赖,gradle7.1之后是到setting.gralde-pluginManagement中添加        maven { url "./local-plugin-repository" }    }    dependencies {        ...        classpath("io.github.chenlauter:applifecycle:1.0")    }}复制代码
  最后在app的build.gradle中添加  plugins {    ...    // 这里跟第三步创建的lauter.applifecycle.properties文件名对应    id "lauter.applifecycle"}复制代码
  至此,所以依赖都配置完毕,运行工程,在app-build下,用Android Studio直接打开apk查看 AppLifecycleManager的字节码,可以看到,在构造方法中已加入两个Proxy类路径调用:
  通过查看日志打印,也能看到功能正常  D/AppLifecycle: HomeAppLifecycle onCreate D/AppLifecycle: MainAppLifecycle onCreate复制代码项目地址
  github.com/ChenLauter/…  启发参考
  juejin.cn/post/702921…
  原文链接:https://juejin.cn/post/7126419784471674887

神探狗狗系列来啦!我不允许你还没看过这么好看的书今天要分享的这套书,我周末去西西弗给乐乐挑书的时候,几个小朋友手捧着书坐在地上认真的看,时而哈哈哈大笑。后来发现他们捧读的书,正是我要去书架上翻阅的书纽约时报畅销书排行榜第一名(映公园长满帐篷,景区空空荡荡每经记者黄名扬每经编辑刘艳美图片来源新华社这个五一,打开朋友圈,仿佛全世界都在露营。公园里长满了帐篷比大学澡堂还挤年轻人的新社交货币疫情之下,长途旅游频频受限,城市周边游户外游随之新一代旗舰双芯强力加持!vivoX80Pro展现出色手游电竞体验在四月下旬正式发布的vivoX80Pro,可谓近期安卓旗舰领域的最大看点之一。新机拥有蔡司全焦段旗舰四摄方圆之境设计等全新看点,而这一次,vivoX80Pro还在性能层面做出强力升无叶风扇和普通风扇比较哪个好,大宇无叶风扇还是不错的大宇无叶风扇还是不错的,非常好用,可参考下面的试用点评和感受。买回来立马就用上了,平时在家的时候会开冷风当电风扇吹风用,有5个档位风力也是很够用了,吹出来的风很舒适,很像自然风了。更适合女生的时尚智能腕表,GarminMoveLuxe上手体验这几年,智能手表凭借对人们生活运动健康上的帮助,受到大家的追捧,它似乎成为了健康生活的专属装备。但你有没有发现,大部分的智能手表外形都过于硬朗阳刚,块头也很大,男生戴着当然合适,但这类口罩,多款不合格来源昆明日报掌上春城疫情期间,口罩已经成为出行的必需品。儿童口罩更是五花八门品种繁多,单价也从几毛钱到几块钱不等,让家长眼花缭乱。那么,这些口罩的质量是否合格?黑龙江60款儿童口罩相约五月漫步东台黄海森林公园一眨眼五一小长假已经过去今天大家都上班了趁着五月份刚开始趁着春光依旧美好不用想,不用犹豫这在这个周日大家来森林就对了不负春光没有发不完的微信没有打不完的电话没有回不完的邮件只有和煦四川省十大特产四川有哪些值得带走的特产四川著名特产排行榜四川历史悠久风光秀丽物产丰富,自古以来享有天府之国的美誉,自然少不了很多土特产,那么,四川著名特产有哪些呢?四川省十大特产排行榜1蜀绣中国四大名绣国家非遗国家地理标志保护产品精美的皇家加勒比所有邮轮将在五月底复航随着邮轮公司重新启动剩余的停止服务的邮轮,邮轮行业终于准备全速前进。对于皇家加勒比来说,本月将标志着整个船队的回归,海洋迎风号将于5月23日从罗马启航,恢复服务。最后一艘皇家加勒比2022年五一假期国内旅游出游1。6亿人次,国内旅游收入646。8亿元2022年五一假期,文化和旅游市场平稳有序,微旅游微度假成为主流,云展演云演艺有声有色。经文化和旅游部数据中心测算,2022年五一假期5天,全国国内旅游出游1。6亿人次,同比减少3自驾皖南川藏线,除了风景很美,这几个注意事项一定要知道在去过的所有自驾线路中,皖南川藏线是最特别最弯转遇到的天气最不好的一条线路。从宁国入口开始正式进入皖南川藏线,路变成了蜿蜒的乡间小道。对于新手而言,感觉对面来的车就像是要擦着自己车
雷霆旗下手游一念逍遥韩服国服差别对待玩家炸锅总结一下这次雷霆的所作所为(说的内容基本实锤可能不全仅供参考)国服出bug扣除难度高全体扣除扣成负数韩服出bug扣除难度低全体不扣反补补偿还极多韩服春节上架玉兔而国服没出,之后慌忙CBA消息韩德君常规赛难复出知名裁判被处罚上海外援拒归队头条创作挑战赛韩德君第三阶段常规赛难复出辽宁队本赛季的表现并不是特别突出。与上赛季相比,辽宁队的常规赛排名有一定程度的下滑。上赛季辽宁队常规赛排名第一,他们也成功拿到了CBA联赛的1811!火箭5人上双惨败骑士,六边形战士攻守兼备,斯通淘到宝了1月27日,NBA常规赛迎来一场关键较量,由休斯顿火箭迎战骑士,本场比赛,是一场天赋级别的对抗,在米切尔因伤无法出战的情况下,骑士这边加兰掌握大量球权,全场疯砍了26分,而作为球队连续5场未打!被弃用成常态昔日单场45分超巨已无法重返巅峰?CBA第二阶段,上海男篮是最成功的球队之一。第一阶段,上海男篮3胜6负,位居CBA倒数第3,犹如鱼腩。第二阶段,上海男篮14胜5负,战绩升至17胜11负,排名位CBA第6。球队战绩中国男篮聚会,众多娇妻相伴,个个肤白貌美身材好,高颜值超养眼春节假期是最让人放松的时刻,CBA球员们也在这个时候休息,和家人相聚,易建联还带着孩子老婆到广东老家的宅子里放鞭炮,一年忙到头,是该跟朋友家人们多相聚多一些陪伴。北京时间1月27日欧洲五大联赛的真正的豪门球队有哪些?就本国联赛中能称作豪门球队的,唯一的指标就是夺冠次数。球队夺冠次数在本国联赛的历史中占的比重,以及和其他球队的夺冠次数所拉开的距离也是重要的参考数据。法甲联赛尽管列入欧洲五大联赛,A股三个信号袭来,下周,股市即将起飞?A股市场休市了那么久,在下周就要迎来开市了,那么,下周,股市走势会如何呢?值得注意的是,这个时候,三个信号袭来,这三个信号对于下周股市而言很重要。第一个信号,虽然A股还没开市,但是T汤普森归来!陪穿错球衣的金卡戴珊看球,接侄女回家,遇到坎耶北京时间1月28日,走出了失母之痛的前NBA球员特里斯坦汤普森被媒体发现,陪同前大姨子金卡戴珊去看小西北和Saint的比赛。另外一边,金卡戴珊的前夫坎耶也来到了现场看子女们打球。两蔡斌难以服众!23人名单却有3个自相矛盾决定,大隐患提前曝光北京时间1月19日,中国女排的全新大名单火爆出炉,但是本次名单出炉之后,却瞬间引爆了一片热议和讨论。因为这一次女排主帅蔡斌所选出的这份名单,争议确实很大,名单一出来,第一大争议就随2023年印尼羽毛球大师赛决赛名单以及半决赛赛果半决赛赛果乔纳坦211315212119石宇奇,石宇奇不敌乔纳坦,实力上其实石头不输乔纳坦,第一,石头失误太多,可能风大,他劈杀打斜线,基本都是出界失误,稳定性不够。第二,石头这场20家企业入选!2022年度洛阳市隐形冠军企业名单揭晓河南日报客户端记者李宗宽范坤鹏通讯员王燕飞1月28日,记者从洛阳市工信局获悉日前,洛阳市公布2022年度洛阳市隐形冠军(培育)企业名单,洛阳建龙微纳新材料股份有限公司等20家企业获