游戏电视苹果数码历史美丽
投稿投诉
美丽时装
彩妆资讯
历史明星
乐活安卓
数码常识
驾车健康
苹果问答
网络发型
电视车载
室内电影
游戏科学
音乐整形

写个App启动任务框架,有多难?

  作者:王晨彦
  我们在开发应用的时候,一般都会引入SDK,而大部分SDK都要求我们在Application中初始化,当我们引入的SDK越来越多,就会出现Application越来越长,如果SDK的初始化任务相互依赖,还要处理很多条件判断,这时,如果再来个异步初始化,相信大家都会崩溃。
  有人可能会说,我都在主线程按顺序初始化不就行了,当然行,只要老板不来找你麻烦。
  小王啊,咱们的APP启动时间怎么这么久?
  开个玩笑,可见,一个优秀的启动框架对于APP启动性能而言,是多么的重要!一、为什么不用Google的StartUp?
  说到启动框架,就不得不提StartUp,毕竟是Google官方出品,现有的启动框架,或多或少都有参考StartUp,这里不再详细介绍,如果对StartUp还不了解,可以参考这篇文章Jetpack系列之AppStartup从入门到出家。
  https:juejin。cnpost7023643365048582174
  StartUp提供了简便的依赖任务初始化功能,但是对于一个复杂项目来说,StartUp有以下不足:
  1。不支持异步任务
  如果通过ContentProvider启动,所有任务都在主线程执行,如果通过接口启动,所有任务都在同一个线程执行。
  2。不支持组件化
  通过Class指定依赖任务,需要引用依赖的模块。
  3。不支持多进程
  无法单独配置任务需要执行的进程。
  4。不支持启动优先级
  虽然可以通过指定依赖来设置优先级,但是过于复杂。二、一个合格的启动框架是怎么样的?
  1。支持异步任务
  减少启动时间的有效手段。
  2。支持组件化
  其实就是解耦,一方面是解耦任务依赖,另一方面是解耦app和module的依赖。
  3。支持任务依赖
  可以简化我们的任务调度。
  4。支持优先级
  在没有依赖的情况下,允许任务优先执行。
  5。支持多进程
  只在需要的进程中执行初始化任务,可以减轻系统负载,侧面提升APP启动速度。三、收集任务
  如果要做到完全解耦,我们可以使用APT收集任务。
  首先定义注解,即任务的一些属性。Target(AnnotationTarget。CLASS)Retention(AnnotationRetention。RUNTIME)annotationclassInitTask(任务名称,需唯一valname:String,是否在后台线程执行valbackground:Booleanfalse,优先级,越小优先级越高valpriority:IntPRIORITYNORM,任务执行进程,支持主进程、非主进程、所有进程、:xxx、特定进程名valprocess:ArrayString〔PROCESSALL〕,依赖的任务valdepends:ArrayString〔〕)
  name作为任务唯一标识,类型为String主要是解耦任务依赖。
  background即是否后台执行。
  priority是在主线程、无依赖场景下的执行顺序。
  process指定了任务执行的进程,支持主进程、非主进程、所有进程、:xxx、特定进程名。
  depends指定依赖的任务。
  任务的属性定义好,还需要一个执行任务的接口:interfaceIInitTask{funexecute(application:Application)}
  任务需要收集的信息已经定义好了,那么看一下一个真正的任务长什么样。InitTask(namemain,process〔InitTask。PROCESSMAIN〕,depends〔lib〕)classMainTask:IInitTask{overridefunexecute(application:Application){SystemClock。sleep(1000)Log。e(WCY,main1execute)}}
  还是比较简洁清晰的。
  接下来需要通过AnnotationProcessor收集任务,然后通过kotlinpoet写入文件。classTaskProcessor:AbstractProcessor(){overridefunprocess(annotations:MutableSetoutTypeElement?,roundEnv:RoundEnvironment):Boolean{valtaskElementsroundEnv。getElementsAnnotatedWith(InitTask::class。java)valtaskTypeelementUtil。getTypeElement(me。wcy。init。api。IInitTask)Paramtype:MutableListTaskInfoTheresnosuchtypeasMutableListatruntimesothelibraryonlyseestheruntimetype。IfyouneedMutableListthenyoullneedtouseaClassNametocreateit。〔https:github。comsquarekotlinpoetissues482〕valinputMapTypeNameClassName(kotlin。collections,MutableList)。parameterizedBy(TaskInfo::class。asTypeName())Paramname:taskList:MutableListTaskInfovalgroupParamSpecParameterSpec。builder(ProcessorUtils。PARAMNAME,inputMapTypeName)。build()Method:overridefunregister(taskList:MutableListTaskInfo)valloadTaskMethodBuilderFunSpec。builder(ProcessorUtils。METHODNAME)。addModifiers(KModifier。OVERRIDE)。addParameter(groupParamSpec)for(elementintaskElements){valtypeMirrorelement。asType()valtaskelement。getAnnotation(InitTask::class。java)if(typeUtil。isSubtype(typeMirror,taskType。asType())){valtaskCn(elementasTypeElement)。asClassName()Statement:taskList。add(TaskInfo(name,background,priority,process,depends,task));loadTaskMethodBuilder。addStatement(N。add(T(S,L,L,L,L,T())),ProcessorUtils。PARAMNAME,TaskInfo::class。java,task。name,task。background,task。priority,ProcessorUtils。formatArray(task。process),ProcessorUtils。formatArray(task。depends),taskCn)}}WritetofileFileSpec。builder(ProcessorUtils。PACKAGENAME,TaskRegistermoduleName)。addType(TypeSpec。classBuilder(TaskRegistermoduleName)。addKdoc(ProcessorUtils。JAVADOC)。addSuperinterface(ModuleTaskRegister::class。java)。addFunction(loadTaskMethodBuilder。build())。build())。build()。writeTo(filer)returntrue}}
  看一下生成的文件长什么样。publicclassTaskRegistersample:ModuleTaskRegister{publicoverridefunregister(taskList:MutableListTaskInfo):Unit{taskList。add(TaskInfo(main2,true,0,arrayOf(PROCESSALL),arrayOf(main1,lib1),MainTask2()))taskList。add(TaskInfo(main3,false,1000,arrayOf(PROCESSALL),arrayOf(),MainTask3()))taskList。add(TaskInfo(main1,false,0,arrayOf(PROCESSMAIN),arrayOf(lib1),MainTask()))}}
  sample模块收集到了3个任务,TaskInfo对任务信息做了聚合。
  我们知道APT可以生成代码,但是无法修改字节码,也就是说我们在运行时想到拿到注入的任务,还需要将收集的任务注入到源码中。
  这里可以借助AutoRegister帮我们完成注入。
  https:github。comluckybillyAutoRegister
  注入前:internalclassFinalTaskRegister{valtaskList:MutableListTaskInfomutableListOf()init{init()}privatefuninit(){}funregister(register:ModuleTaskRegister){register。register(taskList)}}
  将收集到的任务注入到init方法中,注入后的字节码:compiledfrom:FinalTaskRegister。ktpublicfinalclassFinalTaskRegister{privatefinalListTaskInfotaskListnewArrayList();publicFinalTaskRegister(){init();}publicfinalListTaskInfogetTaskList(){returnthis。taskList;}privatefinalvoidinit(){register(newTaskRegistersamplelib());register(newTaskRegistersample());}publicfinalvoidregister(ModuleTaskRegisterregister){Intrinsics。checkNotNullParameter(register,register);register。register(this。taskList);}}
  我们通过APT生成的类已经成功的注入到代码中。
  小结
  至此,我们已经完成了任务的收集,通过APT和字节码修改是常见的类收集方案,相比反射,字节码修改没有任何性能的损失。
  后来发现Google已经推出了新的注解处理框架ksp,处理速度更快,于是果断尝试了一把,所以有两种注解处理可以选择,GitHub上有详细介绍。四、任务调度
  任务调度是启动框架的核心,大家可能听到过。
  处理依赖任务首先要构建一个有向无环图。
  什么是有向无环图,看下维基百科的介绍:
  在图论中,如果一个有向图从任意顶点出发无法经过若干条边回到该点,则这个图是一个有向无环图(DAG,DirectedAcyclicGraph)。
  听起来好像很简单,那么具体怎么实现呢,今天我们抛开高级概念不谈,用代码带大家实现任务的调度。
  首先,需要把任务分为两类,有依赖的任务和无依赖的任务。
  有依赖的首先检查是否有环,如果有循环依赖,直接throw,这个可以套用公式如何判断链表是否有环。
  如果没有循环依赖,则收集每个任务的被依赖任务,我们称之为子任务,用于当前任务执行完成后,继续执行子任务。
  无依赖的最简单,直接按照优先级执行即可。
  不知道大家是否有疑问:有依赖的任务什么时候启动?
  有依赖的任务,依赖链的叶子端点一定是一个无依赖的任务,因此无依赖的任务执行完成后,就可以开始执行有依赖的任务。
  下面用一个小例子来介绍:A依赖B、CB依赖CC无依赖
  树形结构:
  1、分组并梳理子任务。有依赖:
  A:无子任务
  B:子任务:〔A〕无依赖:
  C:子任务:〔A,B〕
  2、执行无依赖的任务C。
  3、更新已完成的任务:〔C〕。
  4、检查C的子任务是否可以执行。
  A:依赖〔B,C〕,已完成任务中不包含B,无法启动
  B:依赖〔C〕,已完成任务中包含C,可以执行
  5、执行任务B。
  6、重复步骤3,直到所有任务执行完成。
  下面我们就用代码来实现:
  使用递归检查循环依赖:privatefuncheckCircularDependency(chain:ListString,depends:SetString,taskMap:MapString,TaskInfo){depends。forEach{dependcheck(chain。contains(depend)。not()){Foundcirculardependencychain:chaindepend}taskMap〔depend〕?。let{taskcheckCircularDependency(chaindepend,task。depends,taskMap)}}}
  梳理子任务:task。depends。forEach{valdependtaskMap〔it〕checkNotNull(depend){Cannotfindtask〔it〕whichdependbytask〔{task。name}〕}depend。children。add(task)}
  执行任务:privatefunexecute(task:TaskInfo){if(isMatchProgress(task)){valcostmeasureTimeMillis{kotlin。runCatching{(task。taskasIInitTask)。execute(app)}。onFailure{Log。e(TAG,executingtask〔{task。name}〕error,it)}}Log。d(TAG,Executetask〔{task。name}〕completeinprocess〔processName〕thread〔{Thread。currentThread()。name}〕,cost:{cost}ms)}else{Log。w(TAG,Skiptask〔{task。name}〕causetheprocess〔processName〕notmatch)}afterExecute(task。name,task。children)}
  如果进程不匹配直接跳过。
  继续执行下一个任务:privatefunafterExecute(name:String,children:SetTaskInfo){valallowTaskssynchronized(completedTasks){completedTasks。add(name)children。filter{completedTasks。containsAll(it。depends)}}if(ThreadUtils。isInMainThread()){如果是主线程,先将异步任务放入队列,再执行同步任务allowTasks。filter{it。background}。forEach{launch(Dispatchers。Default){execute(it)}}allowTasks。filter{it。background。not()}。forEach{execute(it)}}else{allowTasks。forEach{valdispatcherif(it。background)Dispatchers。DefaultelseDispatchers。Mainlaunch(dispatcher){execute(it)}}}}
  如果子任务的依赖任务都已经执行完毕,就可以执行了。
  最后还需要提供一个启动任务的接口,为了支持多进程,这里不能使用ContentProvider。
  小结
  通过层层拆解,将复杂的依赖梳理清楚,用通俗易懂的方法,实现任务调度。
  源码
  https:github。comwangchenyaninit
  另外,我也在JitPack上发布了alpha版本,欢迎大家尝试:kaptcom。github。wangchenyan。init:initcompiler:1alpha。1implementationcom。github。wangchenyan。init:initapi:1alpha。1
  详细使用请移步GitHub。
  https:github。comwangchenyaninit最后
  本文以StartUp作为引子,阐述依赖任务启动框架还需要具备哪些能力,通过APT字节码注入进行解耦,支持模块化,通过一个简单的模型来表述任务调度具体的实现方式。
  希望本文能够让大家了解依赖任务启动框架的核心思想,如果你有好的建议,欢迎评论交流探讨。
  在这里就还分享一份由大佬亲自收录整理的学习PDF架构视频面试文档源码笔记,高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料
  这些都是我现在闲暇时还会反复翻阅的精品资料。里面对近几年的大厂面试高频知识点都有详细的讲解。相信可以有效地帮助大家掌握知识、理解原理,帮助大家在未来取得一份不错的答卷。
  当然,你也可以拿去查漏补缺,提升自身的竞争力。
  真心希望可以帮助到大家,Android路漫漫,共勉!
  如果你有需要的话,只需私信我【进阶】即可获取

