应用办公生活信息教育商业
投稿投诉
商业财经
汽车智能
教育国际
房产环球
信息数码
热点科技
生活手机
晨报新闻
办公软件
科学动态
应用生物
体育时事

APTTransform实现多模块应用Application

  前言
  组件化开发过程中,各个模块内往往需要感知Application的生命周期,以获取context完成初始化工作等,业务上模块间或存在初始化顺序要求,比较常规的做法有:
  在common模块定义AppLifecycleCallbackinterfaceAppLifecycleCallback{fungetPriority():Int0funonCreate(context:Context)}复制代码
  各个模块实现AppLifecycleCallback,如Home模块classHomeAppLifecycle:AppLifecycleCallback{overridefungetPriority():Int0overridefunonCreate(context:Context){todo}}复制代码
  然后在MainApplication中实现生命周期分发classMainApplication:Application(){privatevalcallbacksmutableListOf()overridefunonCreate(){super。onCreate()callbacks。add(HomeAppLifecycle())callbacks。add(UserAppLifecycle())addwhateveryouwant排序实现模块顺序分发callbacks。sortBy{it。getPriority()}callbacks。forEach{it。onCreate(this)}}}复制代码
  这样能实现需求,但每增加一个模块,就得回到MainApplication中添加一个,不够优雅不够装,这时候就可以用上APTTransform实现原理各模块创建AppLifecycleCallback实现类,添加注解,apt为其生成代理类,以Proxy结尾构造AppLifecycleManager对外API,统一管理Proxycallbacksgradletransform遍历。class文件,找到Proxy的所有类,保存类路径,使用asm将代理类加入到AppLifecycleManager中
  此方案主要是为了解学习apt,gradletransform,实际上有更好的实现方案。各位大佬畅所欲言,提出此方案的短板实现过程一、AppLifecycleAPI
  创建androidlibrary,定义AppLifecycleCallback、AppLifecycleManager
  interfaceAppLifecycleCallback{fungetPriority():Int0funonCreate(context:Context)}复制代码
  AppLifecycleManager中onCreate是对外的API,在MainAppkication中调用;registerAppLifecycleCallback则是在transform阶段使用asm在AppLifecycleManager的构造方法中调用,将代理类路径传入,最终通过反射存储在callbacks中objectAppLifecycleManager{privatevarcallbacks:MutableList?nullfunonCreate(context:Context){callbacks?。run{sortBy{it。getPriority()}forEach{it。onCreate(context)}}}privatefunregisterAppLifecycleCallback(name:String){try{if(callbacksnull){callbacksmutableListOf()}valinstanceClass。forName(name)。getConstructor()。newInstance()if(instanceisAppLifecycleCallback!callbacks!!。contains(instance)){callbacks!!。add(instance)}}catch(e:Exception){e。printStackTrace()}}}复制代码二、APT创建kotlinlibrary,定义annotation
  Target(AnnotationTarget。CLASS)Retention(AnnotationRetention。SOURCE)annotationclassAppLifecycle()复制代码创建kotlinlibrary,定义Processor,获取所有AppLifecycle注解类,使用KotlinPoet生成Proxy类
  AutoService(Processor::class)classAppLifecycleProcessor:AbstractProcessor(){省略部分代码overridefunprocess(p0:MutableSetoutTypeElement?,environment:RoundEnvironment?):Boolean{environment?。run{getElementsAnnotatedWith(AppLifecycle::class。java)。filter{it。kindElementKind。CLASS}。filter{(itasTypeElement)。interfaces。contains(elements。getTypeElement(callbackName)。asType())}。forEach{AppLifecycleProxyBuilder(itasTypeElement,elements)。build()。writeTo(filer)}}returntrue}}复制代码
  KotlinPoet生成Proxy类classAppLifecycleProxyBuilder(privatevaltypeElement:TypeElement,elements:Elements){省略部分代码funbuild():FileSpec{returnFileSpec。builder(packageName,fileName)。addType(getTypeSpec())。build()}privatefungetTypeSpec():TypeSpec{returnTypeSpec。classBuilder(fileName)。addProperty(getProperty())。addSuperinterface(superInterface)。addFunction(getOnCreate())。addFunction(getPriority())。build()}privatefungetProperty():PropertySpec{对应注解类实例returnPropertySpec。builder(callback,typeElement。asClassName(),KModifier。PRIVATE)。initializer(T(),typeElement。asType())。build()}privatefungetOnCreate():FunSpec{onCreate(context:Context)returnFunSpec。builder(onCreate)。addModifiers(KModifier。OVERRIDE)。addParameter(context,contextType)。addStatement(callback。onCreate(context))。build()}privatefungetPriority():FunSpec{getPriority():IntreturnFunSpec。builder(getPriority)。addModifiers(KModifier。OVERRIDE)。returns(Int::class)。addStatement(returncallback。getPriority())。build()}}复制代码
  注:kotlin使用apt,要在build。gradle要有以下两个声明plugins{idkotlinkapt}dependencies{kapt(project(:processor))}复制代码三、GradleTransform
  创建kotlinlibrary
  定义AppLifecyclePlugin,继承Transform,实现Project接口classAppLifecyclePlugin:Transform(),PluginProject{privatevalappLifecycleClassNamesmutableListOfString()privatevarappLifecyclesJar:File?nulloverridefuntransform(transformInvocation:TransformInvocation?){transform中遍历。class文件,类名以Proxy结尾并且实现AppLifecycleCallback。。。if(name。endsWith(proxySuffix)classReader。interfaces。contains(callbackInfo)){appLifecycleClassNames。add(name)}。。。定位到包含ApplifecycleManager的JarEntryif(jarEntity。namemanagerClassFile){appLifecyclesJaroutputJar}最终使用ClassVistor将所有Proxy类加入到Manager中的callbacks里valcv:ClassVisitorAppLifecycleVisitor(classWriter,appLifecycleClassNames)classReader。accept(cv,ClassReader。EXPANDFRAMES)classWriter。toByteArray()}}复制代码
  AppLifecycleVisitorclassAppLifecycleVisitor(classVisitor:ClassVisitor,privatevalcallbacks:ListString):ClassVisitor(Opcodes。ASM9,classVisitor){overridefunvisitMethod(access:Int,name:String?,descriptor:String?,signature:String?,exceptions:ArrayoutString?):MethodVisitor{varvisitorsuper。visitMethod(access,name,descriptor,signature,exceptions)if(initname()VdescriptoraccessandOpcodes。ACCPRIVATE!0){visitorobject:AdviceAdapter(ASM9,visitor,access,name,descriptor){overridefunonMethodExit(opcode:Int){for(itemincallbacks){mv。visitVarInsn(ALOAD,0)mv。visitLdcInsn(item。replace(,。))mv。visitMethodInsn(INVOKESPECIAL,comlauterapplifecycleAppLifecycleManager,registerAppLifecycleCallback,(LjavalangString;)V,false)}}}}returnvisitor}}复制代码
  创建完AppLifecyclePlugin,创建文件srcmainresourcesMETAINFgradlepluginslauter。applifecycle。propertiesimplementationclasscom。lauter。applifecycle。AppLifecyclePlugin复制代码
  到此,工作基本完成。只需要将plugin发布到本地,就可以测试功能了四、发布测试
  在上文创建的plugin项目下build。gradle中添加:plugins{。。。添加publishidmavenpublish}。。。发布到本地publishing{publications{mavenJava(MavenPublication){fromcomponents。javagroupIdio。github。chenlauterartifactIdapplifecycleversion1。0}}repositories{mavenLocal()maven{url。。localpluginrepository}}}复制代码
  在gradle中执行publish,发布完成后项目中会新增localpluginrepository文件夹
  在project的build。gradle中添加依赖buildscript{repositories{。。。添加依赖,gradle7。1之后是到setting。graldepluginManagement中添加maven{url。localpluginrepository}}dependencies{。。。classpath(io。github。chenlauter:applifecycle:1。0)}}复制代码
  最后在app的build。gradle中添加plugins{。。。这里跟第三步创建的lauter。applifecycle。properties文件名对应idlauter。applifecycle}复制代码
  至此,所以依赖都配置完毕,运行工程,在appbuild下,用AndroidStudio直接打开apk查看AppLifecycleManager的字节码,可以看到,在构造方法中已加入两个Proxy类路径调用:
  通过查看日志打印,也能看到功能正常DAppLifecycle:HomeAppLifecycleonCreateDAppLifecycle:MainAppLifecycleonCreate复制代码项目地址
  github。comChenLauter启发参考
  juejin。cnpost702921
  原文链接:https:juejin。cnpost7126419784471674887

