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

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

夺位!史蒂文森第十回合TKO赫林,24岁成为两个级别的世界拳王史蒂文森,24岁拿下两个级别的世界拳王北京时间2021年10月24日中午,在美国亚特兰大州立农场体育馆(StateFarmArena)举行的WBO超羽量级世界拳王争霸战落下帷幕。在过早退役的8名球员!如果能继续踢下去,或许能创造一些奇迹据报道,伊瓜因正考虑在33岁退役!自从去年转会到贝克汉姆的国际迈阿密后,他就没能给人留下深刻印象,在过去的大联盟赛季中,他在35次出场中只进了11球。这位前皇家马德里和尤文图斯前锋奥尼尔当今联盟只有4人已经证明了自己,其他人还有很多不足奥尼尔当今联盟只有4人已经证明了自己,其他人还有很多不足!最近奥尼尔在社交媒体晒出了一张现役当中最强的球星,分别是詹姆斯伦纳德字母哥和库里,同时还在图片下面配上一段文字表明这群球员高抬贵手!浦江之流请不要捧杀唐欣周页彤等年轻球员全锦赛正在如火如荼进行中,各队的表现都在我的意料之中,只是江苏女排稍显稚嫩,有点尴尬!不过年轻的江苏女排几乎清一色的零零后球员,不可能与山东女排与天津女排相提并论也是可以理解的。全欧文发文疑似坚持自我!韦德儿子加盟爵士下属球队!詹皇最新动态北京时间10月24日,NBA比赛继续进行,在已经结束的场次里,骑士爆冷击败老鹰,步行者击败拥有三巨头的迈阿密热火,总之,今天冷门不断。而在刚刚过去的一夜之间,联盟有多个重要消息传出三项命中率36038,威少成最大罪人,詹姆斯射手竟是我自己两场比赛,詹姆斯在三分线外20中10,而其他首发球员的这个数据是24中4。我们都知道,最适合詹姆斯的阵容就是一星四射,可是如今詹姆斯看到首发队友的表现不禁感叹射手竟是我自己!再看到怀疑孩子得了注意力缺乏综合症,请仔细读读这篇文章近些年来,我们都太热衷于给孩子贴标签。我建议所有和你有着相同情况的父母首先找出导致这种行为的各种可能原因。经常不听话的孩子,特别难以对付的孩子,能力发展比较慢的孩子,都是父母的心病土超劲旅盼望李盈莹加盟!李盈莹成朱婷之后,中国女排新希望关于李盈莹去海外打球的消息,最近传得沸沸扬扬,有人相信,也有人在质疑。今天土耳其媒体的一则消息,让这些争议戛然而止,看来李盈莹真的要加盟土超劲旅费内巴切了!据外媒消息,费内巴切俱乐郭艾伦赛季首秀2858阿不都43分创生涯得分新高辽宁送新疆三连败北京时间10月25日1500,20212022赛季CBA常规赛第五轮,辽宁队10999战胜新疆队送给对手三连败。本场比赛,郭艾伦首发出场,上演赛季首秀。郭艾伦技术统计辽宁队郭艾伦2北京新增京外关联本地确诊6例10月22日0时至24时,北京新增6例京外关联本地新冠肺炎确诊病例(其中病例1至病例4昨日已通报),无新增疑似病例和无症状感染者无新增境外输入确诊病例疑似病例和无症状感染者。确诊病郭艾伦刘志轩复出,外援到位!辽篮12人主力大名单更新,太豪华这几天辽宁队传来了很多好消息,郭艾伦终于可以上场打球了,福格也马上就能代表辽宁队上场根据辽宁媒体透露,刘志轩已经痊愈,即将赶往赛区。新赛季的这几场比赛,辽宁队阵容并不完整,如今郭艾
狂轰1611!命中制胜三分还创新高,火箭探花秀正在兑现状元天赋哈登重回休城成为了火箭对战76人的一个焦点,虽然他已经离队有3载,但是他昔日的表现已经牢牢印在休城人的心中,其实对于这场比赛,几乎没有人认为火箭能够拿下最终的胜利,但是意想不到的事胖虎正在积极融入的鹈鹕队究竟有多强?最近NBA官方更新了球队战力榜,110凯尔特人雄鹿太阳鹈鹕灰熊骑士掘金国王76人开拓者1120勇士爵士快船老鹰篮网热火独行侠猛龙湖人步行者2130尼克斯雷霆森林狼奇才公牛黄蜂活塞火NBA3消息老鹰爆发内部矛盾,独行侠有意罗斯,湖人被热议第一个消息来自老鹰,据最新消息,老鹰当家球星特雷杨和主教练麦克米兰发生冲突,起因是特雷杨想缺席投篮训练,这可不是一件好事。对此,NBA著名评论员帕金斯表示亚特兰大发生了什么事?招牌生病的门神和中卫复出!瑞士队不惧C罗,有信心淘汰葡萄牙队北京时间12月7日凌晨3时,卡塔尔世界杯最后一场18决赛葡萄牙队与瑞士队比赛将在卢赛尔体育场打响。瑞士队主教练雅金携恩博洛出席赛前新闻发布会图据ICphoto在瑞士队主帅雅金看来,从第三替补到格子军新英雄,利瓦科维奇的封神之路或许在本届世界杯之前,利瓦科维奇并非是一名家喻户晓的球员,甚至在对阵日本的八分之一决赛之前,还有人对利瓦科维奇是否应该成为克罗地亚的首选门将表示怀疑。但随着克罗地亚在点球大战中击败库里我知道本赛季我们犯错的余地可能并不多了今日,NBA常规赛勇士104112不敌步行者。赛后,勇士球员斯蒂芬库里在接受采访时谈到了球队目前的处境。库里首先比较了球队目前的处境和一个月前的处境,如果说一个月前我们处于黑夜中,特鲁姆普遭遇生涯最大打击,身负重压已难回巅峰!英媒令人失望20222023斯诺克苏格兰公开赛圆满落下帷幕之后,由于赛程安排比赛再次进入了枯燥的空窗期,知名度高的球员则是没有闲着在此期间频繁亮相各大直播节目为赛事增加关注度。罗尼奥沙利文本赛出轨打胎?国乒又一球员曝出丑闻,骂队友,多次违反国家队规定12月6日,2022乒超联赛正在如火如荼地进行,樊振东陈梦孙颖莎王曼昱王艺迪等主力悉数参加比赛,为了帮助俱乐部取得更好的成绩背水一战!虽然乒超联赛只有国内的球员参加,但赛事的水平丝寒湿痹阻类风湿关节炎难治,怎么应对呢?类风湿关节炎1常见类风湿关节炎难治,是以侵蚀性关节炎为主的自身免疫病,男女比为14,发病率0。42。2临床主要表现为对称性炎性外周多关节炎,基本病理表现为滑膜炎和血管翳形成,逐渐出洗面奶还要分肤质吗?清洁是护肤第一步骤,如果脸都没洗干净就护肤纯属瞎扯。意会一下,眼屎巴拉的就开始搓眼霜,啥感觉若不洗脸就护肤,那和不刷牙就吃饭有啥区别。另外,选错洗面奶一样会烂脸,不合适的洗面奶洗不一组PIXIV画师smilesheep的知性范人物风格佳作这是一组PIXIV画师smilesheep的知性范佳作之一,我就个人认为所谓知性范就是体态优雅,知性范的那种美也是属于历久弥新永不褪色的那种美。而与清纯典雅并存的知性范的宝贵之处就