鹏博士亮相第三届中国SDWAN峰会再次蝉联创新奖项11月28日,第三届中国SDWAN峰会于北京东方君悦酒店盛大开幕,本次峰会由中国通信学会指导、江苏省未来网络创新研究院主办,由SDNLAB承办。出席本次大会的有中国工院院士、运……华为正式升级这门技术认证华为认证云服务工程师HCIACloudServiceV3。0(中文版)自2021年9月30日起,正式在中国区发布。发布概述基于平台生态战略,围绕云管端协同的新ICT……发文章的时候,显示一直在审核中是怎么回事?相信大家平时在头条上多多少少都发过一些文章,篇幅有长有短。一般来说,文章发出去会在半分钟内发表成功,但是也不排除审核很慢的时候。有些朋友发的文章,有时候要一两个小时的审核时间,……人机交互,软硬结合!CES2020微星打算这么玩当地时间2020年1月6日上午十一点,微星科技在美国拉丝维加斯召开了隆重的记者会,适逢CES2020开展前夕,并借此推出多款新品,让我们一起来看一看。会议伊始,首先是微星……绿电概念多股涨停!高增长潜力股仅5只今日电力板块强势上涨,截至发文,中国核电、上海电力、中闽能源等16涨停,中闽能源5连板;晶科科技、川能动力、协鑫能科等多股创下历史新高。指数大涨超4创五年来新高,主力资金净流入……不抱怨第十天每日箴言社会是有规则的,我们应该调整自己,去适应这个不断变化的世界善变这个曾经的贬义词,现在可能也是褒义词曾经你指责一个人表里不一,就可以用善变这个词,……通用与特斯拉正面开杠,研发出新版本的高级驾驶辅助系统在去年的未来汽车研讨会上通用宣布内部正在研发下一代的量产的自动驾驶系统内部代号为UltraCruise目的正是对抗特斯拉的AutoPilot在经过……独孤求败,三星Note10屏幕有多强在高端面板领域,三星有着举足轻重的地位。今年三星推出的全新旗舰三星Note105G就搭载了自家最为出色的屏幕,这块屏幕究竟有多强呢?让我们一起来了解一下吧!1。出色的视野……喵喵机MAX,重新定义便携打印机提起打印机,我们的第一印象就是那种放在办公室里打印文件的大型机器,一般都是办公使用。那么有没有好用的便携式家用打印机呢?当然是有的,喵喵机,热敏打印,操作简单,身材小巧可爱去年……ampampquot我丈夫和我从学校走到结婚礼服,他就是不忠你能否放过我,周海峰说。对于微信上的这句话,我陷入无尽的绝望之中。真正绝望的时候,是不会流泪的,也不会有任何争吵,仿佛一切都已毫无意义。在我的怀里,尚有一个正……OnePlusWatch钴合金限定版上市1599元今年3月的一加9系列发布会上一加带来了他们的首款长续航智能手表OnePlusWatch,其中还着重介绍了其钴合金限定版,今天一加官方公布OnePlusWatch钴合金限定版为1……谁说SUV不能运动?路虎揽胜SportSVR性能车伪装谍照曝近日我们通过神奇的海外媒体获悉了路虎全新揽胜SportSVR的路试谍照,新车未来属于揽胜性能版车型,它的到来可以说是讲性能SUV提升到了极致,话不多说,一起来看看这台SUV有多……
5G手机综评排名华为落选,三星蓝绿厂上榜,最大赢家是它?就在今天,中国移动公布了最新的《5G手机综合测评TOP排行榜》,囊括了2020年12月2021年6月上市的5G手机,涉及到11个品牌共计43款产品,综合各方面能力评比而来,在国……不到10万就能买合资紧凑型SUV,这不是在痴人说梦对于捷达这款车型,稍微上点年纪的人都对它有一份特殊的感情,尽管捷达这款车型早已成为历史,但现在一汽大众却把它作为一个独立品牌延续它的生命力。捷达品牌延续了捷达经济实惠、皮实耐用……优雅绅士释放野性,英菲尼迪QX50装贴电光金属灰本期施工施工车型:英菲尼迪QX50车型颜色:暮色红施工项目:装贴电光金属灰改色膜在上世纪80年代,北美豪华汽车市场开始了全面复苏。面对这块日渐诱人的蛋糕……美国阴谋浮出水面,台积电再遭重创台积电是全球半导体行业中知名度最高的芯片制造公司,台积电创始人《张忠谋》,从台湾省的一家小公司成长为世界级的民营芯片公司。很多人都非常佩服张忠谋在这方面的经营技巧和智慧。……圆形vs方形餐桌,究竟哪种更好?餐桌,是每个家庭必不可少的用餐家具,而且从材质上分类,餐桌就有木质、石材、金属等选择;而在外观上,餐桌就有圆形与方形的可选。从餐桌材质来说,可以根据喜好来选择,但从外观来……NVIDIA推出OmniverseEnterprise!助力NVIDIA在春季GTC大会上宣布NVIDIAOmniverseEnterprise即将全面上市。这是全球第一个可以让处于世界各地的3D设计团队跨多个软件套件工作,并在同一共享……卓越生产力工具!NVIDIARTXA6000专业显卡测试【前言】NVIDIA在1999年8月发布首款真正意义上的可编程GPUGeForce256,从此奠定了显卡在PC中的重要地位。同年11月再度推出基于GeForce256核心……路由器WiFi速度正常,手机和电脑网速很慢怎么办?路由器WiFi速度正常,但手机和电脑使用的时候上网速度却很慢,这是因为手机和电脑上相关功能的缓存需要清理。电脑电脑WinR组合键之后输入services。msc,进……海尔中央空调凭借节能稳定服务等优势,中标重庆轨道项目近年来,中国城市轨道交通发展速度、运营规模、运营线路等屡创新高!庞大的市场规模给城市轨道交通中央空调产业带来强劲的市场需求。轨道交通作为城市里的能耗大户,为实现节能减排和……要对智障的人工智能说不吗?九十年代初,媒体曾经放言:人工智能会在十年内毁掉社会;而现在的人工智能,却似乎连猫狗都无法分辨,这听起来似乎有点智障?(图片来源于网络)而人工智能的智障不止是把猫识……要解决芯片短缺,除了金钱还不够目前,芯片短缺的情况被全球时刻关注着,芯片短缺,一方面反映着目前芯片的重要性,从哪里说起呢?芯片已经覆盖到手机,手表等穿戴物,还有家电、电脑,甚至还有汽车!越来越多行业都要用到……好家云店店主薇儿30w粉丝,月入6位数,撑起三份事业你要坚持,到最后都会开花;哪有什么天赋异禀,都是百炼成钢。独当一面是把双刃剑,能力越大,责任和压力也就越大,保持初心,心持谦逊很重要。我的人生更像一个厚积薄发的过程……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网