CBA快讯全明星取消延期举办范子铭停赛两场辽宁三将确定离队CBA目前正在进行常规赛第36轮比赛的争夺,在已经结束的焦点大战当中,北控队以四分之差不敌天津,从而遭遇了四连败。而天津队则豪取七连胜,并且锁定了季后赛的席位,这也是八年以来天……中国代表团金牌数和奖牌数创新高星巴克回应驱赶吃盒饭民警丨一览重要舆情特征2月15日,中国代表团金牌数和奖牌数创新高、苏州六地升为中风险地区、星巴克回应驱赶吃盒饭民警、新一轮双一流名单公布等话题受到舆论关注。01中国代表团金牌数和奖……2022赛季F1冲刺赛确认将在3个比赛周末举办2月14日,2022年首次F1委员会会议在伦敦进行,会议对如下议题进行了讨论,并针对部分议题进行了相应的规则修改。需要注意的是,所有的规则修改都需要通过世界汽车运动理事会的最终……自然宇宙之数学原理的数学宇宙《自然宇宙之数学原理》的数学宇宙(物理现象时空岳涌强著内容提要:本文讲述了宇宙数学的产生以及形成的过程;同时讲述了利用宇宙数学去研究宇宙的新发现。一、宇宙与数……王者荣耀新赛年皮肤给兰陵王,雅典娜推出圣诞限定,小乔有好消息大家好,我是小欢,原创不易,切勿抄袭还有一个多月S25赛季就要结束了,结束后s26新赛季即将到来,在下个赛季里,王者荣耀第二款全新赛年皮肤即将上线,而且根据多个小道消息爆……华为四款新机曝光nova10延迟到7月,P60渲染图来了华为因为懂得都懂的原因,华为旗舰在今年始终没有亮相,此前博主厂长是关同学爆料说在6月下旬会带来华为nova10系列,但近日又表示这款手机延期了,大概率会在7月初发布。当然,想买……霞浦丹湾G5观景台丨一眼览海景,你心动了吗?丹湾G5观景台XIAPUDANWAN如果你喜欢观景喜欢静静观赏大海的感觉那你一定不要错过霞浦丹湾G5观景台沿着长长的栈道走到观景台这里……林志颖老婆晒全家出游,12岁Kimi身高超爸爸,父子同框像兄7月8日晚,林志颖在个人社交平台分享了一张自己的出游帅照,他还开心配文:小朋友期待许久的暑假旅游启动,随后陈若仪点赞了老公的帅照,好心情尽显。趁着好天气带着老婆孩子出游,林志颖……张继科被曝未婚生子,牵出白百合大瓜后,谢娜赵丽颖也被波及没想到,张继科和景甜的旧事发酵了小半个月以后,圈内娱记直接连线卓伟,再次曝出大瓜。这一次,可谓是信息量巨大,再次令人大跌眼镜。隐退多年的卓伟之所以突然发声,是因为对……华为在港拓展产学研合作为香港创科产业谋发展邓水根分享华为在港业务。魏华都摄中新网香港4月14日电(记者魏华都)一连四天的首届香港国际创科展正在香港举行,冀促进行业交流与香港创科发展,华为是参展商之一。香港华为国际……美媒送绿军5笔布朗交易方案1换5赴火箭称王2换7联手约基奇争本赛季杰伦布朗在绿军的角色一如既往的不稳固,由于他的合同仅剩两年,布朗有可能在2024年选择离开,美媒《theringer》也在近日解析了这一点,布朗认为绿军管理层低估了他,他……无间出现一大利器!导致闪官计划落空,牧溪鹤免被杀繁星计划名单是日本安插在中国的深度间谍名单,陆风有繁星计划的名单代码,牧溪鹤有破译这些名单代码的密码本,而闪官一直在保护繁星计划名单不被暴露。所以,闪官不惜一切代价要除掉……
什么是游戏代理?怎么做手游代理才靠谱?现在游戏市场如火如荼,游戏市场越来越受欢迎,占游戏市场份额的和。因此,游戏代理出现在公众的视野中,成为年轻人喜爱的创业项目。那么什么是游戏代理呢?如果你准备机游戏代理,就……雷克萨斯销量一夜跌回三年前,饥饿营销不灵了?7月新车交强险上险量出炉,曾经的加价王雷克萨斯以20的跌幅在豪华品牌中垫底。这不是雷克萨斯刚刚遭遇滑铁卢,事实上,进入2022年,雷克萨斯的日子一直很不好过,整个上半年的……张凯丽不愧是妈圈顶流,拍时尚大片好优雅,不扮嫩气质更高级女人到了中年,到底怎么穿才足够高级减龄呢?有人认为要穿的花哨点,去削弱自己的年龄感,有人认为要打扮的简单一些,因为越简约的造型越高级,但是对于中年女性来说,其实只要是适合自己的……为何华凌空调被多数人选择?便宜耐用是其一,这些也是重要原因前言:为什么空调的价格会变得越来越便宜?其实和空调品牌之间的激烈竞争有很大的关系。国内国产品牌除了格力、美的、海尔等3家空调巨头外,还有一些电视机龙头品牌也加入了空调市场的竞争……采集军官如何选?兵人大战资深玩家包教包会观前提醒:本文由玩家团玩家投稿,仅供参考,不代表官方立场。本文作者:〔72战场〕十四指挥官们好,这里是72战场的十四。个人平时喜欢研究一些兵人大战的数据与战报,希望……临津冀傍湖山,一块草坪玩法新鲜三里屯有的,这儿也有平谷金海湖坝前广场的露营地。马平川摄金海湖,京城第三大水库,镶嵌在京津冀交界处的群峰间。这些年,水清了、天蓝了,但旅游项目仍是看景儿、爬山、划船老三样,顶多再吃顿农家饭,……官宣!北京首钢裁掉22岁前锋,曾单场砍下43分,投奔CBA名这个夏天,当大多数CBA球队都在疯狂引援的时候,北京首钢却非常安静,除了试训北控男篮的满江之外,就没有了其他消息。不过北京首钢离队球员不少,除了刘晓宇和常林,球队的另外一名年轻……21利物浦,奄奄一息的曼联,为何能打出如此神迹?曼联赛前:奄奄一息,1:2布莱顿、0:4布伦特福德,球队能打的一个都没有,买来的卡塞米罗不能第一时间出场。滕哈赫想买的德容、安东尼一个都不来,C罗又闹离队,想买拉比奥特还被他妈……夏天可以考虑这几款搭载骁龙870的性价比手机,不输天玑8101、小米12X小米12X屏幕:6。28英寸曲面打孔屏,120Hz刷新率充电续航:67W有线快充,4500毫安电池尺寸重量:176g重量,8。16mm厚度……早起后,第一件事情是喝水还是上厕所?提醒应该先做好这件事睡醒之后,你做的第一件事情是什么?是起床匆匆奔向厕所,还是立刻起来喝水呢?之所以会有这两种反应,第一就是身体看似进入了睡眠状态,但实际上器官并没有完全休息下来,比如……意外!上港当红国脚成了后防最弱一环,遭00后小将打爆,主力不上港在中超第八轮迎来了全华班的武汉队,这场比赛球队主帅莱科依然排出了三中卫阵型。王燊超、张琳芃、李昂三位中卫携手首发,以此来抵御河北队的进攻。事实证明莱科派出三中卫踢河北队,并……克莱因蓝太太太火了!这么穿才显白啧啧,我终于想起来聊个色彩审美干货啦。扫一眼今年夏天的流行色趋势,意外发现了爆火的克莱因蓝!乖乖,这个蓝是真的很蓝啊!穿上不会显黑到哭吗?但经多方网友证明:我可能误解了它……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网