关于android:22岁专科菜逼Android开发之路的2021年终总结

转瞬曾经到了2021年的开端,回首这过来的一年,发现自己已经定下的指标一个都没有实现。前言我是一个专科毕业的菜逼,大学的最初一年发现自己什么都不会,据说程序员赚的多,就趁着培训机构来学校讲课的机会报了个培训班。 在培训班的时候正好疫情来了,就全副改为在线学习,那段时间没人督促也没有好好的学技术,导致本人当初的根底很差。 等学完了进去也只能在二线城市找了个7.5k的工作,这期间边下班边还贷款还是挺吃力的。 虽说公司小,但好歹是个甲方,过年过节的福利是真的挺不错的,干了一年半这期间还给我涨了20%的薪水,过年还有三个月的年终奖,惟一我不太喜爱的就是外面的人挺卷的,尤其是我的老大,天天卷到8、9点钟,加班还没有加班费。 往年公司间断接了好几个我的项目,加班加点没日没夜的,终于把我的腰间盘给累的突出了,在医院看病的期间我还是下定了信心筹备跳槽。 筹备阶段疫情向好、面试在即,还在迷茫迟疑中的后浪们,如何能力在面试中让本人怀才不遇,让面试官眼前一亮? 文章开端我将分享几篇干货满满的面试笔记和材料给大家,记得肯定要好好珍藏哦!!首先筹备一份丑陋的简历一份丑陋的简历就是你进入大厂的敲门砖。 网上有很多教程教大家如何写出一份丑陋的简历,这里我就不做重复劳动了,大家能够去网上间接下载。 明天我就要逆向思维解说一下什么样的简历是蹩脚的,这里大家肯定要检查一下本人的简历有没有如下的故障: 薪资冀望定得过高或者过低。咱们在简历上填写的冀望薪资,倡议和投递的岗位薪资范畴较为靠近,懒人能够间接填面议。因为定得过高,面试官看到之后可能会加大面试过程中发问问题的难度。(你想啊,你定的薪资都比面试官高那么多,人家心里什么味道?还不把你往死里问,看看你到底值不值这个价?)然而如果你定得过低,面试官可能间接就抉择漠视你的简历了,毕竟工资又不是面试官发的,人家只是想招进来一个有能力能够背锅的,你定得那么低,显著是对本人程度没信念,也就不会思考你了。对本人自觉自信,本人搞不明确的也往简历里写,什么都写精通。这也是十分常见的问题。简历最考究的是真挚,会什么就写什么,不要为了凸显本人多厉害而胡乱往上写,否则害的还是你本人。你要晓得的是,个别好一点的面试官都会简略联合你简历上填写的内容进行针对性的发问。因为技术可发问的点十分多,然而面试的工夫是无限的,那么如何能力疾速地考查一个人的技术水平呢?最简略的形式就是联合这个人的工作经验进行针对性的发问。其实面试最根本的一项工作就是验证你简历内容的真实性。简历内容过于丰盛,技能内容与岗位形容匹配度不高。我就常常在Android招聘岗位上收到很多奇葩的简历。这些人的技能树通常是:C,Android,后盾,js等,也就是俗称的全干工程师。说真的,即便你真的全会,你写的这个简历也只是适宜小厂的面试,因为大厂是不会去招一个什么都会,什么都不精的人的。你须要在简历中着重突出你区别于其他人的劣势,最好的做法就是什么样的岗位投递什么样的简历,多做几套简历作为备选。工作经验过于丰盛。例如3年待过3家及以上数量的公司。工作经验丰盛诚然是坏事,但你也不能全都写到简历里去,抉择2~3家较为有名的公司介绍一下即可,否则他人会对你的团队合作能力以及忠诚度提出质疑。我的项目教训过于简略或者论文化。无论你的我的项目教训是多还是少,列举3~4个即可。除此之外,我的项目教训切忌不要论文化,我常常看到很多人的简历上我的项目教训是大段大段的形容,加起来可能有2~3页纸...说真的,你写这么多,面试官反而不会看,因为想全副看完切实是太累了。这里你只须要简略介绍一下我的项目的内容、你负责的模块和负责的角色、波及到的技术以及最初我的项目的成绩等即可。技术博客或者github主页没有什么内容也写到简历里。记住技术博客或者github主页这一类的,原本都属于加分项,可有可无的,然而如果你写了,面试官誓必会满怀期待地点进去看,如果这个时候出现给他的却是空白页或者寥寥几行内容的话,这种一泻千里的感触会给面试官留下十分不好的印象。简历中填写很多对求职无关的内容。与职位要求无关的内容就不须要写到简历里去了。因为你的简历是拿去找工作用的,任何一个与找工作无关的内容写到简历里只会节约你简历的空间。例如你的一些兴趣爱好或者无关证件。自我介绍要背得滚瓜烂熟自我介绍能够说是面试的必要环节,无论你加入什么模式的面试,面试官肯定会首先让你做一个简略的自我介绍,所以自我介绍这一关肯定要准备充分,最好做到烂熟于心。 自我介绍不是简历的反复背诵。咱们在做自我介绍的时候,肯定要把握好重点,切忌过长或者过短。 自我介绍的过程,也是一个自我采购的过程。你能够把面试官当作你的顾客,而把你本人当作采购的产品。你要做的就是应用最真挚的形式,把你集体的工作教训、长处、能力与面试公司的岗位需要紧密结合起来,让面试官置信招这个人进来的确能够分担工作的压力。 那么咱们在做自我介绍的时候,须要介绍哪些内容呢?上面我简略列举一些内容供大家参考: 集体根本信息。个人信息的介绍要突出重点。咱们须要把重点放在与 「公司需要」 匹配的信息上,如果该信息匹配或有关联,那么咱们就说,如果齐全没关联,那就一句话带过或者不说。工作经验。如果你的工作经验十分丰盛,那么简略挑1~2家和目前应聘公司相似的简略介绍一下即可,其实底层的逻辑就是过来经验是否与目前应聘岗位相匹配或有关联。我的项目经验。我的项目经验不要讲太多,挑一个匹配的或者印象最粗浅的重点讲一下即可,其余的能够一笔带过。我的项目经验能够简略从四个维度开展:我的项目的背景、我的项目的内容、你在我的项目中承当的角色和工作、我的项目的成绩或者业绩。将来愿景。说一些积极向上的内容,进一步阐明本身与岗位相匹配,描述将来愿景,从而更好地感动面试官。(要让面试官感觉招你进来是十分有价值的,小伙子不仅是冲着钱来的,还是有谋求讲情怀的)自我介绍不易过长,筹备2~3分钟即可。与此同时,你平时还须要多加练习,依据不同的公司、不同的场合以及面试的不同岗位,进行不同内容的自我介绍。 面试前多刷刷面试题面试前多刷面试题,是对面试最起码的尊重。尽管我在这里不提倡大家长期抱佛脚,然而适当地抱一抱佛脚也比那些什么都不筹备,就间接裸面的人要好很多,至多你的态度是端正的。 邻近年初,很多人开始蠢蠢欲动了,总有一些人啥都不筹备,间接甩两膀子就去面试的。面试基本上是一问三不知,要么就是说之前看过忘了...更有甚者间接就说,我就是进去面个试感受一下面试氛围以及最新行情的... 托付,能不能给予面试最起码的尊重?你来面试也是须要破费面试官工夫的,简略筹备一下不香嘛?万一你运气好,恰好这家公司职位裁减,升高面试要求了呢? 你这么轻易,岂不是把白花花的机会全都给节约掉了嘛! 上面给大家总结进去了一些面试常见的知识点,还有对应的PDF电子书,有须要的敌人文末有自助支付形式。Android技术面试个别波及的因素Java根底面试Android岗位,Java根底那是必问的。如果我的项目中应用kotlin比拟多的话,可能还会问一些kotlin相干的问题。Java, 作为一门根底语言,考核的是应聘者是否具备扎实的基本功。很多培训班或者非科班出身的人,常常会栽在这一环节。个别这个环节的问题答不上来的话,基本上是提前结束了。 那么常见面试的Java根底问题有哪些呢?上面咱们简略列举一些供大家参考: 1.Java汇合类List,Map,Set相干的实现原理。2.Java线程池的实现原理和应用3.Java线程同步相干的知识点。4.Java锁机制,以及死锁产生的起因以及解决方案。5.Java反射、泛型、注解相干的知识点以及应用。6.Java类加载机制。7.Java虚拟机的资源回收机制以及算法。 以上基本上是面试Android岗位的常见考点,所以咱们必须器重对Java语言的学习和了解,即使你在平时工作中应用kotlin较多,也不能漠视对Java基础知识的坚固和学习。 Android根底Android根底,不用说这是面试Android岗位必须要问的内容。要是连这个都答不上来,根本你的面试就提前结束了。Android根底是任何Android面试都须要考核的内容。不过这也是按级别而定,个别高级开发工程师的面试,Android根底只是一笔带过。 那么Android根底有哪些呢?上面咱们简略列举一些供大家参考: 1.Handler机制以及相干常识。2.Activity和Fragment生命周期。3.Android四大组件相干的常识。4.Android过程间通信的形式。5.Context相干的常识。6.Activity的启动模式。7.Android动画相干常识。8.Android自定义组件相干常识。9.Android事件散发机制以及触摸事件抵触的解决。10.ANR产生的起因以及防止ANR的形式。11.内存透露产生的起因以及定位解决的形式。12.OOM产生的起因以及解决的形式。13.Android页面渲染机制以及优化形式。14.LinearLayout、FrameLayout、RelativeLayout和ConstraintLayout的了解和性能比照。15.Android各版本的个性。16.Android屏幕适配的技巧。17.MVC,MVP,MVVM的了解与实际。18.Android的主题、款式、属性相干的内容。19.JNI相干的常识。以上内容是作为一名合格Android开发工程师所必备的知识点,也是常见的考点,请务必每条都要分明把握,这样你在面试过程中能力熟能生巧。 Android源码剖析Android源码剖析,算是要求较高的考核。不过这在大厂面试中十分广泛,因为很多大厂对Android源码的剖析和了解都有相当高的要求。那么常见的Android源码剖析有哪些呢?上面咱们简略列举一些供大家参考: 1.Android零碎的启动流程剖析。2.APP启动的流程剖析。3.Activity的启动流程剖析。4.Zygote过程的创立和启动流程剖析。5.Window窗口创立和加载的流程剖析。6.Dalvik和ART的了解。7.RecyclerView的源码剖析。浏览源码是一件绝对干燥的事件,如果平时工作中波及不到的话就很难坚持下去,因而须要十分强的毅力。不过话又说回来,如果你可能熟练地把握Android源码的话,那么就十分有机会进入大厂了。 Android进阶技能这部分个别是对Android高级开发工程师的考核,次要波及的点次要是一些性能优化,技术细节方面的问题。要想成为一名高级开发工程师,性能优化以及架构设计永远都是绕不开的话题。做技术如果只是广而不深的话,是不可能成为一名高级开发工程师的。只有一直晋升本人的不可替代性,能力进步本人的价值。 那么常见的Android进阶技能有哪些呢?上面咱们简略列举一些供大家参考: 1.App稳定性优化。(crash、性能以及体验等)2.App启动速度优化。3.App内存优化。4.App界面绘制优化。5.App瘦身优化。6.App平安优化。7.网络申请优化。8.WebView应用优化。9.RecyclerView的缓存刷新优化。10.AOP技术的原理和实际。11.gradle脚本继续集成技术。12.App过程保活。 以上只是Android进阶技能的一小部分通用性技术,除此之外还有很多细分畛域相干的进阶技能。总之,如果这项技术是你把握而其他人广泛不理解的,那么它就属于进阶技能。 新技术钻研Android这些年的技术倒退基本上曾经趋势成熟,所以对于新技术的钻研也并不是那么看中,可能面试官就是随口问一下,想要晓得你的学习欲望强不强罢了。那么有什么新的技术能够在业余时间进行钻研呢?上面咱们简略列举一些供大家参考: 1.Android组件化。2.Android插件化。3.Android热更新技术。4.Android JetPack框架技术。5.Kotlin开发技术。6.Android Hook技术。7.AOP技术。8.依赖注入技术IoC。9.跨平台开发技术:ReactNative、Flutter等。 下面的内容,其实很多曾经算不上新技术了,如果你当初还不理解的话,那么你最好花点工夫理解一下,否则我只能说你是真的out了。 开源我的项目源码剖析开源我的项目源码剖析和Android源码剖析一样,也是考核应聘者对原理的了解。如果仅仅只是会应用而不对其原理加以理解的话,那么你也只能算是达到高级程度,这样是无奈进入到大厂的。那么开源我的项目的源码剖析咱们应该怎么做呢?首先咱们须要带着问题一点点浏览源码,搞清楚其外部的实现逻辑,而后梳理出其大抵的设计架构,画出UML图,最初总结出其中使用到的设计模式和思维。 那么有哪些优质的开源我的项目值得咱们去钻研其源码呢?上面咱们简略列举一些供大家参考: OkHttpRetrofitGlideLeakCanaryRxJavaARouterEventBusButterKnifeGreenDaoDagger2以上我列举的基本上都是咱们平时开发过程中常常应用到的开源我的项目,认真钻研和剖析他们的设计思维和精华,并踊跃使用到咱们平时的编码当中去,能够让咱们的技术失去质的飞跃! 算法局部大厂对Android开发工程师的算法也是有肯定要求的,这部分没有什么好说的,关上LeetCode去多刷刷题就能够了。虽说Android开发工程师也须要把握肯定的算法,不过和那些业余做算法的相比必定是没那么高的要求的,咱们并不需要把LeetCode的每道题都刷一遍,只有把一些简略和中等难度的题刷一遍就能够了。 那么常见的Android算法题有哪些呢?上面咱们简略列举一些供大家参考: 1.各类排序。(尤其二分法插入排序、归并排序须要着重把握其思维)2.手写反转链表、链表复制、链表合并。3.手写队列或者链表等数据结构的实现。4.字符串匹配、去重问题。5.双指针算法问题。6.数组查重问题。7.二叉树的遍历和序列化。8.贪婪算法相干问题。 一个好的算法可能极大地晋升利用的性能,如果你平时有心的话就会发现在Android源码中也常常能看到算法的身影,感兴趣的能够浏览一下SparseArray的源码。 最初如果你可能始终保持看到这儿,那么首先我还是非常拜服你的毅力的。不过光是看完而不去付出口头,或者间接进入你的收藏夹里吃灰,那么我写这篇文章就没多大意义了。所以看完之后,还是多多口头起来吧! 以上这些内容均收费分享给大家,须要完整版的敌人,能够加我的技术交换群:34+5659+112,群内有很多Android大佬。 能够十分负责地说,如果你可能保持把我下面列举的内容都一个不落地看完并且全副消化为本人的常识的话,那么你就至多曾经达到了Android中级开发工程师以上的程度,进入大厂技术这块是根本没有什么问题的了。

December 23, 2021 · 1 min · jiezi

关于android:来讨论下-Android-面试该问什么类型的题目

经验过一些面试,也面过一些同学。 被面试官问到头皮发麻,也把候选人问得面红耳赤。 曾恼恨问题刁钻刻薄,也曾狐疑发问跑题超纲。 经验过攻守的角色转换后,沉下心,回顾过往,不由得收回感叹。如果要将“面试”作类比的话,我违心将其比作“相亲”。 之所以这样类比,是因为看似主观的技术面试,其实充斥了各种各样的主观判断。“候选人合不合面试官胃口”可能比“候选人有多优良”更重要一点。 世界这么大,Android 常识体系这么庞杂,我也时不时地狐疑本人,特地是当 pass 一个候选人之后,这种情感愈发强烈。“是不是本人的常识有局限性?”、“我认为要害的问题,真的这么要害吗?” 带着这样的狐疑,我对本人的面试偏好做了一下总结,在此抛砖引玉,欢送各路大神指点迷津。 ps:本篇仅关注 Android 应用层开发相干面试。 八股文式问题Activity 有几种 launch mode?每一种有什么特点?Service 有几种类型?各有什么利用场景?播送有几种注册形式?有什么区别?Activity 有哪些生命周期回调?Kotlin 中的扩大函数是什么?JVM 内存模型是怎么样的?GC 回收算法?Java 中有几种援用类型?这类问题的特点是“只需百度即可立马取得答案”。候选人若做过短缺的筹备,刷过题,就能够滚瓜烂熟。但这些问题也是有价值的,能够疾速判断候选人是否理解 Android 的基本概念。 下面的第 6,7 问,我不太喜爱问。起因是“把握了这个问题对应用层开发能起到什么可见的益处?” 计算机的复杂度高,分层是罕用的升高复杂度的办法,层与层之间造成了壁垒,也进步了层内的效率。将独自一层的复杂度吃透,都可能要花去毕生的精力。并不是否定深挖底层的价值,学有余力当然能够买通好几层,但作为 Android 应用层的面试,重点还是要关注应用层的技术细节。(集体愚见,欢送拍砖~) 但如果面试中全都是八股文式问题,则不太偏心,太过偏袒死记硬背者,也可能因而 pass 掉能力很强,但根本问题筹备不太充沛的候选人。 原理性问题这类问题旨在考查候选人的技术深度,在会用的技术上,晓得为什么用它,及其背地的实现原理。比方: Android 音讯机制是怎么实现的?Android 触摸事件如何传递?Android 视图是怎么被绘制进去的?Android 如何在不同组件间通信?(跨过程,跨线程)Activity 启动流程?AMS、PMS、WMS 创立过程?手写音讯入 MessageQueue 的算法。RecyclerView 缓存机制?原理性问题也能够被百度进去,但可能得多看几篇博客再消化一番,最初用本人的语言组织一下,能力在面试中对答如流。 这类问题不同于八股文的中央不仅在于考查了技术深度,还顺带便考查了了解剖析能力和总结表达能力。把原理性的货色用简略精炼的语言表达进去并让人听懂也是一种能力。 我不太喜爱问 5、6 这样的问题,还是之前提到的那个起因,即“答复出这样的问题对应用层开发能起到什么可见的益处?”。若是 Android 零碎开发工程的面试,倒是很有必要问。 第 7 问将原理性和算法联合,不是让默写算法,而是在考查了解原理的根底上的算法实现能力。若死记硬背原理,通常都写不出。 我的项目经验类问题这类问题旨在考查候选人我的项目经验是否实在,技术栈状况。也可就某一个应用过的技术栈诘问背地的原理。 这类问题对面试官要求最高,若是没有肯定的技术广度和深度,很难就候选人的技术栈问出好问题。 场景类问题场景类问题是指设计一个“待解决的问题”,让候选人当场解决。 所有后面的问题,都能够提前准备,若筹备足够充沛,全副拿下不是问题。而场景题是无奈提前准备的。 如图所示:按住View,移到 View 边界外后松手。这个过程中,哪些触摸事件会被传递,它们是如何传递的? 要做一个 1MB * 10 的帧动画,有什么方法优化内存?如何避免搜寻框适度频繁地发动申请?如何实现弹幕?如何设计直播间礼物队列?设计图片异步加载组件须要留神哪些方面?第 1 问将原理性问题场景化了,对死记硬背不敌对。 这些问题都是应用层开发过程中可能遇到的技术问题,场景类问题是开放性的,没有惟一解,考查候选人的思路、技术积攒及综合使用能力,甚至是抗压能力。 ...

December 23, 2021 · 1 min · jiezi

关于android:Android-表格框架

如何生成一个表格 <com.bin.david.form.core.SmartTable android:id="@+id/table" android:layout_width="match_parent" android:layout_height="300dp" />能够通过注解@SmartTable表格注解 @SmartColumn字段注解@SmartTable(name="用户信息列表")public class UserInfo { @SmartColumn(id =1,name = "姓名") private String name; @SmartColumn(id=2,name="年龄") private int age; ...} List<UserInfo> list = new ArrayList<>(); ... table = (SmartTable<UserInfo>) findViewById(R.id.table); table.setData(list);OK,这就是最简略的注解版。上面看下弱小性能的一般版。只须要创立须要显示的列,设置须要解析的字段就能够,假如须要解析到UserInfo.parent.name,只需parent.name即可。 final Column<String> nameColumn = new Column<>("姓名", "name");final Column<Integer> ageColumn = new Column<>("年龄", "age"); ... tableData = new TableData<>("测试",list,nameColumn,ageColumn...); table.setTableData(tableData); 丑化必定有人说,这点性能,呵呵。来来,咱们坐一下,开始展现丰盛的性能。界面不美观,看这里,格式化一下内容背景: table.getConfig().setContentBackgroundFormat(new BaseBackgroundFormat<CellInfo>() { @Override public int getBackGroundColor() { return ContextCompat.getColor(AnnotationModeActivity.this,R.color.content_bg); } @Override public boolean isDraw(CellInfo cellInfo) { return cellInfo.position%2 ==0; } }); ...

December 23, 2021 · 2 min · jiezi

关于android:Android学习Android广播机制

在Android中实现播送,首先咱们要在Manifest.xml文件中配置一个<receiver/>标签,这个标签必须有一个android:name属性,值为继承自BroadcastReceiver类的接收器类!这个标签还有一个子标签为<intent-filter/>,这个标签很重要,是指定接收器须要接管哪种播送。另外,还有配置一个用户权限:<uses-permission/>,具体的值能够参考官网API文档。另外一个比拟重要的步骤是必须有一个类继承自BroadcastReceiver类,并复写onReceiver办法,在该办法中解决接管到播送后须要解决的事件!上面来看一个具体的例子,有助于更好的了解播送机制是怎么一回事。UI局部就不说了,Activity上就加了一个按钮,点击后发送播送。接收器接管到播送后在终端输入一句话。首先看AndroidManifest.xml文件: `<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"            package="com.gufengxiachen.broadcast"            android:versionCode="1"            android:versionName="1.0">        <uses-sdk android:minSdkVersion="8" />         <application android:icon="@drawable/icon" android:label="@string/app_name">                <activity android:name=".BroadCast"                                    android:label="@string/app_name">                        <intent-filter>                                <action android:name="android.intent.action.MAIN" />                                <category android:name="android.intent.category.LAUNCHER" />                        </intent-filter>                </activity> <receiver android:name=".MyBroadCastReceiver"><intent-filter><action android:name="android.intent.action.EDIT"></action></intent-filter> </receiver>        </application>             <uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission></manifest>  `上面是Activity: `package com.gufengxiachen.broadcast; import android.app.Activity;import android.content.Intent;import android.content.IntentFilter;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button; public class BroadCast extends Activity {        /* Called when the activity is first created. /private Button bound =null;private Button unbound =null;private Button sendBroadCast =null;private SecondBroadCastReceiver sbr =null; public static final String SMS_ACTION="android.provider.Telephony.SMS_RECEVIER";         @Override        public void onCreate(Bundle savedInstanceState) {                super.onCreate(savedInstanceState);                setContentView(R.layout.main);                bound = (Button)findViewById(R.id.bound);                unbound = (Button)findViewById(R.id.unbound);                sendBroadCast = (Button)findViewById(R.id.sendBroadCast);                bound.setOnClickListener(new BoundListener());                unbound.setOnClickListener(new UnboundListener());                sendBroadCast.setOnClickListener(new SendBroadCast());        }        class SendBroadCast implements OnClickListener{        @Override        public void onClick(View v) {        // TODO Auto-generated method stub             Intent intent = new Intent(Intent.ACTION_EDIT);        BroadCast.this.sendBroadcast(intent);        }        }                class BoundListener implements OnClickListener{        @Override        public void onClick(View v) {        // TODO Auto-generated method stub        sbr = new SecondBroadCastReceiver();        IntentFilter filter = new IntentFilter();        filter.addAction(SMS_ACTION);        BroadCast.this.registerReceiver(sbr, filter);                }        }        class UnboundListener implements OnClickListener{             @Override        public void onClick(View v) {        // TODO Auto-generated method stub        BroadCast.this.unregisterReceiver(sbr);        } ...

December 23, 2021 · 1 min · jiezi

关于android:面试官连这些问题都不知道就想要50k

前言自己2016年毕业,目前从事Android开发工作曾经3年啦。就是尘世间一个迷途小开发,二流程序员,居身于小城市,最终也是思考到发展前景的局限性,趁着本人还年老,于是决然裸辞,用一个月工夫面试+温习+总结,最终拿到了抖音Android面经,胜利斩获offe,将本人的面试教训分享给大家,心愿对大家有所帮忙。 面试分享:一面:1.activity和service怎么通信 2.因为扯到了跨过程通信,就让我说一下安卓上有什么跨过程的通信形式 3.说到了管道,让我说一下在Android的时候会用到管道吗 4.Java两个整型相加怎么晓得有没有溢出 5.Java怎么进行线程 6.如果有4个线程同步开始,其中第4个线程要等后面三个线程执行完进行些统计操作,要怎么操作呢。 7.如果不通过应用Java的并发包的现成类库来实现一个CountDownLatch,怎么实现? 8.那么应用你这个CountDownLatch的这3+1个线程,一共须要几个锁呢? 9.晓得大顶堆和小顶堆吗,一个数组建堆,工夫复杂度是多少呢? 10.在堆中找指定的一个元素复杂度是多少? 11.看你简历上也有写网络方面的常识,https的过程说一下 二面:1.Unicode和ASCII的区别 2.Unicode有哪些品种?Java是哪种? 3.json这种格局晓得吗,是怎么的,有什么用? 4.序列化除了json还有什么能够应用? 5.说说Android上的序列化? 6.Java的serializable有个Id,你晓得是有啥用的吗? 7.深拷贝浅拷贝说说? 8.Object的hashcode()用来干嘛,怎么本人实现hashcode? 9.JNI讲讲? 10.一个a包里的B类的c办法,cpp代码中的办法肯定要a_B_c()这样吗 11.Java的泛型讲讲,有啥用?咋实现的 12.在什么状况下能够在运行时获取泛型参 13.上界通配符和下界通配符讲讲 14.两个办法,一个办法的参数是泛型的,一个参数是失常的类(如String),会怎么样 15.输出网址到返回ip的过程】 16.假如你你缓存的ip地址过期了,怎么办 17.你认为DNS机制是怎么解决这个问题的,你能够尝试参考http的缓存机制想想 18.播送有几种,有序和粘性讲讲 19.注册播送的形式,你感觉动态注册播送这个是什么时候执行的呢 20.本地播送 21.线程过程区别 22.讲到内存资源,线程有什么数据是公有的 23.算法:二叉树的右视图 24.算法:两个栈实现队列 25.讲讲工作我的项目遇到的问题 26.有什么想问我的: 三面:自我介绍内核态用户态的区别用户态能够拜访内核态的内存吗,你说的一些有危险的指令,具体是怎么阻止用户态程序去执行有危险的指令的既然用户态不能够拜访内核态的内存,那么在做一些比方网络连接的操作的时候必定须要内核态内存,用户态程序怎么做到应用内核态内存的说到跨过程通信形式,你晓得有什么跨过程通信形式吗?你说到的共享内存,管道,音讯队列,binder他们之间有什么区别吗?你说到播送、内容提供器也有应用binder与AMS通信,那他们与binder之间有什么区别吗(播送、内容提供器的本质是不是就是binder)?为什么要写这样一个测速的程序?两个Activity,一个显示商品列表,一个实现商品详情页,在商品详情页点了关注之后,怎么使得返回商品列表之后也更新了关注状态呢?你说的公布订阅模式,你晓得有什么框架应用了这个设计模式吗?如果两个Activity数据量比拟大呢,要更新相当多的货色呢?你把model设置为单例的话,那这个列表一直下滑,加载更多内容,最初导致占用相当多的内存怎么办?liveData、ViewModel你能够理解下**算法题:www.toutiao.cn转成cn.toutiao.www有什么想问我的?(在头条工作的体验?这个你能够问hr)四面:你是哪里人?为什么抉择投上海的岗位?除了上海,还有什么动向的城市吗?为什么不喜爱北京?上海也是这样啊?问业余。与程序相干的课程有多少?有学计算机组成原理、计算机网络吗?除了看书以外学习路径?你在安卓的群上个别探讨什么货色?印象粗浅的是什么?你这个在wifi的部门不是专门做安卓的吧?有没有安卓方面导师?都是靠你本人摸索的吗?我的项目有几个人在负责,都是你在负责吗?因为什么而接触安卓?你在这个团队里负责什么角色?奉献了多少代码比方有多少页面是你写的?有没有什么社团之类的让你接触安卓?有什么想问我的? HR面:你认为你后面的面试体现怎么样?你感觉抖音(还是字节跳动来着)怎么样?你提到技术驱动型,你认为怎么样才是技术驱动型公司?你提到你是抖音的用户,然而应用频率不高,是因为什么,因为抖音的内容品质不好吗?你提到抖音是音视频相干,你对音视频开发是比拟感兴趣吗?之前工作中有没有遇到什么较大的问题?这个问题是什么起因有没有探索?工作期间有没有遇到什么比拟大的挫折?如果通过了面试,你什么时候能够过去下班?总结:上海抖音经验4面技术面+ hr面。10.25发的意向书 简历的制作简历的作用是展现本人的亮点给面试官,让面试官能够在短时间内迅速理解咱们。简历肯定要把本人的亮点写上去,展现本人的能力。说人话就是:通知面试官本人有多牛叉,这不是体现咱们虚心的时候。不论是我的项目亮点、还是集体技能,都统统写上去。技能点形容要精准,不要含糊。写上简历的内容肯定要是本人把握的内容。例如: 面试倡议1.有急躁且被动 面试不要焦急着去问后果,个别在hr面的时候,她的态度多少可能猜个七七八八的,如果等上一周还没有告诉,那就能够被动去问了。 2.刷题是为了晋升本人的运气运气在面试过程中是十分重要的,刷题的目标很简略,除了坚固咱们所把握的,另一个就是为了能进步在面试中咱们的运气,如果可能问到一样的题是再好不过了,当然这个方法是实用于职级中低岗位。 3.把握根底,留神深度大厂面试最喜爱问两类问题,一类是根底,另一类就是深度。根底局部,无非就是咱们所把握的技术根底内容,基本上只有是有筹备的都没有太大的问题。另一部分就是深度问题,大多波及到本人之前的工作、我的项目,面试官所问的问题不仅仅是停留在外表那么简略,背地的原理是什么才是面试官想要问的。 4.刷面试题 因为文章篇幅无限,文档资料内容较多,本能够提供链接下载,但无奈容易被谐和,所以全副存档,须要这些文档这里的敌人,能够点击我的【Gitee】,心愿可能共同进步,共勉! 最初这也我在工作、面试中学习并总结到的一些知识点, 都是一些比拟典型的、常被问到的问题。如果你平时没有留神去总结的话,那么当你面试被问到的时候可能会是一脸懵圈,就算这个问题你晓得怎么回事,然而你平时没有认真总结, 你也可能会呈现逻辑凌乱的状况,从而错失工作机会。 其实Android开发的知识点就那么多,面试问来问去还是那么点货色。所以面试没有其余的窍门,只看你对这些知识点筹备的充沛水平。so,进来面试时先看看本人温习到了哪个阶段就好。

December 23, 2021 · 1 min · jiezi

关于android:面试造火箭总结-2021大厂-Android-中高级面试题

前言" 面试造火箭,工作拧螺丝 "然我只想拧螺丝,可是我须要用造火箭的技术去寻找拧螺丝的工作,如何能在面试过程中让本人处于不败的境地呢,刷题是一个比拟好的捷径,所以汇总了一些比拟经典的面试题进行了总结,分享给大家。 大厂面试真题滴滴出行:handler原理,主线程发送message给子线程recyclerview列表的优化自定义view,onmeasure的如何测量,测量模式起什么作用?大图片如何解决?sp反对多过程吗?多线程呢?数据库读写在同一个线程吗?一个文本文件中每行有一个手机号或电话号,给定一个手机号,判断该文件中是否存在。给出工夫复杂度较低的计划。作业帮:主线程给子线程发送音讯,handler、threadlocal、threadlocalmap、thread之间是怎么分割的glide的结构设计、btimap的复用和零碎的复用比拟,有什么长处?与生命周期的绑定自定义view测量、布局、绘制,有没有做过简单的自定义view,举个例子一个scrollview里有个button,button有点击事件,列表可滑动,怎么去做事件散发的我的项目架构设计、mvp的实现、model里的请求分页怎么实现?视频播放器、exoplay的优缺点,ijkplay的优缺点小米:handler、massage、massager、Loop之间的关系和区别view的绘制和事件散发,Android的绘制机制?布局的绘制流程?Activity在oncreate中finish,生命周期是怎么的?Glide、okhhtp、retrofit等三方库的原理,简略论述视频播放器封装、弹幕的实现,本人我的项目的构造和路由框架、新闻列表的实现、mpv的实现等android内存泄露有哪些?怎么解决?handler为什么会产生内存泄露?它的gcRoot是什么?强脆弱虚援用哪些能够解决内存泄露?为什么?一个view上每秒显示一个数字,每隔一秒扭转一次,想出解决办法,越多越好代码健壮性和品质怎么管制?appbug怎么统计的?怎么解决的?一个string值传入办法,值扭转吗?换成stringbuild呢?Java垃圾回收、分代算法的原理,如何断定对象死亡?gcRoot有哪些?Java内存模型,哪些区能够作为gcRoot?内存怎么开释?线程的工作内存放在哪?强脆弱虚四种援用的区别?给定数组-1,0,1,0,-1,-4,0找出其中3个数相加为0的全副组合,给出解决方案判断单链表相交,找出节点,手写代码反转单链表,手写代码给定两个链表,存储着两个16进制数,链表的一个节点存储着16进制数的其中一个数,从高位到低位,求相加的值,返回一个链表,链表中保留相加的后果。(先反转链表,而后逐位相加,记录进位值,再与高位相加)手写代码百度:抽奖转盘,分四份,中奖概率为5%,UI和逻辑怎么实现数据库查问,至多参加了三项考试,且分数均超过80的人,写出sql语句线程同步:线程1循环输入1到10,线程2循环输入1到10,启动线程1、2,要求做到线程2输入5之后,线程1才开始输入(用wait、notify实现)jvm内存模型,垃圾回收机制手写单例kotlin类的扩大,【】方括号该扩大什么?怎么在我的项目中进行架构设计的?MVP模式的长处,如何实现?MVVM理解吗?网络申请大量图片并展现在页面上,须要留神什么?网络申请资源复用、图片缓存等内存泄露有哪些?怎么解决?数据查出来为什么用cursor游标,而不间接返回个list汇合?缓存了10000条数据、怎么查出来并显示?我的项目中数据库大略是什么量级的?数据量及占内存量?content provide是干什么的?Google为什么设计它?一个网格页面、显示9张图片,弱网状况下,滑到下一页,怎么去调度线程加载下一页面的图片?理解的设计模式,代理模式流程、观察者模式流程、波及几个类理解哪些google推出的比拟新的库、livedata?databinding?jetpack?kotlin绝对于Java有什么劣势?函数式编程的劣势?函数式和面向对象比拟文件中每行有一个手机号对应用户信息,给定手机号查找出对应信息,如果手机号排序了,怎么查?任意二叉树,求出其中最远的两个节点间的间隔对将来职业生涯的布局?Android 中高级面试题汇总Android 中高级面试题汇总包含:Java根底、Android根底、UI控件篇、网络通信篇、架构设计篇、性能优化篇、源码流程篇、新技术篇、面试篇九个章节,一共1932页。 Java根底动态外部类和非动态外部类的比拟多态的了解与利用java办法的多态性了解java中接口和继承的区别线程池的益处,详解,单例线程池的长处及其原理为什么不举荐通过Executors间接创立线程池BlockingQueue及其实现深刻了解ReentrantLock与ConditionJava多线程:线程间通信之LockSynchronized 关键字原理ReentrantLock原理HashMap中的Hash抵触解决和扩容机制JVM常见面试题JVM内存构造类加载机制/双亲委托Android根底Activity知识点(必问) Activity 启动过程全解析Fragment 知识点onSaveInstanceState 以及 onRestoreInstanceState 应用4onConfigurationChanged应用以及问题解决Fragment 知识点 Fragment 的通信问题, 新建 Fragment 为何不要在构造方法中传递参数为什么官网举荐 Fragment.setArguments(Bundlebundle)这种形式来传递参数,而不举荐通过构造方法间接来传递参数呢?Androidx 下 Fragment 懒加载的新实现Fragment全解析系列Google-Fragment概览Google-与其余Fragment通信Service 知识点 Handler知识点(必问)Android主线程阻塞解决及优化深刻聊聊Android音讯机制中的音讯队列的设计深刻了解MessageQueue你真的懂Handler.postDelayed()的原理吗?Handler.postDelayed()是如何准确提早指定工夫的Handler提早音讯执行机制,会阻塞吗?Intent知识点 Android跨过程传递大内存数据数据存储UI控件篇屏幕适配 Android屏幕适配和计划Android 目前稳固高效的UI适配计划次要控件优化 RecyclerView优化事件散发与嵌套滚动 NestedScrollingParent & NestedScrollingChild动态化页面构建计划组件与布局网络通信篇网络协议 彻底了解 WebSocket 原理,附残缺的实战代码(蕴含前端和后端)架构设计篇MVP架构设计组件化架构性能优化篇启动优化内存优化绘制优化安装包优化源码流程篇开源库源码剖析Glide 源码剖析Glide 面试题聊一聊对于Glide在面试中的那些事简历上如果写Glide,请留神以下几点...Glide OOM问题解决办法汇总OkHttp源码剖析Okhttp连接池复用机制Okhttp 流程和优化的实现OkHttp的整个异步申请流HttpEngine中的sendRequest办法详解OkHttp解析大总结Okhttp工作队列工作原理Android 网络优化,应用 HTTPDNS优化 DNS,从原理到 OkHttp 集成Retrofit源码剖析RxJava源码剖析RxJava原理与源码剖析新技术篇实战问题面试篇开源文档面试题合集 android事件散发机制,请具体说下整个流程android view绘制机制和加载过程,请具体说下整个流程android四大组件的加载过程,请具体介绍下Activity的启动模式A、B、C、D别离是四种Activity的启动模式,那么A->B->C->D->A->B->C->D别离启动,最初的activity栈是怎么样的Activity缓存办法Service的生命周期,两种启动办法,有什么区别怎么保障service不被杀死动态的Broadcast 和动静的有什么区别Intent能够传递哪些数据类型Json有什么优劣势、解析的原理一个语言的编译过程动画有哪几类,各有什么特点Handler、Looper音讯队列模型,各局部的作用怎么退出终止AppAndroid IPC:Binder 原理了解Window和WindowManagerBitmap的解决如何实现一个网络框架(参考Volley)ClassLoader的基础知识插件化框架形容:dynamicLoadApk为例子热修复:Andfix为例子线程同步的问题,罕用的线程同步Asynctask和线程池,GC相干(怎么判断哪些内存该GC,GC算法)数据库性能优化:索引和事务APK打包流程和其内容网络劫持的类型原理操作系统过程和线程的区别...... 须要完整版《2022年Android中高级面试题汇总》的敌人能够【点击此处收费支付!】

December 22, 2021 · 1 min · jiezi

关于android:CG-Kit探索移动端高性能渲染

内容起源:华为开发者大会2021 HMS Core 6 Graphics技术论坛,主题演讲《CG Kit摸索挪动端高性能渲染》 演讲嘉宾:华为海思麒麟GPU团队工程师 大家好,我来自华为海思麒麟团队的一名GPU研发工程师,明天给大家带来的主题是“CG Kit摸索挪动端高性能渲染”。 华为图形计算服务(Computer Graphics Kit,简称“CG Kit”)提供最前沿计算机图形学畛域的渲染框架、插件SDK与GPU扩大接口,帮助开发者开掘硬件极限性能,大幅升高开发难度,帮忙开发者发明出体验更佳的产品。 那么,CG Kit能提供哪些解决方案呢?一、Vulkan渲染框架实际 Vulkan是最新的图形规范API,相较于OpenGL具备肯定的劣势,并且OpenGL这个规范曾经进行演进,将来图形学基本上以Vulkan向前演进。举个例子,挪动端的光线追踪就是在Vulkan中形容,并且在OpenGL中是没有的。但问题在于,Vulkan非常灵活,它相较OpenGL有肯定的应用门槛,所以就须要有基于Vulkan高性能的渲染框架,以此提供实际架构和计划,充分发挥出硬件性能。 二、高性能渲染插件 CG Kit提供多线程渲染、拍照超分、体积云、遮挡剔除等一系列渲染能力的插件,以便于三方单干的顺利进行,比方去年的网易《天谕》手游就集成了拍照超分的算法。 三、开发者工具链 CG Kit也提供了残缺的开发者工具链,咱们能够帮忙开发者迅速定位解决渲染性能和性能问题。大家能够设想一下,如果将来工具能够自动识别游戏场景中的一些性能/性能问题并反馈给开发者,这将极大晋升咱们的开发效率。 四、前沿图形技术摸索 始终以来CG Kit团队都在对前沿图形技术进行摸索,比方,咱们如何把AI的技术利用到图形渲染中,目前咱们已在AI超分、主动3D人脸建模,AI协同动画生成等方面有所研究成果。 Vulkan渲染框架实际 Vulkan渲染框架实际,为开发者提供Vulkan渲染解决方案优化、渲染加强插件和渲染技术文档,比方,文档中会介绍一些API应用策略、资源缓存应用优化、Vulkan的兼容性问题等等。 后面提到Vulkan是比拟新的API,它的Command Buffer机制能够人造反对多线程渲染。因为Vulkan比拟灵便,CG Kit就会针对Vulkan的API做了简化封装,应用起来更便当。 其次, CG Kit也反对基于物理的渲染,PBR能够实在地反映物体外表光照的属性,通过PBR咱们渲染进去的物体会更加的实在。 同时,CG Kit提供了资源管理器,能够将所用到的大量管线资源尽可能地进行复用,从而升高开销,进步渲染性能。 最初,CG Kit同样反对提供HDR10的显示能力,配合HDR屏幕的显示优化,最终出图会有更好的动静范畴。 动态超分组件 上面介绍一下游戏拍照超分的插件,游戏是具备社交属性的,分享就是社交里十分重要的一个环节。在游戏过程中常常会遇到一些十分值得分享的精彩时刻,比方实现了一个里程碑的工作,获取了一个限量款精美的皮肤,或者曾经实现了一个虚构人物形象定制……在这些时刻,游戏玩家十分迫切地想把这些精彩的霎时分享给本人的敌人,那就须要用到拍照的性能,然而如何让拍照的成果更好呢? 针对拍照成果,CG Kit提供了两种解决方案。 第一种解决方案就是针对具备独立NPU的高端手机,例如麒麟980、990和麒麟9000芯片对应的手机,这些具备独立高端NPU的手机能够间接调用AI超分接口,这样画面细节得以显著减少,画面格调更加清晰天然,从上面的比照图能够看出,解决后的图片人物面部细节显著有晋升。 而针对那些没有独立NPU芯片的手机,咱们也提供了一种通用的解决方案,叫作FilterSR,这是基于通用GPU的一种算法,利用这种算法后,没有NPU的手机也能够大幅晋升画面成果,并且相较于传统的办法它的锯齿感和画面清晰度也有很大的晋升。值得一提的是,《天谕》就集成了咱们拍照超分的算法。 体积云组件CG Kit也提供了挪动端高性能的体积云插件,体积云技术能够实时动静地渲染出高度实在云海中全局光照场景,并且反对玩家在云中任意地穿梭,画面能够实在还原云朵的物理个性。比方,玩家在穿梭过程中扑面而来的粒子感,还有实在的光照成果,包含云朵边缘的细节等等,都会有十分好的出现。从下图能够看出,这个云朵的色彩是随着工夫的变动在逐渐变动的,就是因为咱们对光照做了24小时的适配。 在体积云的状态方面,咱们反对实在和卡通两个格调,还反对任意形态的Mash转换成体积云,这样能够满足开发者不同的定制需要。 从性能角度看,在麒麟980这个平台上,咱们能够做到4毫秒以内渲染1帧,插件显示上,同时提供了PC端和挪动端的插件,一般来说开发者是在挪动端上进行编辑调试,并在挪动端上以SO的形式集成,而它的包体大小只有400K左右。 体积雾组件上面介绍一下体积雾组件,在一些特定游戏格调的游戏中,具备高度实在的光和雾的成果会给大家带来十分好的体验,比方去年有一款十分火的游戏,叫《赛博朋克2077》,它外面就有很多雾效。 主机3A大作中,体积雾个别是通过体渲染来实现的,不同于外表渲染只须要渲染物体外表,体渲染要渲染物体外部,渲染工作量可能是外表渲染的几十倍上百倍,体渲染对硬件的性能要求十分高,这也是始终没有在挪动端落地的起因。 而CG Kit体积雾的组件对传统的体渲染做了很多优化,我简略介绍两种优化。 第一种优化是针对多光源场景下的优化。多光源的时候,渲染的工作量是成几十倍的减少,针对这个问题咱们引入了光源剔除技术,让光照计算只产生在光源所影响的部分范畴内,这样就能够大幅地升高渲染的工作量。 第二种优化是,为了晋升渲染的效率,咱们采纳了升高采样率的形式,然而升高采样率当前会存在画面细节有余的问题,为了解决这个问题,咱们引入了时域滤波技术,把以后帧和上一帧的后果交融,这样也会失去一个十分不错的后果。数据结构也针对这些优化做了相对性的适配。 通过后面一系列的优化之后,咱们能够在挪动端进行实时高性能的体积雾渲染,从性能角度来看,在麒麟980平台上,能够做到4毫秒一帧渲染;在集成模式上,能够同时提供PC端和挪动端插件,反对PC端对编辑调试,挪动端以SO形式集成,挪动端插件包体小于500KB。 、 AI捏脸最初介绍一下AI捏脸,在游戏场景中如果可能做到虚构形象千人千面,而且它的虚构形象可能有游戏玩家一部分的脸部特色,就会晋升用户的代入感。AI捏脸以侧面自拍照的形式输出,在调用咱们的AI接口当前,会生成一组高度还原用户脸部特色的捏脸参数,基于捏脸参数主动生成3D模型,同时咱们在谋求几何类似的同时,还将实在纹理、模型纹理相交融,使得它的纹理能提现玩家的一些面部特色,还原性更高。咱们在集成上提供了非常简单的接口,开发者能够便当地进行适配,也能够大幅地晋升他的开发成果。 因为咱们是纯端侧运行,在中高端机型AI捏脸工夫小于4s,稳定性很高。同时咱们的捏脸范畴岂但反对面部,而且还反对五官、发型、眼镜等;咱们还融入了高度还原的实在纹理,有更好的还原度,并提供好看度调整性能,能够管制最终的输入图好看度。在开发效率上,开发者只须要两步就能够调用咱们的性能,第一步PC端进行模型自在适配,第二步在挪动端以用户的自拍照为输出就能够调用咱们的接口,整个过程非常简单便捷。 心愿大家能够进行深度的单干,谢谢! 更多精彩内容,请见华为开发者官方论坛→https://developer.huawei.com/...

December 22, 2021 · 1 min · jiezi

关于android:手语服务让信息世界没有障碍

内容起源:华为开发者大会2021 HMS Core 6 App Services技术论坛,主题演讲《手语服务,助您构建信息无障碍利用》。 演讲嘉宾:华为消费者云服务 手语服务技术总监 北京师范大学传授 郑璇 大家好。明天为大家分享一下HMS Core为什么要做手语服务,背地的故事和停顿。 首先看一下咱们服务的对象,据世界部门组织考察,以后有4.6亿听障群体,而我国至多有2700万听障群体,并且每年国家也有将近2.3万的听障儿童出世,然而仅有不到5%的听障群体应用助听器等辅助设施。因而因为信息的缺失,咱们听障敌人在日常的学习交换中存在一些艰难,这就是为什么在公共场所利用场景中手语的渠道十分迫切。 手语是什么?对听障群体意味着什么?对健全的群体意味着什么?咱们邀请到北京师范大学郑璇传授跟大家做分享。大家好,我是北京师范大学的郑璇,很快乐跟大家面对面交换。 其实我是聋人,大家可能看不出我左耳戴了助听器,然而我的书面语还是不错的,我的手语翻译是听力健全人士,然而她能够流畅地应用手语,我想在这一刻,聋人和听人界线不那么明显了,这要感激科技的提高。 明天要跟大家分享的是《解锁手语明码,走进无声世界》。说到手语大家可能感觉很神秘,手语从语言学来说,是一种语言,我在读博士的时候,在复旦大学中文系语言学与利用语言学业余,我所做的是从语言学角度钻研手语到底是什么样的语言,手语是用手的手形、地位、静止、手掌朝向、配合面部表情和身材姿势,还有必要的口形,表白特定意思的交际工具,是一种真正的语言。为什么这么说?因为手语是有残缺简单零碎的语言,有它的语音、语汇、语法,如果孩子的父母是聋人,就能够把手语当作第一语言学习,这时倒退的门路和书面语根本是同步的,而且咱们从脑科学的角度能够证实,聋人在用手语的时候,大脑外面沉闷的区域根本也是左脑的语言区。 对于手语的位置曾经有了比拟成熟的法律规定,比方2006年联合国的残疾人权力公约,以及起初在中国签订的联合国教科文组织的岳麓宣言强调,手语和书面语是平等的,是两种语言,每个国家有任务爱护促成推广手语的应用,目前世界聋人联合会的数据显示,世界有66个国家和地区通过立法抵赖了手语的位置。 咱们国家在通用手语推广上,也有很大的提高,比方2015年和2021年别离是“十三五”和“十四五”的终点,咱们公布了两期《国家手语和盲文的规范化行动计划》,2018年的时候,咱们出台了《国家通用手语词表》,这个回升到了国家语言文字标准的高度,在2019年又出版了《国家通用手语词典》,如果大家有趣味的话,能够间接从华为利用市场上下载APP。 上图是一个中国残疾人艺术团的演员演示“中国”的手语打法,“中国”的手语打法是伸出手指,从左肩到右肩往下,这时模拟汉服当中传统服装的式样,来模拟中国的概念。 手语对聋人敌人意味着什么? 我是一名聋人,所以我十分粗浅地感触到手语对咱们的重要性,可能大家不晓得,超过95%的聋孩子,他们的父母是听力健全的人,这就意味着在家里他们不能像失常孩子一样顺利的跟父母沟通。国外有一个词形容:餐桌综合症,即便在餐桌上咱们跟父母都是最相熟的陌生人。所以,手语的染指能够扭转这个情况。 当他们成长进入学校当前,手语能够作为教学语言,连贯孩子和世界,促使他们对常识的学习;当他们走入社会当前,能够通过手语跟普通人建设连贯,当社会上每个人都会手语,聋人敌人就会感触到平等和尊重;当他老了当前,手语会为他营造一个精神家园,聋人敌人对手语是十分有感情的,已经有句诗刻画他们对手语的感情,“如果你砍掉了我双手,我就用双臂打手语,如果你砍断了我的双臂,我就用双肩打手语”。 我已经屡次在高校教手语课,学生们问我:“老师,手语要怎么示意我爱你?”手语对青年学生来说是技能能力,对刚出生的婴儿能够作为早教益智的伎俩开发他的智力,当他走入社会当前,如果他会手语,其实有助于构建信息无障碍的社会,让他晓得每个人都能够接收世界的多元性,让这个世界更美妙。 此外,手语能够在特地的时候沟通,比方当环境嘈杂的时候,当机密交换的时候,手语都十分地有用,当老去当前,有助人助己的意义,以前是他帮忙他人,然而每个人都会老去,听力会降落,手语能够作为视觉语言撑持他的沟通。 我本人也有过多年的手语教学提倡和科研的经验,我本人十分观赏一句话“如果你接收了一个人,那你必将接收他的语言,反过来如果你回绝了一个人的语言,那就是回绝了他自身”。我已经在美国的孔子学院,教美国的聋孩子学习中国的手语和中国文化,我已经在重庆师范大学的课堂上教空乘业余学生学习手语,我已经拍摄过《我和我的祖国》手语歌的MV,我也已经跟南京聋人学校的老师和同学们,一起编创咱们的国学手语的图书。 做这些事的时候,我就有一个粗浅的感触,手语其实并不是小众的语言,离每个人都不远,咱们说手语是桥梁,能够连贯世界上每一座孤岛,手语是资源,让咱们明确每种语言独特的美,它还是人生教训的传承,是团结奋斗的桥梁,是聋听共建的纽带。 我作为参谋参加这样的我的项目,咱们的愿景是:手语并不边远,触手可及。其实每一个人在年轻当前,在生病当前,在某些非凡的情况下,都会变成所谓的“残障者”。 手语不神秘,其实手语人人可学。比如说,这个手势示意一个人,那人从远到近是来,从近到远是去,两个人相遇、离开、追赶,你看,咱们一下能够把一串手语词学会,真的并不难。 手语也不狭窄,海纳百川,咱们不心愿聋人敌人外部有什么手语群体、书面语群体的撕裂,我真心心愿,咱们能够一起交换、一起建设家园、一起共享古代生存的便当。 手语更加不是一个小众的语言,咱们能够开脑洞,能够打造一个手语的生态系统和新的经济体。从玻璃墙到破壁者,华为走出了要害一步。 参加这个我的项目的过程当中,其实也经验了十分多的崎岖,我集体十分地荣幸能参加其中。我本人是一名聋人,我本人是手语言学的研究者,对于咱们来说,这个产品能够帮忙到咱们。然而在当初可能不是所有的人都可能了解,然而咱们非常高兴通过一段时间的攻关,终于有了一个阶段性的成绩,我想,光明给了咱们彩色的眼睛,然而我却用它寻找光明,从光明中走过的眼睛,是世界上最亮堂的眼睛。 最初我想教大家两个手语。 第一个是欢送欢呼的意思,咱们欢呼这个平凡的时代。 第二个是谢谢,谢谢大家给了咱们无声世界新的心愿。 谢谢大家。 从郑老师的分享能够看到,手语无论对听障人士还是健听人都十分重要,国家也意识到这个问题,并颁布了相应的法律条款。深圳市特区的条例往年9月1日刚刚施行的,还有10月1日北京市的条例、10月 22日广电总局公布了“十四五”的布局,都在推动和激励应用手语。 咱们总结了三点国家法律条款。 第一,在党和国家以及中央重大流动中安顿国家通用手语翻译。 第二,市级以上电视台应踊跃创造条件,播出节目装备手语或者字幕,停办手语栏目,推广和应用国家通用手语。 第三,飞机、铁路、地铁等公共交通应为听力残疾人提供国家通用手语服务。 华为公司做手语服务,并不是从零到一开始做的,咱们在2018年跟欧洲聋人协会和世界聋人协会推出了Storysign的我的项目,是面向三到六岁的儿童浏览的场景,应用华为手机对着儿童浏览书籍拍摄,能够通过人工智能的技术主动产生手语动画。 在Storysign我的项目的根底上,咱们开发了手语服务,不再面向非凡的年龄特殊人群,咱们开发的是面向凋谢人群、凋谢场景、智能手语动作生成的。 手语不仅包含手部动作,还有唇动和面部表情整个的表白,因为手语是一种视觉语言,跟书面语不太一样,有本人的语法,比方“我没有带身份证”,在手语当中不是逐词打的,整个的手语是依照视觉语言,会先打“身份证”“我”“带”“没有”,其次是手语动作是否连贯天然,再就是是否自带面部表情。 华为手语服务次要有三个模块。 第一个模块,首先把语音转成文本,这是在日常生活当中常常应用语音转文字的能力,这是比拟成熟的技术。 第二个模块,从文本转到手语表白,这里有一个手语翻译的关键技术,利用的是华为公司的自研的语言大模型,再联合手语语言学数据做的,咱们跟其余技术不一样的是,咱们有训练大模型,在特定语义环境下训练,所以成果十分好。 第三个模块,文本产生3D动作,这是十分难的技术问题,咱们是利用了神经网络多模态的模型实现的。当然这个过程当中,咱们不仅有人工智能算法和数据,还把手语语言学跟手语翻译、手语生成两个模块进行深度交融,输入3D的动作,最初通过3D虚拟人出现。要驱动3D虚拟人,还要通过骨骼静止带动肢体静止,再进行3D虚拟人的渲染出现。 以后的语种只反对中国的手语,后续对英文也有布局。对于词汇也是十分重要的,方才郑老师也讲了,国家通用词典2019年公布了当前,其实外面收录了8214个词汇,然而实际上还有很多词汇并没有输出,咱们跟郑老师一起,把日常生活当中,没有被国家通用词典收录的词进行拓展,以后笼罩了一万多个词汇,当然还会持续减少,预估在明年达到2万的词汇,根本能够笼罩90%-95%的日常词汇。 如果您想将手语服务使用到您的业务场景当中,也反对3D虚拟人定制,比方将穿红衣服的3D小姐姐换个造型。 以上介绍的是手语服务的关键技术,那手语服务的能力在什么场景中利用呢? 在To C的利用场景中,面向一般消费者,能够升高交换和信息获取难度,实现沟通无障碍。 第一, 日常生活。日常生活能够用于比方在家庭、敌人交换的场景。 第二, 教育学习。手语也是有口音和中央规范的,国家始终在推广国家通用的手语,而真正懂或者是十分纯熟业余手语的人是非常少的,那么基于国家通用手语规范的华为手语服务,利用于聋人敌人的教育是十分好的。 第三, 用于对社会资讯的获取。比方游览资讯、就餐、购物等场景。 手语服务在一些To B的场景中也施展了很大作用。比方国家激励或推动在一些行业里进行推广和应用国家通用手语。 ...

December 22, 2021 · 1 min · jiezi

关于android:Android构建aab程序提示MinSdkVersionException

Android构建aab程序时,咱们个别状况下都会应用apksigner工具来进行v1、v2加密签名: apksigner sign --ks [.jks文件门路] --ks-key-alias [别名] --out [签名过导出的aab文件] [行将签名的aab]但往往会提醒如下谬误: Exception in thread "main" com.android.apksig.apk.MinSdkVersionException: Failed to determine APK's minimum supported platform version. Use --min-sdk-version to override at com.android.apksigner.ApkSignerTool.sign(ApkSignerTool.java:387) at com.android.apksigner.ApkSignerTool.main(ApkSignerTool.java:88)Caused by: com.android.apksig.apk.MinSdkVersionException: Failed to determine APK's minimum supported Android platform version at com.android.apksig.ApkSigner.getMinSdkVersionFromApk(ApkSigner.java:957) at com.android.apksig.ApkSigner.sign(ApkSigner.java:278) at com.android.apksig.ApkSigner.sign(ApkSigner.java:214) at com.android.apksigner.ApkSignerTool.sign(ApkSignerTool.java:381) ... 1 moreCaused by: com.android.apksig.apk.ApkFormatException: Missing AndroidManifest.xml at com.android.apksig.ApkSigner.getAndroidManifestFromApk(ApkSigner.java:913) at com.android.apksig.ApkSigner.getMinSdkVersionFromApk(ApkSigner.java:955) ... 4 more在官网 apksigner 却没有明确提醒要增加最低构建版本,依据谬误提醒,以及官网的文档阐明,咱们很容易晓得,须要制订最低构建版本进行验证即可 apksigner sign --ks [.jks文件门路] --ks-key-alias [别名] --min-sdk-version [你的最低反对版本] --out [签名过导出的aab文件] [行将签名的aab]这样就能够失常构建出v1+v2的aab包了。 ...

December 22, 2021 · 1 min · jiezi

关于android:让您的应用支持新式的-Emoji-符号吧

Emoji 已无处不在,自公布以来 emoji 已成为咱们语言中不可或缺的一部分,它活泼无效的表达力带来了语言文字层面的改革。您可能不会想到,连银行利用、健身利用或外卖利用也都应该反对 emoji。Emoji 当初曾经遍布短信等通信利用,曾经成为咱们语言的一部分。如果您的利用蕴含文本视图,那么它应该反对 emoji,至于起因,且听我娓娓道来。 遇到的问题 如果您的利用没有对 emoji 进行相应的解决,较早版本的 Android 可能不晓得如何去显示它们。在大多数状况下,只会显示一个空白方格,咱们称之为 "豆腐"。在未正确处理 emoji 的利用中,在本来应该显示 emoji 的地位将会显示出一个 "豆腐块",这可能会给用户带来困惑。例如,如果用户在 TODO 利用的工作列表里,向 EditText 中增加一个 表情,此时用户看到 "豆腐" 呈现在屏幕上而没有显示输出的 表情时,用户则会认为利用存在 bug。 为了使 emoji 更加乏味,在很多状况下,一个 emoji 是由其它多个 emoji 组成的。比方 是 和 的组合。 如果您输出肌肉的表情,而利用显示了胳膊和色彩方块,那么就不仅会让用户感到困惑,同时对于不同肤色格调的表述也有失精确,从而升高了利用的用户体验。 随着语言的倒退,emoji 也在一直进化。每年新的 emoji 会以 Unicode 的模式增加到新的 Android 发行版本中,但惋惜的是,没有路径可能将新的 emoji 字体增加到 Android S 之前的版本。 解决方案emoji2 库曾经集成到了 AppCompat 1.4,这意味着您只需降级至 AppCompat 1.4 版本,便可在 API 19 及更高版本上显示风行的 emoji。AppCompat 中的所有 TextView 都默认反对,因为咱们增加了主动配置,所以它能够配置本人来加载正确的 emoji 字体。如果须要,您能够在 XML 或者代码中为特定的 TextView 敞开该性能。 ...

December 22, 2021 · 1 min · jiezi

关于android:应付Android面试看这一篇文就够了含面试真题

前言 我的微信小号有一组非凡的敌人。 他们从 CSDN上看到我之前公布的博客后,留下邮箱询要学习材料的,我在邮箱发送材料之后咱们相互增加微信意识聊上的,和他们沟通交流中能够显著感觉他们的待业焦虑。 一方面放心受疫情的影响,心仪的公司缩招或者不招;另一方面则是本人技术的不自信,放心面试不通过。我很能了解他们,有一个哥们咱们前后断断续续聊了将近有一个月的工夫。 上周,这个哥们冲动地跟我说:“多亏了你分享的那份学习材料,我拿到小米的offer了”!尽管咱们素未谋面,然而我是真的替他快乐,感觉帮到他了本人也很有成就感。 上面是这位哥们这段时间面试总结进去的面经,让我帮忙给分享进去,他说心愿大家都和他一样可能找到称心的工作。 面试题第一遍,间接看解法多解法,比拟解法优劣,默写好的解法第二遍,关上leetcode,间接开始写多种解法比拟,调优第三遍,过一天之后,再反复做题第四遍,过了一周,再来重复练、第五遍,面试前一周,恢复性训练通过以上办法反复练习,大略刷100题就足以应酬面试,如果每天刷3道,大略筹备一个月即可 接下来是整顿的一系列大厂的面试题及具体解析:(面试题的具体解析我都整顿成了几个文档,有须要的能够点击这里间接支付)[字节]() Android 面试真题解析Java 根底局部 HashMap 和 HashTable 以及 CurrentHashMap 的区别synchronized 和 volatile 、ReentrantLock 、CAS 的 区别JVM 类加载机制、垃圾回收算法比照、Java 虚拟机结 构等Java 的四大援用Java 的泛型, 和 的区别Java 线程有哪些状态,有哪些锁,各种锁的区别final 、finally、finalize 区别接口和抽象类的区别sleep 、wait、yield 的区别,wait 的线程如何唤醒它?java 中==和 equals 和 hashCode 的区别String、StringBuffer、StringBuilder 区别.........Jvm局部 Jvm 内存区域是如何划分的?Jvm 内存模型是怎么样的?String s1 = "abc"和 String s2 = new String("abc")的区别, 生成对象的状况如何判断对象可回收?GC 的罕用算法?Minar GC 和 Full GC 的区别?说一下四种援用以及他们的区别?类加载的过程?类加载的机制,以及为什么要这样设计?.........计算机网络局部 TCP 与 UDP 的区别三次握手、四次挥手。为啥是三次不是两次?HTTPS 和 HTTP 的区别。HTTP 2.0,3.0?浏览器输出一个 URL,按下回车网络传输的流程?TCP 建设连贯后,发包频率是怎么的?OKHttp如何验证证书的合法性?https 中哪里用了对称加密,哪里用了非对称加密,对加 密法(如 RSA)等是否有理解?client 如何确定本人发送的音讯被 server 收到?谈谈你对 WebSocket 的了解WebSocket 与 Socket 的区别谈谈你对安卓签名的了解请解释安卓为啥要加签名机制?.........Android 面试题 ...

December 22, 2021 · 2 min · jiezi

关于android:Framework没掌握好字节技术大牛精编解析笔记带你系统学习

把握Framework能给工作带来那些帮忙?其实不须要别的,你去 Github 上看一下 腾讯 Matrix 的源码,就晓得 Framework 的常识有多重要了。 像掉帧监控,函数插桩,慢函数检测,ANR 监控,启动监控,都须要对 Framework 有比拟深刻的理解,能力晓得怎么去做监控,利用什么机制去监控,函数插桩插到哪里,反射调用该反射哪个类哪个办法哪个属性……另外 Framework 作为 Android 框架层,为 App 提供了泛滥 API 去调用 ,然而很多机制都是 Framework 包装好了给 App 来用的,如果不晓得这些机制的原理,那么很难去在这根底上做优化。 如何学习Framework?咱们齐全能够跟着这份由字节技术团队出品的《Android Framework 开发揭秘》。这份材料全文共19万字,蕴含109个知识点,通过经典Binder、Handler、AMS等面试题解析加深你对Android Framework框架层的了解 第一章|系统启动流程剖析Android启动概览 init.rc解析Zygote 面试题 第二章|Binder解析宏观意识Binderbinder的jni办法注册binder驱动 数据结构 启动service_manageraddService流程 第三章|Handler解析源码剖析 难点问题 Handler常问面试题 第四章|AMS解析通信形式系统启动系列 AMS面试题解析 第五章|WMS解析Activity与Window相干概念WindowManagerService 计算Activity窗口大小的过程剖析 WindowManagerService对窗口的组织形式剖析 WindowManagerService 对输入法窗口(Input Method Window)的治理剖析 第六章|PKMS Android10.0 源码解读PKMS 概述信息PKMS角色地位 置信这份材料,肯定能够为大家在FrameWork的学习上提供强有力的帮忙和撑持,快人一步成为真正的高级Android开发者,须要这份《Android Framework 开发揭秘》的敌人能够点击这里收费支付。

December 22, 2021 · 1 min · jiezi

关于android:Android插件化系列一Binder机制ClassLoader

系列前言从明天开始,我会花较多的工夫来跟大家一起学习Android插件化。这一篇文章是Android插件化的启动篇。 Android插件化是之前几年里的一个很火的技术概念。从2012年开始就有人在钻研这门技术。从毛糙的AndroidDynamicLoader框架,到第一代的DroidPlugin等,继而倒退到第二代的VirtualApk,Replugin等,再到现如今的VirtualApp,Atlas。插件化在国内逐步的倒退和欠缺,却也在近几年呈现了RN等替代品当前缓缓会走向弱势。 只管插件化技术的钻研热潮曾经过来,然而这门技术自身还是有着大量的技术实际,对于咱们理解Android机制很有帮忙。所以从这篇文章开始我会写一系列的文章,加上本人对插件化的实际,最初会去从源码角度剖析几个优良的插件化库,造成一套残缺的插件化的理论体系。 上面是插件化的技术框架,也是我这个系列文章的行文思路, 一. Binder机制网上剖析Binder机制的文章曾经很多了,在这篇文章里,我不会去解说Binder的应用,而是会去解说分明Binder的设计思路,设计原理和对于插件化的应用。 为什么须要Binder首先咱们晓得,Android是基于Linux内核开发的。对于Linux来说,操作系统为一个二进制可执行文件创立了一个载有该文件本人的栈,堆、数据映射以及共享库的内存片段,还为其调配非凡的外部治理构造。这就是一个过程。操作系统必须提供偏心的应用机制,使得每个过程能失常的开始,执行和终结。 这样呢,就引入了一个问题。一个过程能不能去操作别的过程的数据呢?咱们能够想一下,这是相对不能呈现的,尤其是零碎级的过程,如果被别的过程影响了可能会造成整个零碎的崩塌。所以咱们很天然的想到,咱们应该把过程隔离起来,linux也是这样做的,它的虚拟内存机制为每个过程调配间断的内存空间,过程只能操作本人的虚拟内存空间。同时,还必须满足过程之间放弃通信的能力,毕竟团结力量大,单凭单个过程的独立运作是不能撑起操作系统的性能需要的。 为了解决这个问题,Linux引进了用户空间User Space和内核空间Kernel Space的区别。用户空间要想拜访内核空间,惟一形式就是零碎调用。内核空间通过接口把应用程序申请传给内核解决后返回给应用程序。同时,用户空间过程如果想降级为内核空间过程,须要进行安全检查。 补充常识:零碎调用次要通过两个办法: copy\_from\_user():将用户空间的数据拷贝到内核空间copy\_to\_user():将内核空间的数据拷贝到用户空间 以上就是linux零碎的跨过程通信机制。而咱们马上要说的Binder,就是跨过程的一种形式 Binder模型Binder是一种过程间通信(IPC)形式,Android常见的过程中通信形式有文件共享,Bundle,AIDL,Messenger,ContentProvider,Socket。其中AIDL,Messenger,ContentProvider都是基于Binder。Linux零碎通过Binder驱动来治理Binder机制。 Binder的实现基于mmap()零碎调用,只用拷贝一次,比惯例文件页操作更快。微信开源的MMKV等也是基于此。有趣味的能够理解一下。首先Binder机制有四个参与者,Server,Client两个过程,ServiceManager,Binder驱动(内核空间)。其中ServiceManager和Binder驱动都是零碎实现的,而Server和Client是须要开发者本人实现的。四者之中只有Binder驱动是运行在内核空间的。 这里的ServiceManager作为Manager,承当着Binder通信的建设,Binder的注册和传递的能力。Service负责创立Binder,并为他起一个字符模式的名字,而后把Binder和名字通过通过Binder驱动,借助于ServiceManager自带的Binder向ServiceManager注册。留神这里,因为Service和ServiceManager也是跨过程通信须要Binder,ServerManager是自带Binder的,所以绝对ServiceManager来说Service也就相当于Client了。 Service注册了这个Binder当前,Client就能通过名字取得Binder的援用了。这里的跨过程通信单方就变成了Client和ServiceManager,而后ServiceManager从Binder表取出Binder的援用返给Client,这样的话如果有多个Client的话,屡次返回援用就行了,然而事实上援用的都是放在ServiceManager中的Service。 当Client通过Binder驱动跟Service通信的时候,往往须要获取到Service的某个对象object。这时候为了平安思考,Binder会把object的代理对象proxyobject返回,这个对象领有截然不同的办法,然而没有具体能力,只负责接管参数传给真正的object应用。 所以残缺的Binder通信过程是 OK,跨过程通信就讲清楚了。接下来咱们讲讲插件化中的Binder。 Binder与插件化首先,咱们先回顾一下Activity的启动过程,Instrumentation调用了ActivityManagerNative,这个AMN是咱们的本地对象,而后AMN调用getDefault拿到了ActivityManagerProxy,这个人AMP就是AMS在本地的代理。相当于binder模型中的Client,而这个AMP继承的是IActivityManager,领有四大组件的所有须要AMS参加的办法。本地通过调用这个AMP办法来间接地调用AMS。这样,咱们就调用到了AMS启动了Activity。 那么,AMS如何与Client进行通信呢?当初咱们通过Launcher启动了Activity,必定要通知Launcher “没你什么事了,你洗洗睡吧”。大家能够看到,这里单方的角色就产生了扭转,AMS须要去发消息,承当Client的角色,而Launcher这时候作为Service提供服务。而这次通信同样也是应用的Binder机制。AMS这边保留了一个ApplicationThreadProxy对象,这个对象就是Launcher的ApplicationThread的代理。AMS通过ATP给App发消息,App通过ApplicationThread解决。 以上,就是Binder机制在Android中的使用,咱们前面会通过hook这个过程实现插件化。 总结看了这么多,可能还是很多敌人不懂Binder。我也是这样,很长一段时间都不晓得Binder到底指的是啥。起初我看到了这样一种定义: 从过程间通信的角度看,Binder 是一种过程间通信的机制;从 Server 过程的角度看,Binder 指的是 Server 中的 Binder 实体对象;从 Client 过程的角度看,Binder 指的是对 Binder 代理对象,是 Binder 实体对象的一个近程代理从传输过程的角度看,Binder 是一个能够跨过程传输的对象;Binder 驱动会对这个逾越过程边界的对象对一点点非凡解决,主动实现代理对象和本地对象之间的转换。相干视频:无所不能的Binder底层原理解析;插件化 二. ClassLoader双亲委托模型Java中默认有三种ClassLoader。别离是: BootStrap ClassLoader:启动类加载器,最顶层的加载器。次要负责加载JDK中的外围类。在JVM启动后也随着启动,并结构Ext ClassLoader和App ClassLoader。Extension ClassLoader:扩大类加载器,负责加载Java的扩大类库。App ClassLoader:零碎类加载器,负责加载应用程序的所有jar和class文件。自定义ClassLoader:须要继承自ClassLoader类。ClassLoader默认应用双亲委托模型来搜寻类。每个ClassLoader都有一个父类的援用。当ClassLoader须要加载某个类时,先判断是否加载过,如果加载过就返回Class对象。否则交给他的父类去加载,持续判断是否加载过。这样 层层判断,就到了最顶层的BootStrap ClassLoader来试图加载。如果连最顶层的Bootstrap ClassLoader都没加载过,那就加载。如果加载失败,就转交给子ClassLoader,层层加载,直到最底层。如果还不能加载的话那就只能抛出异样了。 通过这种双亲委托模型,益处是: 更高效,父类加载一次就能够防止了子类多次重复加载更平安,防止了外界伪造java外围类。Android中的ClassLoaderandroid从5.0开始应用art虚拟机,这种虚拟机在程序运行时也须要ClassLoader将类加载到内存中,然而与java不同的是,java虚拟机通过读取class字节码来加载,然而art则是通过dex字节码来加载。这是一种优化,能够合并多个class文件为一个classes.dex文件。 android一共有三品种加载器: BootClassLoader:父类结构器PathClassLoader:个别是加载指定门路/data/app中的apk,也就是装置到手机中的apk。所以个别作为默认的加载器。DexClassLoader:从蕴含classes.dex的jar或者apk中,加载类的加载器,可用于动静加载。看PathClassLoader和DexClassLoader源码,都是继承自BaseDexClassLoader。 public DexClassLoader(String dexPath, String optimizedDirectory, String librarySearchPath, ClassLoader parent) { super(dexPath, new File(optimizedDirectory), librarySearchPath, parent);}public class PathClassLoader extends BaseDexClassLoader { public PathClassLoader(String dexPath, ClassLoader parent) { super(dexPath, null, null, parent); //见下文 }}public class BaseDexClassLoader extends ClassLoader { private final DexPathList pathList; public BaseDexClassLoader(String dexPath, File optimizedDirectory, String libraryPath, ClassLoader parent) { super(parent); //见下文 //收集dex文件和Native动静库【见大节3.2】 this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory); }}咱们能够看到PathClassLoader的两个参数都为null,表明只能承受固定的dex文件,而这个文件是只能在装置后呈现的。而DexClassLoader中optimizedDirectory,和librarySearchPath都是能够本人定义的,阐明咱们能够传入一个jar或者apk包,保障解压缩后是一个dex文件就能够操作了。因而,咱们通常应用DexClassLoader来进行插件化和热修复。 ...

December 22, 2021 · 1 min · jiezi

关于android:Android设置透明半透明等效果

设置通明成果 大略有三种 1、用android零碎的通明成果Java代码  android:background="@android:color/transparent" 例如 设置按钮Java代码  <Button android:background="@android:color/transparent"     android:text="@+id/Button01"     android:id="@+id/Button01"     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:textColor="#ffffff" />  2、用ARGB来管制Java代码  半透明<Button android:background="#e0000000" /> 通明<Button android:background="#00000000" />  ```3、设置alphaJava代码 View v = findViewById(R.id.content);//找到你要设通明背景的layout 的id v.getBackground().setAlpha(100);//0~255透明度值       android 窗体通明的,光明度等的设置技巧设置透明度(这是窗体自身的透明度,非背景)WindowManager.LayoutParams lp=getWindow().getAttributes(); lp.alpha=0.3f; getWindow().setAttributes(lp); alpha在0.0f到1.0f之间。1.0齐全不通明,0.0f齐全通明设置光明度WindowManager.LayoutParams lp=getWindow().getAttributes(); lp.dimAmount=0.5f; getWindow().setAttributes(lp); getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); dimAmount在0.0f和1.0f之间,0.0f齐全不暗,1.0f全暗设置背景含糊getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, WindowManager.LayoutParams.FLAG_BLUR_BEHIND); 以上设置对dialog对话框同样无效   Activity的通明、半透明成果的设置transparentres/values/styles.xml<resources>    <style name="Transparent">      <item name="android:windowBackground">       @color/transparent_background    </item>      <item name="android:windowNoTitle">true</item>      <item name="android:windowIsTranslucent">true</item>        <item name="android:windowAnimationStyle">         @+android:style/Animation.Translucent   </item>    </style>  </resources> res/values/color.xml<?xml version="1.0" encoding="utf-8"?>  <resources>    <color name="transparent_background">#50000000</color>  </resources>  //留神://color.xml的#5000000前两位是通明的成果参数从00--99(通明--不怎么通明),//后6位是色彩的设置 ...

December 22, 2021 · 1 min · jiezi

关于android:大厂面试轻轻松松就能过拥有它不吃亏

前言在互联网做了几年之后,去大厂“镀镀金”是大部分人的首选。大厂不仅待遇高、福利好,更重要的是,它是对你业余能力的背书,大厂工作背景多少会给你的简历减少几分竞争力。我本人和敌人也去过很多大厂面试过,整顿了一份面试题和面试教训分享给大家,心愿能帮忙到你们。 面试题总结一. 数据结构与[算法]()罕用的数据结构有哪些?数组(1).如何在一个1到100的整数数组中找到失落的数字?(2).如何在给定的整数数组中找到反复的数字? 【小米】(3).如何在未排序整数数组中找到最大值和最小值? 【字节跳动】**(4).在Java中如何从给定数组中删除多重复制?(5).大数相加【今日头条】链表(1).那查问第一个跟倒数第二个呢?(这就不一样了,第一个间接给了头结点,倒数第二个须要从倒数第一个开始查问,走两步) 【腾讯】(2).arrayList底层原理 【滴滴】【字节跳动】(3).如何在一次遍历中找到单个链表的中值? 【中国安全】(4).如何证实给定的链表是否蕴含循环?如何找到循环的头节点? 优酷(5).两个有穿插的单链表,求交叉点 【华为】(6).如何失去单[链表]()的长度? 【360】(7).如何在不应用递归的状况下逆转单[链表]()? 【小米】【美团】(8).怎么判断[链表]()有环?【 滴滴】队列&堆栈(1).如何应用栈实现队列的性能?【广州荔枝】(2).两个栈实现一个队列 【蘑菇街】(3).两个队列实现一个栈 【腾讯】(4).比照一下队列和栈,以及它们底部实现 【腾讯】二叉树(1).如何在给定的二叉树中执行先序遍历?【百度】(2).如何实现后序遍历[算法]()? 【百度】(3).如何在给定数组中执行二分法搜寻? 【苏宁】(4).已知前序遍历为{1,2,4,7,3,5,6,8},中序遍历为{4,7,2,1,5,3,8,6},它的[二叉树]()是怎么样的? 【58】(5).输出两棵[二叉树]() A 和 B,判断 B 是不是 A 的子结构。 【爱奇艺】(6).请实现两个函数,别离用来[序列化二叉树]()和反[序列化二叉树]()。【 YY】(7).[均衡二叉树]()和[红黑树]()的区别?【字节跳动】(8).什么是[均衡二叉树](),它有什么特色 【美团】(9).B 树,B+树HashMap(1).HashMap的底层原理是什么?线程平安么? 【百度】【美团】(2).HashMap中put是如何实现的?【滴滴】(3).谈一下hashMap中什么时候须要进行扩容,扩容resize()又是如何实现的?(4).什么是哈希碰撞?怎么解决? 【滴滴】【美团】(5).HashMap和HashTable的区别 【小米】(6).HashMap中什么时候须要进行扩容,扩容resize()是如何实现的? 【滴滴】(7).hashmap concurrenthashmap原理 【美团】(8).arraylist和hashmap的区别,为什么取数快?【字节跳动】图(1).旋转输入矩阵( 2).给定一个矩阵 int matrixAm,每行每列都是增序的,实现一个[算法]()去寻找矩阵中的某个元素 element. 【搜狗】排序算法有哪些?(1).top-k[排序]()(堆[排序](),位图法) 【美团】(2).冒泡[排序]()的手写 【华捷艾米】(3).堆[排序]()[算法]()的手写【华捷艾米】(4).椭圆形场地有两个赛道,能够同时提供两匹马较量,两匹马较量后,能够获知两匹马中跑的快的那匹马,然而没有计时工具。问题,如何最优的[算法]()(较量次数起码),获知10匹马中速度最快的三匹马 【阿里】(5).输出一个整型无序数组,对堆[排序]()的办法使得数组有序 【阿里】(6).如何应用疾速[排序]()[算法]()对整数数组进行[排序]()? 【CVTE】查找算法(1).有序数组的[二分查找]()[算法]() 【百度】串(1).给定一个字符串,请你找出其中不含有反复字符的 最长子串的长度。 【字节跳动】(2).给定一个字符串 s,找到 s 中最长的回文子串。你能够假如 s 的最大长度为 1000。请写出以下算法的工夫复杂度冒泡[排序]()法 插入[排序]()法 堆[排序]()法 [二叉树]()[排序]()法其余算法(1).罕用的对称加密[算法](),有什么同? 【字节跳动】(2).如何在无序(有正数)的数组中查找是否存在和为target的两个数组合,twoSum(); 【字节 】二. Java根底(1).什么状况下会产生栈内存溢出?(2).如果让你写一段栈溢出的代码你会什么写,一个栈大略有多大,为什么?每个线程都有这样大小的一个栈吗? 【美团】(3).JVM中一次残缺的GC流程是怎么的,对象如何降职到老年代?(4).介绍下GC回收机制与分代回收策略。(5).Java中有几种援用关系,它们的区别是什么?(6).GC收集[算法]()有哪些?它们的特点是什么?(7).如何判断一个对象是否被回收,有哪些GC[算法](),理论虚拟机应用最多的是什么GC[算法]()?【美团】(8).Jvm内存 构造说一下。a.形容JVM内存模型。【西方头条】(9).JVM DVM ART的区别【360】(10).形容GC机制。Class会不会回收?用不到的Class怎么回收?【西方头条】 三、Android体系(1). Acitvity的生命周期是什么样的? a. Acitvity的生命周期,如何捣毁一个Activity? 【美团】 ...

December 22, 2021 · 1 min · jiezi

关于android:启动优化-有向无环图

前言说到 Android 启动优化,大家第一工夫可能会想到异步加载。将耗时工作放到子线程加载,等到所有加载工作加载实现之后,再进入首页。 多线程异步加载计划的确是 ok 的。但如果遇到前后依赖的关系呢。比方工作2 依赖于工作 1,这时候要怎么解决呢。 最简略的计划是将工作1 丢到主线程加载,而后再启动多线程异步加载。 如果遇到更简单的依赖呢。 工作3 依赖于工作 2, 工作 2 依赖于工作 1 呢,这时候你要怎么解决。更简单的依赖关系呢 总不能将工作 2,工作 3 都放到主线程加载吧,这样多线程加载的意义就不大了。 有没有更好的计划呢? 答案必定是有的,应用有向无环图。它能够完满解决先后依赖关系。 重要概念有向无环图(Directed Acyclic Graph, DAG)是有向图的一种,字面意思的了解就是图中没有环。经常被用来示意事件之间的驱动依赖关系,治理工作之间的调度。 顶点:图中的一个点,比方顶点 1,顶点 2。 边:连贯两个顶点的线段叫做边,edge。 入度:代表以后有多少边指向它。 在上图中,顶掉 1 的入度是 0,因为没有任何边指向它。顶掉 2 的入度是 1, 因为 顶掉 1 指向 顶掉 2. 同理可得出 5 的入度是 2,因为顶掉 4 和顶点 3 指向它 拓扑排序:拓扑排序是对一个有向图结构拓扑序列的过程。它具备如下特点。 每个顶点呈现且只呈现一次。若存在一条从顶点 A 到顶点 B 的门路,那么在序列中顶点 A 呈现在顶点 B 的后面因为有这个特点,因而经常用有向无环图的数据结构用来解决依赖关系。 上图中,拓扑排序之后,工作2必定排在工作1之后,因为工作2依赖 工作1, 工作3必定在工作2之后,因为工作3依赖工作2。 ...

December 22, 2021 · 1 min · jiezi

关于android:一篇文章读懂Android-Framework

本文旨在将Framework的框架描绘出来,次要是记录我一段时间对于android framework的学习,心愿抛砖引玉,对于读者有肯定的帮忙。 前言写在后面: 1、有没有必要学习linux内核? 我认为是很有必要的。学习linux内核有助于咱们加深对一些概念的了解,比方“过程”、“线程”。举荐入门的教程:中国大学MOOC李治军老师的操作系统课程 2、有没有必要本人编译android源码? 非必须,能够间接用android studio查看sdk源码,除非要调试一些性能。然而要亲自操练起来能力更相熟。android framework与咱们的开发非亲非故,本文将从开机,即framework的初始化讲起,而后再波及android运行过程中的几个应用场景。比方用户启动app(点击桌面图标后产生了什么),用户应用app(一次触摸,Android到底干了啥)。其中会波及主线程、anr、handler、binder、zygote、app的入口是什么、自定义view为什么要三步走等一些咱们常常接触的概念,并一一解答。波及源码为api 27。 一、初始化篇当按开机键的时候,设施首先执行BootLoader,BootLoader负责把Linux内核从加载到内存,并执行内核的初始化,最初内核将读取init.rc文件,并启动该文件中定义的各种服务程序。Android framework对于内核而言就是一个Linux程序而已,而该程序就在init.rc文件中被定义。Android framework的初始化过程由此开始。 首先被创立的是zygote过程,这是零碎中运行的第一个Dalvik虚拟机程序,顾名思义,前面所有Dalvik虚拟机过程都是通过它“孵化”而来(学过生物的咱们都晓得,人体所有的细胞都是由受精卵决裂而来,所以自己感觉这个名称获得十分精确奇妙)。 zygote孵化出的第一个 Dalvik1 过程叫做 SystemServer,是Framework相当重要的过程。 SystemServer 仅仅是该过程的别名,而该过程具休对应的程序仍然是 app\_process, 因为 SystemServer 是从 app\_process中孵化进去的。Ams、Wms、Pms等等都在此过程中创立,能够说SystemServer治理Framework所有的流动。 注1:Andoird 4.4引入ARTSystemServer 中创立了一个 Socket2 客户端,并有AmS负责管理该客户端,之后所有的 Dalvik 过程都将通过该 Socket 客户端间接被启动。当要启动新的 APK 过程时 ,AmS 中会通过该 Socket 客户端向 zygote 过程的 Socket服务端发送一个启动命令,而后zygote会孵化出新的过程。 注2:此处波及Android过程中通信的一种办法Socket,学过计算机网络的读者应该对此有肯定的概念。当前还会提及pipe、binder两种过程通信办法,无论如何,它们最终的目标都是为了让开发者跨过程调用时都像是在进行本地调用。至于它们的优缺点以及实现形式,读者能够自行探索。1、zygote的启动后面咱们提到内核初始化时,会启动在init.rc文件中配置的程序,zygote相干的配置信息如下: service zygote /system/bin/app\_process -Xzygote /system/bin --zygote --start-system-server简略阐明一下这个语句的意思,内核会执行/system/bin/app\_process3目录下的程序,启动一个叫zygote的服务。其中参数--start-system-server, 仅在指定 -- zygote 参数时才无效,意思是告知Zygotelnit启动结束后孵化出第一个过程SystemServer。由此可知,zygote启动后做的事件之一就是启动SystemServer。 注3:Android反对64位当前,会依据不同的ABI别离执行/system/bin/app\_process32和/system/bin/app\_process64目录。当 zygote 服务从 app\_process 开始启动后,会启动一个 Dalvik 虚拟机,而虚拟机执行的第一个 Java类就是 ZygoteInit.java。(app过程fork自zygote过程,所以ZygoteInit.main同样也是app的入口,只不过会依据过程的不同执行不同的逻辑。这就是有时候咱们程序谬误日志的调用栈外面能够看到"…ZygoteInit.main……"的起因。)ZygoteInit会做另外两件事:一是后面提到的,启动一个Socket服务端口,该Socket端口用于接管启动新过程的命令;二是预加载的Framework大部分类及资源供后续app应用。zygote fork app过程时,并不需要复制这一部分,而是应用共享内存的形式。 总结: zygote的过程启动后次要做了三件事:别离是启动一个Socket服务,用于接管启动新过程的命令、预加载的Framework大部分类及资源以及启动SystemServer。 ...

December 22, 2021 · 9 min · jiezi

关于android:Android系统性能优化

什么是性能 快,稳,省,小,这四点很形象的代表了性能的四个方面,同时也让咱们晓得咱们App当初是否是款性能良好的APP,如果有一项不达标,那么阐明咱们的利用有待优化。 很多时候咱们重视性能实现,保障能用,然而咱们会发现,这样的利用很难拿的出手,外面的槽点太多了,性能很差,然而又不晓得从哪里下手进行优化,那么咱们就一步一步来,看看咱们到底应该怎么优化咱们的APP。 1 、布局优化和UI相干的首先就是布局,特地是在开发一些简单界面的时候,通常咱们都是采纳布局嵌套的办法,每个人的布局思路不太一样,写出的也不太一样,,所以就可能造成嵌套的层级过多。 官网 屏幕上的某个像素在同一帧的工夫内被绘制了屡次。在多层次的UI构造外面,如果不可见的UI也在做绘制的操作,这就会导致某些像素区域被绘制了屡次。这就节约大量的CPU以及GPU资源。 文言 显示一个布局就好比咱们盖一个房子,首先咱们要测量房子的大小,还要测量房间外面各个家具的大小,和地位,而后进行摆放同时也要对房子进行装修,如果咱们是一层,都在明面上,干起活来敞亮也轻松,可是有的人的房子,喜爱各种隔断,分成一个一个的大隔断间,每个大隔断间里还有小隔断间,小隔断间里有小小隔断间,还有小小小隔断间。。。N层隔断间。 看到这些头皮发麻吧,而且是一个大隔断间外面所有的小隔断,小小隔断等等都测量完摆放好,能力换另外一个大隔断,天呢,太浪费时间了,不能都间接都放里面吗?也好摆放啊,这么搞我怎么摆,每个隔断间都要装修一遍,太浪费时间了啊。 咱们的Android虚拟机也会这么埋怨,咱们家原本就不富裕,什么都要省着用,你这么搞,必定运行有问题啊,那么多嵌套的小隔断间须要解决,都会占用cpu计算的工夫和GPU渲染的工夫。显示GPU适度绘制,分层如下如所示: 通过色彩咱们能够晓得咱们利用是否有多余档次的绘制,如果一路飘红,那么咱们就要相应的解决了。 所以咱们有了第一个优化版本: 优化 1.0如果父控件有色彩,也是本人须要的色彩,那么就不用在子控件加背景色彩如果每个自控件的色彩不太一样,而且能够齐全笼罩父控件,那么就不须要再父控件上加背景色彩尽量减少不必要的嵌套能用LinearLayout和FrameLayout,就不要用RelativeLayout,因为RelativeLayout控件绝对比较复杂,测绘也想要耗时。做到了以上4点只能说祝贺你,入门级优化曾经实现了。 针对嵌套布局,谷歌也是陆续出了一些新的计划。对就是include、merge和ViewStub三兄弟。 include能够进步布局的复用性,大大不便咱们的开发,有人说这个没有缩小布局的嵌套吧,对,include的确没有,然而include和merge联手搭配,成果那是杠杠滴。 merge的布局取决于父控件是哪个布局,应用merge相当于缩小了本身的一层布局,间接采纳父include的布局,当然间接在父布局外面应用意义不大,所以会和include配合应用,既减少了布局的复用性,用缩小了一层布局嵌套。 ViewStub它能够按需加载,什么意思?用到他的时候喊他一下,再来加载,不须要的时候像空气一样,在一边静静的呆着,不吃你的米,也不花你家的钱。等须要的时候ViewStub中的布局才加载到内存,多勤俭持家啊。对于一些进度条,提示信息等等八百年才用一次的性能,应用ViewStub是极其适合的。这就是不必不晓得,一用戒不了。 咱们开始进化咱们的优化 优化 1.1应用include和merge减少复用,缩小层级ViewStub按需加载,更加轻便可能又有人说了:背景复用了,嵌套曾经很精简了,再精简就实现了不了简单视图了,可是还是一路飘红,这个怎么办?面对这个问题谷歌给了咱们一个新的布局ConstraintLayout。 ConstraintLayout能够无效地解决布局嵌套过多的问题。ConstraintLayout应用束缚的形式来指定各个控件的地位和关系的,它有点相似于 RelativeLayout,但远比RelativeLayout要更弱小(照抄隔壁IOS的束缚布局)。所以简略布局简略解决,简单布局ConstraintLayout很好使,晋升性能从布局做起。 再次进化: 优化 1.2简单界面可抉择ConstraintLayout,可无效缩小层级2、绘制优化咱们把布局优化了,然而和布局非亲非故的还有绘制,这是间接影响显示的两个基本因素。 其实布局优化了对于性能晋升影响不算很大,然而是咱们最容易下手,最间接接触的优化,所以不论能晋升多少,哪怕只有百分之一的晋升,咱们也要做,因为影响性能的中央太多了,每个局部都晋升一点,咱们利用就能够晋升很多了。 咱们平时感觉的卡顿问题最次要的起因之一是因为渲染性能,因为越来越简单的界面交互,其中可能增加了动画,或者图片等等。咱们心愿发明出越来越炫的交互界面,同时也心愿他能够晦涩显示,然而往往卡顿就产生在这里。 这个是Android的渲染机制造成的,Android零碎每隔16ms收回VSYNC信号,触发对UI进行渲染,然而渲染未必胜利,如果胜利了那么代表一切顺利,然而失败了可能就要延误工夫,或者间接跳过去,给人视觉上的体现,就是要么卡了一会,要么跳帧。 View的绘制频率保障60fps是最佳的,这就要求每帧绘制工夫不超过16ms(16ms = 1000/60),尽管程序很难保障16ms这个工夫,然而尽量升高onDraw办法中的复杂度总是切实有效的。 这个失常状况下,每隔16ms draw()一下,很参差,很晦涩,很完满。 往往会产生如下图的状况,有个便秘的家伙霸占着,一帧画面拉的工夫那么长,这一下可不就卡顿了嘛。把前面的工夫给占用了,前面只能延后,或者间接略过了。 既然问题找到了,那么咱们必定要有相应的解决办法,基本做法是 加重onDraw()的累赘。 所以 第一点: onDraw办法中不要做耗时的工作,也不做过多的循环操作,特地是嵌套循环,尽管每次循环耗时很小,然而大量的循环势必霸占CPU的工夫片,从而造成View的绘制过程不晦涩。 第二点: 除了循环之外,onDraw()中不要创立新的部分对象,因为onDraw()办法个别都会频繁大量调用,就意味着会产生大量的零时对象,不进占用过的内存,而且会导致系统更加频繁的GC,大大降低程序的执行速度和效率。 其实这两点在android的UI线程中都实用。 降级进化: 优化2.0onDraw中不要创立新的部分对象onDraw办法中不要做耗时的工作其实从渲染优化里咱们也牵扯出了另一个优化,那就是内存优化。 3、内存优化内存透露指的是那些程序不再应用的对象无奈被GC辨认,这样就导致这个对象始终留在内存当中,占用了没来就不多的内存空间。 内存透露是一个迟缓积攒的过程,一点一点的给你,温水煮青蛙个别,咱们往往很难直观的看到,只能最初内存不够用了,程序奔溃了,才晓得外面有大量的透露,然而到底是那些中央?预计是狼烟遍地,千疮百孔,都不晓得如何下手。怎么办?最让人好受的是内存透露状况那么多,记不住,了解也不容易,要害是老会遗记。怎么办呢?老这么上来也不是事,总不能面试的时候突击,做我的项目的时候手足无措吧。所以肯定要记住理解GC原理,这样才能够更精确的了解内存透露的场景和起因。不懂GC原理的能够先看一下这个JVM初探:内存调配、GC原理与垃圾收集器 原本GC的诞生是为了让java程序员更加轻松(这一点隔壁C++苦楚的一匹),java虚构机会主动帮忙咱们回收那些不再须要的内存空间。通过援用计数法,可达性分析法等等办法,确认该对象是否没有援用,是否能够被回收。 有人会说真么强悍的性能看起来无懈可击啊,对,实践上能够达到打消内存透露,然而很多人不按常理出牌啊,往往很多时候,有的对象还放弃着援用,但逻辑上曾经不会再用到。就是这一类对象,游走于GC法律的边缘,我没用了,然而你又不晓得我没用了,就是这么赖着不走,空耗内存。 因为有内存透露,所以内存被占用越来越多,那么GC会更容易被触发,GC会越来越频发,然而当GC的时候所有的线程都是暂停状态的,须要解决的对象数量越多耗时越长,所以这也会造成卡顿。 那么什么状况下会呈现这样的对象呢? 根本能够分为以下四大类: 1、汇合类透露 2、单例/动态变量造成的内存透露 3、匿名外部类/非动态外部类 4、资源未敞开造成的内存透露 1、汇合类透露 汇合类增加元素后,仍援用着汇合元素对象,导致该汇合中的元素对象无奈被回收,从而导致内存泄露。 举个栗子: static List<Object> mList = new ArrayList<>(); for (int i = 0; i < 100; i++) { Object obj = new Object(); mList.add(obj); obj = null; }当mList没用的时候,咱们如果不做解决的话,这就是典型的占着茅坑不拉屎,mList外部持有者泛滥汇合元素的对象,不泄露天理难容啊。解决这个问题也超级简略。把mList清理掉,而后把它的援用也给开释掉。 ...

December 22, 2021 · 5 min · jiezi

关于android:高级Android插件化最全开源项目看这一篇就够了

前言插件化技术倒退到当初其实曾经很成熟了,然而相应的问题,如果没有真正地去实际过,基本不理解其中有多少问题,会牵涉到多少技术细节,多少被外人膜拜的表面光鲜的技术大牛都被『插件化』这三个字折磨地死去活来,这对于 Android 整个生态的侵害也让人无奈漠视。 那么这个组件化是什么意思呢?我说下我本人的了解,可能不对,还请指教: 通过 gradle 配置的形式,将打 debug 包和 release 包离开。这样会有一个益处,开发一个模块,在 debug 的时候,能够打成一个 apk ,独立运行测试,能够齐全独立于整个宿主 APP 的其余所有组件;待到要打 release 包的时候,再把这个模块作为一个 library ,打成 aar ,作为整个宿主 APP 的一部分。而 debug 和 release 的切换都是通过 gradle 配置,能够做到无缝切换。至于模块之间的跳转,能够用别名的形式,而不是用 Activity 和 Fragment 类名。这样所有的模块和宿主 APP 都是齐全解耦的,彻底解决了并行开发的可能造成的穿插依赖等问题。依照这个思路,咱们再来看看一些其余的细节: 在 Android 里有一个比拟爽的一点是,作为 library 的时候,aar 里的援用依赖,在宿主 Application 里也有同样的援用依赖,并不会打包两份到宿主 Application 里;模块之间的跳转,除了应用别名的形式,我能想到的还有另外一种形式,同样是通过 gradle 脚本,将跳转用到的类打成一个 jar ,作为一个 API 服务提供给其余模块作为编译期依赖(provided)引入;各个 library 在 debug 的时候作为 apk ,要独立打包运行测试,这时就须要有一个启动 Activity ,而 library 是不须要的,我的想法是搁置两个 AndroidManifest.xml ,应用 sourceSets 别离在 debug 和 release 的时候加载不同的 AndroidManifest.xml。对于Android开发者而言,插件化技术曾经是进阶Android高级工程师的必备技能之一。我这里有一份【高级Android插件化强化实战】材料,心愿能帮到大家! ...

December 22, 2021 · 1 min · jiezi

关于android:Android入门教程-Notification-使用

应用过程NotificationManager - 用于提醒的治理,例如发送、勾销NotificationCompat.Builder - Builder 模式结构 notification;Notification - 提醒,可能显示在状态栏和下拉栏上;结构实例能设定 flags;NotificationDemo界面中搁置了很多个按钮,每个按钮发送的提醒并不完全相同。流程都一样。设定一个 NotificationManager, 应用 NotificationCompat.Builder 来建设 Notification;点击按钮时 NotificationManager.notify 发送提醒 其中有接管播送发送 notification 的例子。 build.gradle局部代码,最低API 19: android { compileSdkVersion 23 buildToolsVersion "23.0.1" defaultConfig { applicationId "com.rust.rustnotifydemo" minSdkVersion 19 targetSdkVersion 23 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } }}次要代码 MainActivity.java : import android.app.NotificationManager;import android.app.Notification;import android.app.PendingIntent;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.support.v4.app.NotificationCompat;import android.support.v7.widget.Toolbar;import android.view.MotionEvent;import android.view.View;import android.view.inputmethod.InputMethodManager;import android.widget.Button;import android.widget.EditText;class notifyBroadcast extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { NotificationManager nMgr = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); Intent goHome = new Intent(Intent.ACTION_MAIN); goHome.addCategory(Intent.CATEGORY_HOME); NotificationCompat.Builder builder = new NotificationCompat.Builder(context) .setSmallIcon(R.drawable.signal_horn_26px) .setContentText("点击返回桌面") .setContentTitle("Go home") .setTicker("来自播送的提醒") .setContentIntent(PendingIntent.getActivity(context, 0, goHome, 0)); Notification notificationBroadcast = builder.build(); notificationBroadcast.flags |= Notification.FLAG_AUTO_CANCEL; nMgr.notify(002, notificationBroadcast);/* id雷同;此提醒与 Notification 2 只能显示一个 */ }}public class MainActivity extends AppCompatActivity { public static final String BroadcastNotify = "com.rust.notify.broadcast"; private EditText editContent; private Button sendNotification; private Button notifyButton1; private Button notifyButton2; private Button cleanButton; private Button notifyBroadcast; private int notificationId = 001; private BroadcastReceiver notifyReceiver; private InputMethodManager inputMgr; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); IntentFilter filter = new IntentFilter(BroadcastNotify); notifyReceiver = new notifyBroadcast(); registerReceiver(notifyReceiver, filter); /* get the widgets */ editContent = (EditText) findViewById(R.id.et_content); sendNotification = (Button) findViewById(R.id.btn_send_content); notifyButton1 = (Button) findViewById(R.id.btn_notify_1); notifyButton2 = (Button) findViewById(R.id.btn_notify_2); notifyBroadcast = (Button) findViewById(R.id.btn_notify_broadcast); cleanButton = (Button) findViewById(R.id.btn_clean_notification); /* 结构一个Bitmap,显示在下拉栏中 */ final Bitmap notifyBitmapTrain = BitmapFactory .decodeResource(this.getResources(), R.drawable.train); /* 管理器-用来发送notification */ final NotificationManager nMgr = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); notifyButton1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(); intent.setClass(getApplicationContext(), MainActivity.class); NotificationCompat.Builder nBuilder1 = new NotificationCompat.Builder(getApplicationContext()) .setTicker("Notify 1 ! ")/* 状态栏显示的提醒语 */ .setContentText("Go back to RustNotifyDemo")/* 下拉栏中的内容 */ .setSmallIcon(R.drawable.notification_small_icon_24)/* 状态栏图片 */ .setLargeIcon(notifyBitmapTrain)/* 下拉栏内容显示的图片 */ .setContentTitle("notifyButton1 title")/* 下拉栏显示的题目 */ .setContentIntent(PendingIntent .getActivity(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)); /* 间接应用PendingIntent.getActivity();不须要实例 */ /* getActivity() 是 static 办法*/ Notification n = nBuilder1.build();/* 间接创立Notification */ n.flags |= Notification.FLAG_AUTO_CANCEL;/* 点击后触发工夫,提醒主动隐没 */ nMgr.notify(notificationId, n); } }); notifyButton2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { NotificationCompat.Builder nBuilder2 = new NotificationCompat.Builder(getApplicationContext()) .setTicker("Notify 2 ! ")/* 状态栏显示的提醒语 */ .setContentText("Notification 2 content")/* 下拉栏中的内容 */ .setSmallIcon(R.drawable.floppy_16px)/* 状态栏图片 */ .setLargeIcon(notifyBitmapTrain)/* 下拉栏内容显示的图片 */ .setContentTitle("title2");/* 下拉栏显示的题目 */ nMgr.notify(notificationId + 1, nBuilder2.build()); /* 两个id一样的notification不能同时显示,会被新的提醒替换掉 */ } }); sendNotification.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String content = editContent.getText().toString(); if (content.equals("")) { content = "U input nothing"; } NotificationCompat.Builder contentBuilder = new NotificationCompat.Builder(getApplicationContext()) .setTicker(content)/* 状态栏显示的提醒语 */ .setContentText("I can auto cancel")/* 下拉栏中的内容 */ .setSmallIcon(R.drawable.rain_32px)/* 状态栏图片 */ .setLargeIcon(notifyBitmapTrain)/* 下拉栏内容显示的图片 */ .setContentTitle("Edit title");/* 下拉栏显示的题目 */ Notification n = contentBuilder.build(); nMgr.notify(notificationId + 2, n); } }); notifyBroadcast.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent i = new Intent(BroadcastNotify); sendBroadcast(i); } }); cleanButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { nMgr.cancel(notificationId);/* 依据id,撤销notification */ } }); } /** * 点击空白处,软键盘主动隐没 */ @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { if (getCurrentFocus() != null && getCurrentFocus().getWindowToken() != null) { inputMgr = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); inputMgr.hideSoftInputFromWindow( getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); } } return super.onTouchEvent(event); } @Override protected void onDestroy() { unregisterReceiver(notifyReceiver); super.onDestroy(); }}MainActivity launchMode="singleInstance";便于返回 activity ...

December 21, 2021 · 3 min · jiezi

关于android:原生Android工程接入Flutter-aar

一、环境搭建首先,须要开发者依照原生Android、iOS的搭建流程搭建好开发环境。而后,去Flutter官网下载最新的SDK,下载结束后解压到自定义目录即可。如果呈现下载问题,能够应用Flutter官网为中国开发者搭建的长期镜像。 export PUB_HOSTED_URL=https://pub.flutter-io.cnexport FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn为了方便使用命令行,还须要额定配置下环境变量。首先,应用vim命令关上终端。 vim ~/.bash_profile 而后,将如下代码增加到.bash_profile文件中,并应用source ~/.bash_profile命令使文件更改失效。 export PATH=/Users/mac/Flutter/flutter/bin:$PATH//刷新.bash_profilesource ~/.bash_profile实现上述操作之后,接下来应用flutter doctor命令查看环境是否正确,胜利会输入如下信息。 二、创立Flutter aar包原生Android集成Flutter次要有两种形式,一种是创立flutter module,而后以原生module那样依赖;另一种形式是将flutter module打包成aar,而后在原生工程中依赖aar包,官网举荐aar的形式接入。 创立flutter aar有两种形式,一种是应用Android Studio进行生成,另一种是间接应用命令行。应用命令行创立flutter module如下: flutter create -t module flutter_module而后,进入到flutter_module,执行flutter build aar命令生成aar包,如果没有任何出错,会在/flutter_module/.android/Flutter/build/outputs目录下生成对应的aar包,如下图。 build/host/outputs/repo└── com └── example └── my_flutter ├── flutter_release │ ├── 1.0 │ │ ├── flutter_release-1.0.aar │ │ ├── flutter_release-1.0.aar.md5 │ │ ├── flutter_release-1.0.aar.sha1 │ │ ├── flutter_release-1.0.pom │ │ ├── flutter_release-1.0.pom.md5 │ │ └── flutter_release-1.0.pom.sha1 │ ├── maven-metadata.xml │ ├── maven-metadata.xml.md5 │ └── maven-metadata.xml.sha1 ├── flutter_profile │ ├── ... └── flutter_debug └── ...当然,咱们也能够应用Android Studio来生成aar包。顺次抉择File -> New -> New Flutter Project -> Flutter Module生成Flutter module工程。 ...

December 21, 2021 · 3 min · jiezi

关于android:优酷-Android-构建速度优化实践

作者:苏彦郊(木磊) Android 我的项目个别应用 gradle 作为构建打包工具,gradle 简洁、动静的性能个性为人津津有味,同样,构建执行速度迟缓的缺点也始终为人诟病。 近年来,随着优酷性能个性日益丰盛,优酷的代码规模也急剧减少,同时,宏大的代码规模也带来了构建耗时的一直减少。整包构建耗时一度高达35min,重大影响集成与迭代效率。因而构建速度优化势在必行。截止 2021年 11 月份,优酷构建耗时优化获得较为理想的优化后果(如下),现将构建速度优化的实际计划记录成文。 android构建类型2020年2021android debug 包构建耗时12min2.5minandroid release 包构建耗时35 min12min计划与收益统计图: 优化思路技术优化类我的项目个别采纳照设定数据指标、技术优化、成绩防腐化三个维度开展。套用技术优化类项拆解可知,咱们须要实现如下三个子项目: 设定数据指标:即收集与选取外围优化的数据指标,体现成绩价值。本文选取构建耗时、构建失败率、小时维度构建次数等指标作为成绩优化的数据撑持;技术优化:通过影响构建速度的影响因素可知,包含软件与硬件两局部,所以构建速度优化可分为软件优化与硬件优化两大方向;成绩防腐化: 即维持技术优化指标不好转,保障优化成绩。接下来,我将依照设定数据指标与后果防腐、技术优化——软件优化、技术优化——硬件优化三个局部开展。 优化计划设定数据指标与后果防腐优化类我的项目须要建立健全相应的数据指标体系,借由数据评判体积优化项与优化计划进行有效性断定。进行构建优化前,笔者基于阿里巴巴Aone FaaS( Severless 服务)平台搭建了数据评判与监控大盘。该大盘有构建类型、构建工夫、构建成功率、构建工作耗时等多项指标,满足构建优化我的项目须要依据类型、工作频率、高耗时工作排查的需要。 实现相干数据能力建设后,通过构建要害数据指标——构建耗时与构建成功率的追踪和剖析,进而得出构建耗时的次要影响因素为高耗时工作,构建成功率的次要影响因素为不合理的构建工作。因而,咱们能够通过高耗时工作报警与不合理工作报警,疾速发现并剖析构建速度好转情景,进而保障构建耗时优化成绩。 软件优化构建侧去atlasAtlas是随同着手机淘宝的一直倒退,进而衍生进去的一个运行于android零碎上的容器化框架,咱们也叫动静组件化(Dynamic Bundle)框架。它次要提供理解耦化、组件化、动态性的反对。笼罩了工程师的工程编码期、Apk运行期以及后续运维期的各种问题。 依靠于深度定制的产物构造与高度简单、深度hook 的运行时框架,Atlas能够视为挪动端 OSGI 实现计划与组件化计划。但随着优酷挪动端架构调整与自研近程化计划落地,Atlas运行时框架逐步丢失了OSGI框架作用,遂在运行期去除Atals 框架。 当运行期将Atlas依赖去除后,Atlas的简单构建流程(如下图所示)也失去了存在意义。随即,优酷启动了构建侧Atlas 去除我的项目,指标是将Atlas构建插件去除、构建原生化、污浊化、精简化。通过产物原生化、构建工作清理、工具链降级等一系列动作,在实现了构建侧Atlas去除指标的同时,构建性能也有局部晋升。 收益:debug 包构建耗时升高 3min左右。release 包构建耗时升高4min-5min。 gradle 降级和android gradle plugin 降级gradle 团队始终在继续优化gradle 的构建速度等性能指标, 同时 google 团队也在继续优化 android gradle plugin 构建工具性能。为了进一步晋升优酷android 端构建性能,决定对优酷android构建零碎进行降级,将android gradle plugin 构建工具版本由3.0.1(2017年)晋升至3.4.3(2019年)版本,将gradle构建工具由4.4(2017)至5.5 (2019年)版本。 比照降级前后构建耗时,能够发现构建工具降级后,性能晋升次要源于三个方面: 随android gradle plugin 降级,aapt2、proguard 等构建工具也进行了降级,这部分工具降级后,构建性能有小幅晋升;更好工作排布与并行化机制:降级gradle 与agp 后,agp 3.4.3 版本进行了签名、压缩、对齐工作的整合优化;配置按需加载与异步化策略:android gradle plugin 3.4.3 采纳资源的异步加载策略,即configuaration 阶段仅做依赖拉取工作,不再进行产物的解压、过滤、合并工作,这样能够无效防止io 拥塞问题,防止cpu 忙等景象。收益:debug 包构建耗时升高 2min左右 。release 包构建耗时升高4min左右。 ...

December 21, 2021 · 2 min · jiezi

关于android:大佬亲自分享Android开发该如何迎接2022

前言2021年未然靠近序幕,尽管没有2020年那么跌宕起伏,但很多行业仍旧收到了来自各方面的冲击(K12培训:你间接报我身份证号得了呗)。对于Android开发者们,年底也是听到、看到了很多不太利好的音讯,很多大厂也是频频冲上热搜,这也着实让大家对本人的前途感到迷茫。 其实近些年来,很多人都在一直地唱衰Android的发展趋势,还有人每天纠结于要不要寻求转行。尽管Android热度不如从前,随着行业的倒退,各大厂对于从业者的要求也越来越严格,但其实那些基础知识扎实、开发技能过硬的开发者仍旧是各大厂争相争夺的香饽饽,很多大厂对于中高级Android开发者仍旧求贤若渴。 “打铁还需本身硬”,这并不是一句空话。很多开发者也在踊跃的致力提高,但在信息爆炸的时代,苦于没有方法找到靠谱的学习资源。年后,金三银四也会马上到来,很多Androider都对高薪蠢蠢欲动。为了更好地帮忙大家进行学习,在这里给大家分享一份BAT大佬整顿总结进去的《2022中高级Android面试必知百题》,外面蕴含了所有Android面试的知识点,能够全面的进行常识补给。这份材料蕴含了Java和Android两大部分,因为篇幅起因,这里只展现局部知识点,有须要的敌人文末有收费支付形式。 Java局部第一节 Java 根底局部 “equals”与“==”、“hashCode”的区别和应用场景谈一谈Java成员变量,局部变量和动态变量的创立和回收机会?第二节 Java 汇合 谈谈List,Set,Map的区别? HashMap 的实现原理? 第三节 Java 多线程 Java 中应用多线程的形式有哪些? 如何保障线程平安? 第四节 Java 虚拟机 谈一谈JAVA垃圾回收机制? 简述JVM中类的加载机制与加载过程? Android局部第一节 Android 四大组件相干 Activity 与 Fragment 之间常见的几种通信形式?简略介绍下ContentProvider是如何实现数据共享的?Activity中onNewIntent办法的调用机会和应用场景?Intent传输数据的大小有限度吗?如何解决? 第二节 Android 异步工作和音讯机制 HandlerThread 的应用场景和用法?AsyncTask的长处和毛病?子线程是否更新UI?为什么?试从源码角度剖析Handler的post和sendMessage办法的区别和利用场景?第三节 Android UI 绘制相干 谈谈Android的事件散发机制?谈谈自定义View的流程?谈一谈Fragment懒加载?谈一谈Activity,View,Window三者的关系?请谈谈Fragment的生命周期? 第四节 Android 性能调优相干 谈谈你对Android性能优化方面的理解?个别什么状况下会导致内存透露问题?哪些状况下会导致oom问题?谈谈你是如何优化App启动过程的?谈谈如何对WebView进行优化? 第五节 Android 中的 IPC 请答复一下Android过程间的通信形式?请谈谈你对Binder机制的了解?谈谈 AIDL?第六节 Android 零碎 SDK 相干 请简要谈谈Android零碎的架构组成?什么是Lifecycle?请剖析其外部原理和应用场景?请简述Apk的装置过程?第七节 第三方框架剖析 谈一谈LeakCanray的工作原理?谈一谈RxJava背压原理? 第八节 综合技术 请谈谈你对 MVC 和 MVP 的了解?简述下热修复的原理?什么是MVVM?你是如何将其利用于具体我的项目中的?第九节 数据结构方面 什么是冒泡排序?如何优化?什么是红黑树?为什么要用红黑树?第十节 设计模式 什么是代理模式?如何应用?Android源码中的代理模式?谈一谈单例模式,建造者模式,工厂模式的应用场景?如何正当抉择?第十一节 计算机网络方面 ...

December 21, 2021 · 1 min · jiezi

关于android:相比-XML-Compose-性能到底怎么样

前言最近Compose曾经正式公布了1.0版本,这阐明谷歌认为Compose曾经能够用于正式生产环境了 那么相比传统的XML,Compose的性能到底怎么样呢? 本文次要从构建性能与运行时两个方面来剖析Compose的性能,数据次要来源于:Jetpack Compose — Before and after 与 Measuring Render Performance with Jetpack Compose , 想理解更多的同学能够间接点击查看 构建性能Compose构建性能次要以 tivi 为例来进行阐明 Tivi是一个开源的电影App,本来基于Fragment与XML构建,同时还应用了DataBinding等应用了注解处理器的框架 起初迁徙到应用Compose构建UI,迁徙过程分为两步 第一步:迁徙到Navigation与Fragment,每个Fragment的UI则由Compose构建第二步:移除Fragment,齐全基于Compose实现UI上面咱们就对Pre-Compose,Fragments + Compose,Entirely Compose三个阶段的性能进行剖析比照 APK体积包体积是咱们常常关注的性能指标之一,咱们一起看下3个阶段的包体积比照 能够看出,Tivi 的 APK 大小缩减了 46%,从 4.49MB 缩减到 2.39MB,同时办法数也缩小了17% 值得注意的是,在刚开始在利用中采纳Compose时,有时您会发现APK大小反而变大了 这是因为迁徙没有实现,老的依赖没有实现移除,而新的依赖曾经增加了,导致APK体积变大 而在我的项目齐全迁徙到Compose后,APK 大小会缩小,并且优于原始指标。 代码行数咱们晓得在比拟软件我的项目时,代码行数并不是一个特地有用的统计数据,但它的确提供了对事物如何变动的一个察看指标。 咱们应用cloc工具来计算代码行数 cloc . --exclude-dir=build,.idea,schemas后果如下图所示: 能够看出,在迁徙到Compose后,毫无意外的,XML代码行缩小了76% 乏味的是kotlin代码同样缩小了,可能是因为咱们能够缩小很多模板代码,同时也能够移除之前写的一些View Helper代码 构建速度随着我的项目的一直变大,构建速度是开发人员越来越关怀的一个指标。 在开始重构之前,咱们晓得,删除大量的注解处理器会有助于进步构建速度,但咱们不确定会有多少。 咱们运行以下命令5次,而后取平均值 ./gradlew --profile --offline --rerun-tasks --max-workers=4 assembleDebug后果如下 这里思考的是调试构建工夫,您在开发期间会更关注此工夫。 在迁徙到Compose前,Tivi 的均匀构建工夫为 108.71 秒。 在齐全迁徙到 Compose 后,均匀构建工夫缩短至 76.96 秒!构建工夫缩短了 29%。 构建工夫能缩短这么多,当然不仅仅是Compose的功绩,在很大水平上受两个因素的影响: ...

December 21, 2021 · 1 min · jiezi

关于android:Android实例-android-蓝牙开发浅析

应用蓝牙的响应权限 <uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> 配置本机蓝牙模块在这里首先要理解对蓝牙操作一个外围类BluetoothAdapter BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); //间接关上零碎的蓝牙设置面板 Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(intent, 0x1); //间接关上蓝牙 adapter.enable(); //敞开蓝牙 adapter.disable(); //关上本机的蓝牙发现性能(默认关上120秒,能够将工夫最多缩短至300秒) Intent discoveryIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);//设置持续时间(最多300秒) 3.搜寻蓝牙设施应用BluetoothAdapter的startDiscovery()办法来搜寻蓝牙设施startDiscovery()办法是一个异步办法,调用后会立刻返回。该办法会进行对其余蓝牙设施的搜寻,该过程会继续12秒。该办法调用后,搜寻过程实际上是在一个System Service中进行的,所以能够调用cancelDiscovery()办法来进行搜寻(该办法能够在未执行discovery申请时调用)。申请Discovery后,零碎开始搜寻蓝牙设施,在这个过程中,零碎会发送以下三个播送:ACTION_DISCOVERY_START:开始搜寻ACTION_DISCOVERY_FINISHED:搜寻完结ACTION_FOUND:找到设施,这个Intent中蕴含两个extra fields:EXTRA_DEVICE和EXTRA_CLASS,别离蕴含BluetooDevice和BluetoothClass。咱们能够本人注册相应的BroadcastReceiver来接管响应的播送,以便实现某些性能 // 创立一个接管ACTION_FOUND播送的BroadcastReceiver private final BroadcastReceiver mReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); // 发现设施 if (BluetoothDevice.ACTION_FOUND.equals(action)) { // 从Intent中获取设施对象 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // 将设施名称和地址放入array adapter,以便在ListView中显示 mArrayAdapter.add(device.getName() + "\n" + device.getAddress()); } } }; // 注册BroadcastReceiver IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(mReceiver, filter); // 不要忘了之后解除绑定 蓝牙Socket通信如果打算倡议两个蓝牙设施之间的连贯,则必须实现服务器端与客户端的机制。当两个设施在同一个RFCOMM channel下别离领有一个连贯的BluetoothSocket,这两个设施才能够说是建设了连贯。服务器设施与客户端设施获取BluetoothSocket的路径是不同的。服务器设施是通过accepted一个incoming connection来获取的,而客户端设施则是通过关上一个到服务器的RFCOMM channel来获取的。服务器端的实现通过调用BluetoothAdapter的listenUsingRfcommWithServiceRecord(String, UUID)办法来获取BluetoothServerSocket(UUID用于客户端与服务器端之间的配对)调用BluetoothServerSocket的accept()办法监听连贯申请,如果收到申请,则返回一个BluetoothSocket实例(此办法为block办法,应置于新线程中)如果不想在accept其余的连贯,则调用BluetoothServerSocket的close()办法开释资源(调用该办法后,之前取得的BluetoothSocket实例并没有close。但因为RFCOMM一个时刻只容许在一条channel中有一个连贯,则个别在accept一个连贯后,便close掉BluetoothServerSocket) ...

December 21, 2021 · 3 min · jiezi

关于android:Android中LayoutAnimation的分析三

PS:本文系转载文章,浏览原文可读性会更好,文章开端有原文链接 ps:源码是基于 android api 27 来剖析的。 咱们持续Android中LayoutAnimation的剖析(二)这篇文章剖析,在Android中LayoutAnimation的剖析(二)这篇文章中,咱们还漏剖析了一些内容,那就是属性动画的解析,咱们看 LayoutAnimation-Controller 中 LayoutAnimationController(Context context, AttributeSet attrs) 的构造方法; public LayoutAnimationController(Context context, AttributeSet attrs) { ...... //1、 int resource = a.getResourceId(com.android.internal.R.styleable.LayoutAnimation_animation, 0); if (resource > 0) { //2、 setAnimation(context, resource); } ......} 正文1 示意从 layoutAnimation 标签中解析出 animation 属性援用的 xml 文件 id;正文2 示意要将析出 animation 属性援用的 xml 文件 id作为参数调用 setAnimation(Context context, @AnimRes int resourceID) 办法; public void setAnimation(Context context, @AnimRes int resourceID) { //3、 setAnimation(AnimationUtils.loadAnimation(context, resourceID));} ...

December 21, 2021 · 7 min · jiezi

关于android:Gradle-与-AGP-构建-API-配置您的构建文件

欢送浏览全新的 MAD Skills 系列 之 Gradle 及 Android Gradle plugin API 的第一篇文章。咱们将在本文中理解 Android 构建零碎的工作形式以及 Gradle 的基础知识。 咱们将会从 Gradle 的构建阶段开始,探讨如何应用 AGP (Android Gradle Plugin) 的配置选项自定义您的构建,并探讨如何使您的构建放弃高效。如果您更喜爱通过视频理解此内容,请在 此处 查看。 通过理解构建阶段的工作原理及配置 Android Gradle plugin 的配置办法,能够帮您基于我的项目的需要自定义构建。让咱们回到 Android Studio,一起看看构建零碎是如何工作的吧。 Gradle 简介Gradle 是一个通用的自动化构建工具。当然,您能够应用 Gradle 来构建 Android 我的项目,但实际上您能够应用 Gradle 来构建任何类型的软件。 Gradle 反对繁多或多我的项目构建。如果要将我的项目配置为应用 Gradle,您须要在我的项目文件夹中增加 build.gradle 文件。 在多我的项目层级构造中,根我的项目中会蕴含一个 settings.gradle 文件,其中列出了构建中蕴含的其余我的项目。Android 应用多我的项目构建来帮您模块化利用。 △ Android 我的项目构造与 build.gradle 及 settings.gradle 文件 因为插件的存在,Gradle 能够解决不同类型的我的项目,比方 Android 或 Java。这些插件会蕴含预约义的性能,用于配置和构建特定类型的我的项目。 例如,为了构建 Android 我的项目,您须要应用 Android Gradle 插件配置您的 Gradle 构建文件。无论以后的 Android 我的项目是利用还是依赖库,Android Gradle 插件都晓得如何对其进行构建和打包。 ...

December 21, 2021 · 2 min · jiezi

关于android:Flutter-不一样的跨平台解决方案

本文次要介绍Flutter相干的货色,包含Fuchsia、Dart、Flutter个性、装置以及整体架构等内容。简介Flutter作为谷歌最近推出的跨平台开发框架,一经推出便吸引了不少留神。对于Flutter,目前咱们晓得它是一个跨平台开发框架。然而它自身并不止于此,例如Fuchsia、Dart等,咱们也都须要去理解。 Fuchsia说到Flutter,相对绕不开Fuchsia,这个是谷歌开发的一款全新的操作系统,GitHub地址以及Google source主页。Fuchsia内核是Magenta Kernel,一个基于LittleKernel的我的项目。该零碎与Android相比,无论是存储器还是内存之类的硬件要求都大幅升高,外界推论是一款面向物联网的零碎。笔者倒是没有查到谷歌开发这款操作系统的目标,如果有通晓的,也烦请告知。 就像很多博客主说的那样,如果只是取代Android,那无疑是一种很不好的做法。任何技术的推动,都得靠背地的商业驱动,尤其是这种波及到手机厂商利益的技术。 FlutterFlutter是Fuchsia的开发框架,是一套挪动UI框架,能够疾速在iOS、Android以及Fuchsia上构建高质量的原生用户界面。 目前Flutter是完全免费、开源的,GitHub地址。其官网编程语言为Dart,也是一门全新的语言。所以说,上手老本比拟高,对于挪动端开发人员,语言以及框架都是全新的,整个技术栈的积攒也都得从头开始。 能够看下其官网介绍的个性: 疾速开发:Flutter的热重载能够疾速地进行测试、构建UI、增加性能并更快地修复谬误。富裕表现力,丑陋的用户界面:自带的Material Design和Cupertino(iOS格调)widget、丰盛的motion API、平滑而天然的滑动成果。响应式框架:应用Flutter的古代、响应式框架,和一系列根底widget,轻松构建您的用户界面。拜访本地性能和SDK:Flutter能够复用现有的Java、Swift或ObjC代码,拜访iOS和Android上的原生零碎性能和零碎SDK。对立的利用开发体验:Flutter领有丰盛的工具和库,能够帮忙开发者轻松地同时在iOS和Android零碎中实现想法和创意。原生性能:Flutter蕴含了许多外围的widget,如滚动、导航、图标和字体等,这些都能够在iOS和Android上达到原生利用一样的性能。其实从官网个性来看,惟一有点吸引力的就是对立的利用开发体验。一套代码运行在多个平台,做到真正的跨平台。像热加载,目前Android开发自身就反对了,响应式框架以及拜访本地性能和SDK,对于Native来说,自身并没有多大的吸引。至于丑陋的用户界面,国内的商业我的项目,哪一个会去依照Material Design去设计。 跨平台自身,往往意味着性能受损,通用性解决不了的问题,又得回到Native去实现。所以这些因素也是跨平台从挪动端诞生之初就开始提,到当初也没有被很好解决的一个起因。至于谷歌可能做到什么水平,或者说开发者该放弃什么期许,我感觉都不好说,或者谷歌解决了一个多年的难题,或者又像被谷歌放弃掉的其余我的项目一样。抛开商业层面,对于技术人员,咱们更多的是应该去关注它的思维,谷歌是如何去解决这些理论存在很久的问题的,至于技术自身的倒退,这个是集体开发者无奈去左右的,技术的更迭,放弃一种学习的状态,而后致力锻炼身体,就可能保障不被淘汰掉。 DartDart是谷歌开发的计算机编程语言,于2011年10月份公布,能够被用于web、服务器、挪动端和物联网等畛域的开发。Flutter采纳Dart,起因很多,抛开商业层面的Java版权问题,单纯从技术层面: Dart是AOT(Ahead Of Time)编译的,编译成疾速、可预测的本地代码,使Flutter简直都能够应用Dart编写;Dart也能够JIT(Just In Time)编译,开发周期快;Dart能够更轻松地创立以60fps运行的晦涩动画和转场;Dart使Flutter不须要独自的申明式布局语言;Dart容易学习,具备动态和动静语言用户都相熟的个性。Dart最后设计是为了取代JavaScript成为web开发的首选语言,最初的后果可想而知,到Dart 2的公布,专一于改善构建客户端应用程序的体验,能够看出定位的转变。用过Java、Kotlin的人,能够很快的上手Dart。 一门语言的成败,抛开背地的商业推动,我想很重要的一点在于其生态,生态的好坏,次要包含开发者以及第三方库的数目,目前看,Dart的生态还是比拟差。对于集体开发者,能够依据情绪来抉择,然而对于商业利用,有更简单的考量规范。Dart背地有谷歌的推动,能倒退到什么水平,还得看其商业运作能力了。 配置此局部针对Mac平台,Windows平台的装置配置,Linux平台的装置配置。因为笔者次要做挪动端开发,如果想应用Flutter进行iOS和Android全平台的开发,环境也倡议是Mac平台,毕竟iOS只能在Mac下进行模仿调试。 装置Fluttergit clone -b beta https://github.com/flutter/flutter.gitexport PUB_HOSTED_URL=https://pub.flutter-io.cn //国内用户须要设置export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn //国内用户须要设置export PATH=`pwd`/flutter/bin:$PATHiOS设置brew updatebrew install --HEAD libimobiledevicebrew install ideviceinstaller ios-deploy cocoapodspod setupAndroid设置下载Android Studio,装置Flutter插件,会将Dart插件也一起装置。 体验FlutterIDE倡议抉择Android Studio,装置了Flutter插件后,Flutter的开发跟Android 开发相似,附带三种模版工程、断点调试等。 在Android Studio外面新建一个Flutter Application的我的项目,抉择模拟器或者间接连贯真机运行,就能够看到一个简略的Flutter利用了,能够在Android和iOS不同平台下看看差别。 Flutter架构Flutter是一款挪动应用程序SDK,一份代码能够同时生成iOS和Android两个高性能、高保真的应用程序。 Flutter对于挪动开发人员,最引诱的能力是其齐全的跨平台个性,不同于RN这种一处学到处写,它是一处写到出跑,然而他跟其余的跨平台有何区别呢? 跨平台解决方案市面上的跨平台解决方案,能够大抵归结为两类: 应用平台反对的web技术:这些解决方案基本上加载了应用程序中的挪动浏览器,并在该浏览器中执行所有的逻辑,例如PhoneGap。本地跨平台:程序员编写的代码主动转换为Native代码,这种形式的长处是近乎原生的性能,例如RN、Weex、Xamarin等。这些计划是否真正的解决了跨平台问题呢?从目前的情况来看,很显然是没有的,因为它们都始终逃不开性能、包大小、流畅性、内存、平台个性等问题。 RN独自拧进去说,是因为它们并不是谋求的一次写到处跑,FB本人也晓得不事实,所以把口号改成一次学到处写,去思考平台的个性,去思考这个被跨平台计划常常疏忽的问题。然而RN也并没有被宽泛的接收,从阿里开始应用到放弃,外面的很多坑都绕不过来。写一次到处跑的确很迷人,从企业角度讲,能够节俭大量的人力,然而却疏忽了一个很根底的问题,不同平台是否心愿如此,苹果是否会违心本人的生态被突破,不同平台的个性是否应该被归为统一。 Flutter的跨平台解决方案下面简略说了传统跨平台解决方案,咱们再回过头看看Flutter的解决方案,Flutter跨平台最外围的局部,是它的高性能渲染引擎(Flutter Engine)。Flutter不应用浏览器技术,也不应用Native的原生控件,它应用本人的渲染引擎来绘制widget。 说到widget,就要说一句Flutter的所有皆为widget理念。widget是Flutter应用程序用户界面的根本构建块。每个widget都是用户界面一部分的不可变申明。与其余将视图、控制器、布局和其余属性拆散的框架不同,Flutter具备统一的对立对象模型:widget。在更新widget的时候,框架可能更加的高效。 对于Android平台,Flutter引擎的C/C++代码是由NDK编译,在iOS平台,则是由LLVM编译,两个平台的Dart代码都是AOT编译为本地代码,Flutter应用程序应用本机指令集运行。 Flutter正是是通过应用雷同的渲染器、框架和一组widget,来同时构建iOS和Android利用,而无需保护两套独立的代码库。 Flutter将UI组件和渲染器从平台挪动到应用程序中,这使得它们能够自定义和可扩大。Flutter惟一要求零碎提供的是canvas,以便定制的UI组件能够呈现在设施的屏幕上。 Flutter框架Flutter框架是一个分层的构造,每个层都建设在前一层之上。 框架没什么可介绍的(次要是具体介绍我也没找到啥材料,大写的难堪),看着很简略,就分为两个局部,Framework和Engine局部,其中Framework提供了各种根底的组件库,Engine局部渲染各种widget,两者独特作用,使得运行性能高效稳固。 Flutter调研生态在Flutter官网的Pub平台上,纯Flutter Package大略有两千多个,基本上常见的库还是都有的,例如网络、图片、音视频播放等等。然而对于目前Android以及iOS的生态,还是远远的有余的,对于一些简单的UI或者一些不是特地通用的性能,就得本人去实现。 包大小依据官网的介绍,一个最小的Android版本的Flutter利用。release版本大小约6.7MB,其中外围引擎大概3.3MB,框架+利用程序代码大概是1.25MB,LICENSE文件(蕴含在app.flx中)是55k,必须的Java代码.dex为40k,并且约有2.1MB的ICU数据。思考到目前网络环境,包大小的减少,还也在能够承受的范畴。 CrashiOS运行官网的例子,会有时候crash掉,因而咱们将一个开源的Flutter利用增加了Bugly上报,在Android平台进行了众测。 ...

December 21, 2021 · 1 min · jiezi

关于android:Android要凉了吗其实只是你凉了

前言Android程序员不论是做 Android 底层开发,还是做应用层开发,想在 Android 这条路上走上来,必须对于 Android 源码够理解,如某一个性能,某一个机制,或者某一个API,它到底是如何实现的,都须要深刻理解源码,做到能知其然,知其所以然。 最近在各大论坛外面都能看到这样的话语:1、Android开发如何啊?2、感觉前景不太乐观啊?3、当初人工智能热度很火,是不是换这个会好一些?Android近况:想必大家都晓得,当初的挪动开发不像以前那么活了,齐全没有了一几年Android 开发那种炽热的势头,与此同时,AI人工智能当初是炽热半边天。此时就有了很多舆论都说Android 开发凉了、不行了、没有前景了等此类的舆论话题。那么到底该如何对待这一景象呢? 我的答案是:Android 还行,只是高级开发没有之前那么吃香了,高级市场进行了饱和,然而中高级岗位人才还是比拟稀缺。为什么说Android还行?其实不论在任何行业,任何岗位,高级技术人才总是供大于求,都是不好找工作的,Android开发只是其中之一 同样,不论任何行业、岗位,技术过硬的也都是十分吃香的! 说到底,是Android凉了吗?其实只是你凉了! Android市场怎么样?就以后的手机应用人群占比来说,Android是榜首这个毫无疑问,随同着国内Android 5G手机的领先推出,吸引了不少的追赶时代潮流用户。 随着Android手机的人多,那么必定对于Android手机里APP的需要就会多。APP需要多了,那么开发岗位的需要也多。比照以往来说,没啥差异,甚至还有可能会更好。 Android开发工程师薪资待遇和岗位要求 那到底是该坚守还是转行?我感觉吧,首先抛开其余因素,就拿随声附和来说,在当下这个互联网时代,很多技术一下子就火起来了,这个时候匹配的岗位需要必定也多了,难道每次都想着换方向,转岗? 显然这个是不对的,这些炽热的技术必定会缓缓趋于失常,那么你又回到了原点。如果还是思路不变,那么就会永远的原地踏步。 那如何把本人晋升为“IT型人才”作为身处开发类岗位的大家或者还在纠结方向的大家,我感觉还是找准方向,深耕。技术有一点深度了,而后工作教训也有了,那么我置信间隔稳固的高薪也就不远了。 因为就目前局势来说,对于企业,高级开发都比拟好招,然而中级或以上的就比拟难了,有很多公司在这下面花了很多工夫,找简历,猎头,被动分割等等,最终也是无功而返。 这其实也就变相阐明了,行业内中高端人才的稀缺。想要高薪,必先埋头钻研,本身达到肯定高度,薪酬天然跟着下来。 换个角度,当你技术有肯定深度的时候,对于一些其余技术,或多或少都会有所波及的。这个时候技术的广度也有了,大家还会感觉薪资会低吗? 我给大家整顿了一篇对于《Android开发相干源码精编解析》,心愿能帮忙大家更好地学习浏览 Android 源码,材料一共 558 页。Android开发相干源码精编解析内容涵盖:微信 MMKV 源码、阿里巴巴路由框架 ARouter 源码、AsyncTask 源码、Volley 源码、Retrofit 源码、OkHttp 源码、ButterKnife 源码、Okio 源码、SharedPreferences 源码、EventBus 源码等等一系列优良源码解析。1. 深刻解析微信 MMKV 源码 初始化获取批改读取文件回写Protobuf 解决跨过程锁实现2. 深刻解析阿里巴巴路由框架ARouter 源码 初始化路由跳转Service 的获取拦截器机制注解解决 3. 深刻解析AsyncTask 源码(一款 Android 内置的异步工作执行库) 性能概述创立执行勾销线程池不足之处4.深刻解析Volley 源码(一款 Google 推出的网络申请框架) VolleyRequestQueueExecutorDeliveryNetworkDispatcherCacheDispatcherRequestResponseNetworkHttpStack缓存机制 5.深刻解析 Retrofit 源码 简介与其余网络申请开源库比照Retrofit 的具体应用源码剖析6. 深刻解析 OkHttp 源码 整体架构拦截器&一个理论网络申请的实现工作队列缓存策略连接池 ...

December 21, 2021 · 1 min · jiezi

关于android:全网最全Android音视频开发教程字节跳动技术大佬亲授内部音视频开发笔记

前言随着5G时代的到来,音视频缓缓变成人们日常生活中的必须品。所以,当初有大量的公司开始寻找音视频人才,一个稍好点的音视频人才当初可能会有3-4家公司抢着要。5G的呈现,也会促成至多10年音视频行业的凋敝,因为,音视频在5G时代会给用户带来更好,更丰盛的用户体验。但往这方面倒退须要学什么呢?其实多看看招聘的岗位要求就能明确。 所以,做音视频研发的前景是广大的。对于很多早看出音视频前景的敌人来说,曾经开始通过各种渠道收集相干的学习材料,及早的投入音视频研发的队伍,这样能力使本人在将来几年能够退职场上更有作为。我倡议你当初连忙转音视频开发。学好后肯定会有好的将来。你能够从ffmpeg 或WebRTC 学起,不断深入,这是一个最佳学习路径。 如何学习音视频开发?咱们齐全能够跟着这份由字节团队出品的《音视频开发教程(附面试题)》。这份材料全文共301页,蕴含50个知识点,通过经典音视频采集、编码网络编程等知识点解析加深你对音视频开发的了解,同时附带字节面试题,助力大厂面试。 第一章、WebRTC 发送方码率预估实现解析 第二章、码率管制基本概念 第三章、Speex回声打消代码剖析 第四章、房间声学原理与Schroeder混响算法实现第五章、H264系列–压缩编码技术第六章、RTSP 媒体协定流的录制计划及其笼罩策略详解第七章、webrtc建设连贯之ICE框架… 第八章、流媒体协定介绍(rtp/rtcp/rtsp/rtmp/mms/hls) 第九章、音视频同步原理及实现第十章、直播概念和流程框架第十一章、CDN在直播中的使用第十二章、常见音视频编码格局第十三章、H.264官网软件JM源代码剖析-编码器lencod第十四章、H.264官网软件JM源代码剖析-解码器ldecod… 第二十八章、webRTC是如何实现音视频的录制 第二十九章、音视频同步算法 第三十章、房间声学原理与Schroeder混响算法实现 第三十一章、一个频域语音降噪算法实现及改良办法第三十二章、HEVC官网软件HM源代码剖析-编码器TAppEncoder第三十三章、HEVC官网软件HM源代码剖析-解码器TAppDecode第三十四章、音视频编解码罕用知识点… 音视频开发面试题 总结以上就是对于音视频的材料最强整顿和概括了(还有局部内容没有截图进去),置信应该是全网最全了,所有材料都是收费分享给大家的,也省去了对音视频感兴趣的小伙伴们到处找材料的工夫,如果你正好须要能够点击这里收费获取!**

December 21, 2021 · 1 min · jiezi

关于android:Android-dex文件64k限制解决办法

随着安卓平台的一直倒退与壮大,市场上大而全的利用亘古未有,产品需要的变更累积和UI交互的极致谋求,除了 resources 文件的俱增,在 Android Project 中依赖的 Library 和 本人写的 Java 代码也会越来越多。这些变动,除了会导致打包出的 APK 文件越来越大之外,当我的项目中java代码蕴含的办法数(method count)超出一个峰值时,编译过程中就会呈现如下谬误: 较早版本的编译系统中,谬误内容如下: Conversion to Dalvik format failed:Unable to execute dex: method ID not in [0, 0xffff]: 65536而在新版编译系统中,是这样: trouble writing output:Too many field references: 131000; max is 65536.You may try using --multi-dex option.只管在不同版本的编译系统中显示的谬误内容不尽相同,但内容中都提到了一个具体的数字:65536,这个数字也是本文要讲到的核心内容:Android 64K Method Counts Limit 的峰值。 Android Project 通过编译打包,其中的Java代码(包含Library)转化为DEX格局的字节码文件,这是Android 5.0之前的 Dalvik 虚拟机决定的(5.0之后改为 ART 虚拟机),并且采纳 short 类型援用 DEX 文件中的 method,这也为method数量的峰值大小埋下了隐患。short 类型可能示意的最大值是 65536,也就说单个 DEX 文件中最多只有 65536 个 method 可能失去援用,如果代码执行了超出局部的 method 援用,天然会报错,如 methodNotFound 等。1K 等于 1024,65536 刚好是 64K,为了便于称说和应用,就将这个限度规定统称为 64K 办法数的援用限度。 ...

December 21, 2021 · 2 min · jiezi

关于android:面试官今日头条启动很快你觉得可能是做了哪些优化

前言网上对于启动优化的文章多不胜数,内容千篇一律,大都是列举一些耗时操作,采纳异步加载、懒加载等。 而在面试过程中,对于启动优化的问题,如果只是很外表地答复耗时操作应该放在子线程,显然太过于一般,无奈跟竞争者拉开差距。如何让面试官晓得你的“内功深厚”,那必定是要往原理层面去答复。 本文重点还是关注原理,冷启动优化这个问题能延长到很多原理层面的知识点,本文比拟有意思的中央是通过反编译今日头条App,钻研大厂的启动优化计划。 讲启动优化之前,先看下利用的启动流程 一、利用启动流程利用过程不存在的状况下,从点击桌面利用图标,到利用启动(冷启动),大略会经验以下流程: Launcher startActivityAMS startActivityZygote fork 过程ActivityThread main() 4.1. ActivityThread attach 4.2. handleBindApplication 4.3 attachBaseContext 4.4. installContentProviders 4.5. Application onCreateActivityThread 进入loop循环Activity生命周期回调,onCreate、onStart、onResume...整个启动流程咱们能干涉的次要是 4.3、4.5 和6,利用启动优化次要从这三个中央动手。现实情况下,这三个中央如果不做任何耗时操作,那么利用启动速度就是最快的,然而事实很骨感,很多开源库接入第一步个别都是在Application onCreate办法初始化,有的甚至间接内置ContentProvider,间接在ContentProvider中初始化框架,不给你优化的机会。 二、启动优化直奔主题,常见的启动优化形式大略有这些: 闪屏页优化MultipDex优化(本文重点)第三方库懒加载WebView优化线程优化零碎调用优化2.1 闪屏页优化打消启动时的白屏/黑屏,市面上大部分App都采纳了这种办法,非常简单,是一个障眼法,不会缩短理论冷启动工夫,简略贴下实现形式吧。 <application android:name=".MainApplication" ... android:theme="@style/AppThemeWelcome>styles.xml 减少一个主题叫AppThemeWelcome <style name="AppThemeWelcome" parent="Theme.AppCompat.NoActionBar"> ... <item name="android:windowBackground">@drawable/logo</item> <!-- 默认背景--></style>闪屏页设置这个主题,或者全局给Application设置 <activity android:name=".ui.activity.DemoSplashActivity" android:configChanges="orientation|screenSize|keyboardHidden" android:theme="@style/AppThemeWelcome" android:screenOrientation="portrait"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>这样的话启动Activity之后背景会始终在,所以在Activity的onCreate办法中切换成失常主题 protected void onCreate(@Nullable Bundle savedInstanceState) { setTheme(R.style.AppTheme); //切换失常主题 super.onCreate(savedInstanceState);这样关上桌面图标会马上显示logo,不会呈现黑/白屏,直到Activity启动实现,替换主题,logo隐没,然而总的启动工夫并没有扭转。 2.2 MultiDex 优化(本文重点)说MultiDex之前,先梳理下apk编译流程 2.2.1 apk编译流程Android Studio 按下编译按钮后产生了什么? ...

December 21, 2021 · 4 min · jiezi

关于android:Android注解三大框架DaggerHilt-和-Koin-有何不同

Dagger 和 Koin 无疑是 Android 中最风行的两个依赖注入框架。这两个库具备雷同的用处,而且看起来十分类似,但它们在底层的工作形式却十分不同。 那么 Hilt 是什么呢?Hilt 是一个外部应用 Dagger 的库,只是简化了它的用法,因而我在这里所说的无关 Dagger 的内容也实用于 Hilt。在本文中,我不会告诉您应该抉择哪个库。相同,我想向您展现它们的本质区别以及这些差别对您的利用造成的影响。 Dagger如果咱们心愿 Dagger 提供某个类的实例,咱们要做的就是在构造函数中增加 @Inject 注解。 增加这个注解后,Dagger 会在构建时为这个类生成一个 Factory。在该用例下,因为它的类名是 CompositeAdapter, 它会生成一个名为 CompositeAdapter**_**Factory的类。 此类蕴含创立 CompositeAdapter 类的实例所需的所有信息。 如你所看到该工厂类实现了 get() 并返回了一个新的 CompositeAdapter 实例。这实际上是此类实现的 Provider <T> 接口中指定的办法。其余类能够应用 Provider<T> 接口来获取一个类的实例。 如果咱们用 Hilt 代替 Dagger 呢?在这个例子中,没有任何区别。Hilt 是一个外部应用 Dagger 的库,我向你展现的类是由 Dagger 生成的。如果您应用 Hilt,它的确为咱们生成了一些额定的类,这些类简化了 Dagger 的应用,并缩小了咱们须要编写的样板代码的数量。但外围局部放弃不变。 KoinKoin 与 Dagger 以及 Hilt 相比,治理依赖项的办法齐全不同。要在 Koin 中注册依赖项,咱们不会应用任何注解,因为Koin不会生成任何代码。相同,咱们必须为模块提供工厂,这些模块将用于创立我的项目中所需的每个类的实例。 Koin 将这些工厂类的援用增加到 InstancesRegistry 类中,该类蕴含对咱们编写的所有工厂的援用。 该 map 中的 key 是类的全名或应用命名参数时提供的名称。对应的值是咱们编写的工厂,将用于创立类的实例。 要取得依赖关系,咱们须要调用 get() (比方在一个工厂类中) 或者通过在 activities 或 fragments 中调用 inject() 委托属性 ,从而懒加载 get()。get()办法将查找为给定类型的类注册工厂,并将其注入其中。 有什么影响?Dagger 生成代码来提供依赖,而 Koin 不生成代码,这实际上带来了一些影响。 1. 错误处理因为Dagger 是一个编译时依赖注入框架,如果咱们遗记提供某些依赖,咱们简直会立刻晓得咱们的谬误,因为咱们的我的项目将构建失败。 例如,如果咱们遗记向构造函数的 CompositeAdapter 中增加 @Inject 注解,并尝试将其注入 fragment 中,则构建将失败,并显示适当的谬误,确切地通知咱们出了什么问题。 在 Koin 中的状况有所不同,因为它不会生成任何代码。如果咱们遗记为 CompositeAdapter 类增加工厂,利用将会胜利构建,然而会抛出 RuntimeException 一旦咱们申请获取这个类的实例。它可能会在利用启动时产生,因而咱们可能会立刻留神到它,但也可能稍后在其余屏幕上或当用户执行某些特定操作时产生。 2. 对构建工夫的影响Koin 不生成任何代码的长处是:它对咱们的构建工夫的影响要小得多。Dagger 须要应用注解处理器来扫描代码并生成适当的类。这可能须要一些工夫,可能会减慢咱们的构建。 3. 对运行时性能的影响从另一方面来说,因为 Koin 在运行时解析依赖项,所以它的运行时性能稍差一些。 到底相差多少呢?为了估算性能差别咱们能够应用该库,其中 Rafa Vázquez 基于不同的设施上测量并比拟了这两个库。测试数据的编写形式能够模仿多个级别的传递依赖关系,因而它不仅仅是具备 4 个类的虚构应用程序。 如您所见,Dagger 对启动性能简直没有影响。另一方面,在 Koin 中,咱们能够看到它破费了很多工夫。在 Dagger 中注入依赖也比在 Koin 中快一些。 总结正如我在本文开始时所说的,我这里的指标不是告诉您要应用哪个库。我在两个不同的大我的项目中都应用了 Koin 和 Dagger。诚实说,我认为抉择 Dagger 还是 Koin 并不重要,重要的是可能让你编写洁净、简略且易于单元测试的代码。我认为所有的库:Koin,Dagger 和 Hilt 都达到了这个目标。 所有这些库都有本人的劣势,我心愿理解它们在底层是如何工作的,可能帮忙您本人决定哪种库最适宜您的利用。 ...

December 21, 2021 · 1 min · jiezi

关于android:从新手到架构师一篇就够Android性能优化实战解析支付宝App百度App抖音网易携程

前言安卓开发大军浩浩荡荡,通过近十年的倒退,Android技术优化日异月新,现在Android 9.0 曾经公布,Android零碎性能也曾经十分晦涩,能够在体验上齐全媲美iOS。然而,到了各大厂商手里,改源码、自定义零碎,使得Android原生零碎变得泥沙俱下,而后到了不同档次的开发工程师手里,因为技术水平的参差不齐,即便很多手机在跑分软件性能十分高,关上利用仍然存在卡顿景象。另外,随着产品内容迭代,性能越来越简单,UI页面也越来越丰盛,也成为晦涩运行的一种妨碍。 在 Android开发中,性能优化策略非常重要本文次要解说Android性能优化—实战解析心愿你们会喜爱这一份《Android性能优化—实战解析》,是整顿了业内有赞技术团队、腾讯技术团队、阿里巴巴技术团队、美团技术团队、爱奇艺技术团队、失去技术团队、携程技术团队、蘑菇街技术团队等性能监控实战中遇到的问题以及解决方案。从各个方面对指标产品进行全方位的“优化”,让产品的性能失去晋升。对于大部分程序员来说,哪怕工作很久经验丰富,但仍然会呈现面对辣手问题大刀阔斧的情况,大多是因为对呈现问题的状况和解决思路模糊不清,导致此起因就是因为对性能优化方面的实战经验有余。 即使是最有教训的程序员,也很难在开发时就能防止所有导致性能低下的“坑”,因而解决性能问题的要害是在于能不能尽早地发现和定位这些“坑”。 只有通过在实践中总结常见性能问题,能力在你遇到性能问题的时候疾速定位问题、解决问题,那你在工作中、团队里、面试时,也就领有了同行难以复制的外围竞争力。 目录对字符串匹配算法的一点了解安卓APP解体捕捉计划———xCrash深刻了解Gradle框架之一:Plugin,Extension, buildSrcAndroid H5首屏优化实际任意URL跳转破绽修复与JDK中getHost()办法之间的坑支付宝客户端架构解析:Android_客户端启动速度优化之「垃圾回收l支付宝App构建优化解析:通过安装包重排布优化Android 端启动性能支付宝App构建优化解析:Android包大小极致压缩深刻了解Flutter多线程携程技术—从智行Android我的项目看组件化架构实际Flutter您须要晓得的知识点二维码扫描优化本来Lark间接集成了zxing实现扫一扫性能。因为Lark的非凡业务需要,因而并不需要反对到这么多格局,只须要反对QR Code,因而咱们对zxing外部进行定制,使得zxing只反对QR Code。这样既能够缩小zxing库的大小,也能够放慢zxing解决一帧数据的速度。 优化次要蕴含两方面:**扫描性能交互体验** AOP技术在客户端的利用与实际互联网产品决策秘笈:AB测试Android Native 内存透露系统化解决方案Android P之Smart Linkify百度App组件化之路百度App网络深度优化系列《三》弱网优化深刻了解gradle框架之二:依赖实现剖析Probe: Android线上OOM问题定位组件Android动态代码扫描效率优化与实际Scene: Android开源页面导航和组合框架网易新闻客户端H5秒开优化解决支付宝包体积优化的遗留问题:运行时获取dexpc精简安卓利用的包体积是晋升其品质的重要伎俩之一。安卓利用的安装包(apk文件)中dex保留的是利用的代码,占有可观的体积。如果可能将这一部分的体积减小,那么无疑会无效地减小安装包的体积。 Android篇│爱奇艺App启动优化实际分享二维码扫描优化及爱奇艺App的实际动静下发so库在Android APK安装包瘦身方面的利用史上最全Android渲染机制解说(长文源码深度分析)花椒Android端自动化测试实际一种简略优雅的TextView行间距适配计划Android 10分区存储介绍及百度APP适配实际抖音BoostMultiDex优化实际: Android低版本上APP首次启动工夫缩小80%抖音BoostMultiDex优化实际:Android低版本上APP首次启动工夫缩小80%(二)携程Android 10适配踩坑指南抖音包大小优化-资源优化随着业务的疾速迭代,抖音 Android 端的包大小爆发式增长。包大小间接影响到下载转化率、推广老本、运行内存和安装时间等因素,因而对 apk 进行瘦身是一件很有必要且收益很大的事件。 apk 次要由 dex、resource、asserts、native libraries 和 meta-data 组成,针对每一部分,都能够专项去做包大小优化。抖音 Android 端通过一段时间致力,包大小优化曾经获得了阶段性的成绩。目前仍在继续的优化中。 Gradle 与 Android构建入门AwCookieManager.nativeGetCookie crash排查开源|BoostMultiDex:解救Android Dalvik 机型APP降级装置体验字节跳动技术团队—另类BadTokenException问题剖析和解决LayoutInflater原理剖析与简单布局优化实际今日头条Android '秒级编译速度优化曾幻想if-else走咫尺?看看"麦任树模式"优化谷歌—协程中的勾销和异样│异样解决详解QQ音乐—彻底弄懂浏览器缓存策略闲鱼如何在2个月内实现Android启动速度翻倍的?随着闲鱼App端更多新性能、新技术的退出,利用冷启动速度越来越慢,这也意味着用户看到无效内容的工夫被拉长,对用户体验有着很大的挫伤。目前,在内部测试版本中,咱们曾经将安卓在低端机上的冷启动工夫从原来的10s升高到了5s内。 Android Camera内存问题分析有赞挪动Crash平台建设贝壳APP Top Experience系列|Android办法耗时统计工具抖音Android性能优化系列:Java内存优化篇QQ音乐Android编译提速之路挪动端UI—致性解决方案Android D8编译器" bug"导致Crash的问题排查今日头条ANR优化实际系列–设计原理及影响因素今日头条ANR优化实际系列–监控工具与剖析思路全民k歌适配arm64-v8a计划全民K歌内存篇1——线上监控与综合治理全民K歌内存篇2——虚拟内存浅析全民K歌内存篇3———native内存剖析与监控一种依照library的维度进行Android包大小剖析的办法和实际网易新闻构建优化:如何让你的构建速度"势如闪电"?美团—设计稿(UI视图)主动生成代码计划的摸索 因为文章篇幅无限,文档资料内容较多,本能够提供链接下载,但无奈容易被谐和,所以全副存档,须要这些文档这里的敌人,能够点击我的【Gitee】,心愿可能共同进步,共勉! 总结作为一个程序员,性能优化是常有的事件,不论是桌面利用还是web利用,不论是前端还是后端,不论是单点利用还是分布式系统,所以咱们应该更加去重视性能优化的一个应用和技术上晋升,综上所述,对APP进行性能优化已成为开发者该有的一种综合素质,也是开发者可能实现高质量应用程序作品的保障。

December 21, 2021 · 1 min · jiezi

关于android:新一代声明式-UI-框架Android-Jetpack-Compose-开发应用指南

前言Jetpack Compose 是 Android 推出的新一代申明式 UI 框架,Compose 库是用响应式编程的形式对 View 进行构建,用更少更直观的代码领有更弱小的性能,同时还能进步开发速度。Jetpack Compose 特点依据谷歌官网介绍,Jetpack Compose 有以下特点: 更少的代码:应用更少的代码实现更多的性能,并且能够防止各种谬误,从而使代码简洁且易于保护。直观的 Kotlin API:只需形容界面,Compose 会负责解决残余的工作。利用状态变动时,界面会自动更新。放慢利用开发:兼容现有的所有代码,不便随时随地采纳。借助实时预览和全面的 Android Studio 反对,实现疾速迭代。功能强大:凭借对 Android 平台 API 的间接拜访和对于 Material Design、深色主题、动画等的内置反对,创立精美的利用。如何学习 Compose ?这里给大家分享一份学习材料《Android Jetpack Compose 开发利用指南》,内容分为七个章节:初识 Jetpack、Compose 的设计原理和基本概念、Compose 入门、Compose 布局、Compose 动画、Compose 图形、Compose 核⼼控件总结。帮忙大家疾速入门并把握Jetpack Compose。第⼀章 初识 Jetpack JetPack 是什么JetPack 和AndroidXAndroidX 的迁徙第⼆章 Compose 的设计原理和基本概念 JetPack Compose 环境搭建JetPack Compose 新个性和组件依赖JetPack Compose 编程思维总结第三章 Compose 入门 JetPack Compose ⼊门的根底案列JetPack Compose 根底实战第四章 Compose 布局 Compose StateCompose 款式(Theme)Compose布局核⼼控件⾃定义布局Compose中的ConstraintLayout第五章 Compose 动画 ...

December 20, 2021 · 1 min · jiezi

关于android:为-CameraX-ImageAnalysis-进行-YUV-到-RGB-的转换

CameraX 是一个旨在帮忙开发者简化相机利用开发工作的 Jetpack 反对库。它反对多种诸如 ImageCapture、Preview 和 ImageAnalysis 这种能够和 ML Kit 或 TensorFlow Lite 无缝联合的应用场景。这为文本辨认、图像标记等利用的开发提供了可能,甚至还能够反对应用开发者本人训练的 TensorFlow Lite 模型进行物体的辨认和检测。然而,在 CameraX 和这些库之间进行图像格式转换的工作还是比拟费时费力的。本文咱们会介绍最近为 CameraX ImageAnalysis 带来的新性能,反对从 YUV 到 RGB 的转换,咱们会介绍一些背景常识,为什么会引入该性能,并会以大量的示例代码来介绍如何应用它。 背景CameraX 应用 YUV420_888 来生成图像,该格局有 8 位的 Luma(Y)、Chroma(U, V) 和 Paddings(P) 三个通道。YUV 是一种通用且灵便的格局,它反对不同的设施上的 OEM 变体,这就笼罩了很多 ImageAnalysis 的应用场景。然而很多利用仍然依赖 RGB 格局。在咱们的开发者社区,YUV 到 RGB 的转换是呼声最高的性能之一,因为 RGB 格局风行且易于应用,且有时须要在 TensorFlow Lite 模型中应用。让咱们先来看看 YUV 和 RGB 格局。 YUV_420_888 格局YUV 格局也能够被称为 "YCbCr",它包含立体 (planar,如 I420)、半立体 (semi-planar,如 NV21/NV12) 和打包 (packed,如 UYVY) 格局。YUV_420_888 是一种通用的 YCbCr 格局,它可能示意任何 4:2:0 色度二次采样的立体或半立体缓冲区 (但不齐全交织),每个色彩样本有 8 位。且可能保障 Y 立体不会与 U/V 立体交织 (且像素步长始终为 1),以及 U/V 立体总是具备雷同的行步长和像素步长。 ...

December 20, 2021 · 2 min · jiezi

关于android:阿里大佬强Android性能优化实战解析全方面解析Android性能优化

前言 Android曾经融入了寻常百姓的生存中。当今世界,手机正从性能时代进化到智能时代,同时又诞生了令人爱不释手的平板电脑。目前,应用程序开发者的可抉择平台次要就是Android和iOSAndroid升高了甚至能够说是突破了挪动开发的门槛,应用程序开发者编写Android应用程序只须要一台计算机就够了(当然还要有一些编程常识)。工具都是收费的,简直每个人都能写出数百万人会用的利用。Android能够运行在各种设施上,从平板到电视。开发者要害要做的 就是保障利用能够顺利地在这些设施上运行,而且比竞争对手的还好。对应用程序开发人员而言,Android开发的门槛曾经很低了,你会发现,在许多状况下,本人不过是想要在日益增长的Android应用程序市场上分一杯羹而已。赖以谋生、实现明星梦,或者只是想使世界变得更美妙……无论你编写程序所为何求,性能问题都是其中的要害。 性能问题是造成App用户散失的罪魁祸首之一。App的性能问题包含解体、网络申请谬误或超时、响应速度慢、列表滚动卡顿、流量大、耗电等等。而导致App性能低下的起因有很多,除去设施硬件和软件的内部因素,其中大部分是开发者谬误地应用线程、锁、零碎函数、编程范式、数据结构等导致的。即使是最有教训的程序员,也很难在开发时就能防止所有导致性能低下的“坑”,因而解决性能问题的要害是在于能不能尽早地发现和定位这些“坑”。 为什么要学习性能优化?1.性能优化目标是使app更稳固、更晦涩、损耗低。 更稳固: 应用程序可能稳固运行,可能失常应用,不呈现Crash 和 ANR这两个谬误更晦涩: 利用程序运行得更加晦涩损耗更低: 应用程序对内存,电量以及网络资源占用更低 2.领有性能优化技术的开发者,对于岗位的招聘更加吃香,当初各大公司面试都会问对于性能优化的问题,如果你把握了该技术,将会在泛滥应聘者中怀才不遇。 如何学习性能优化?上面是阿里大佬强势举荐的《Android性能优化—实战解析》,材料一共有61个章节,720页,上面是该材料的局部展现 第一章、腾讯Bugly—对字符串匹配算法的一点了解明确你的指标是算法抉择最重要的事常见字符串匹配算法KMP算法表情举荐算法怎么选的? 第二章、爱奇艺技术产品团队—干货|安卓APP解体捕捉计划——xCrash导读问题概述Native 解体介绍xCrash 架构与实现xCrash 与 BreakPad 比拟xCrash 的将来打算 第三章 字节跳动技术团队— 深刻了解Gradle框架之一:Plugin,Extension, buildSrc缘起系列阐明PluginExtensionPlugin TransformGradle插件的公布非凡的buildSrcGradle插件的调试 第四章、百度APP-Android H5首屏优化实际背景方法论Hybrid计划简述及性能瓶颈百度App落地页优化计划新的问题-流量和速度的均衡总结&瞻望 第五章、京东技术—任意URL跳转破绽修复与JDK中getHost()办法之间的坑任意URL跳转破绽getHost()办法的坑之一getHost()办法的坑之二附送一个实在例子 ...... 因为篇幅无限,无奈将材料显示齐全,有须要的小伙伴请点击这里,深刻零碎的学习完这份《Android性能优化—实战解析》,置信你会在性能优化畛域大有晋升。**

December 20, 2021 · 1 min · jiezi

关于android:2021字节跳动腾讯美团快手Android开发面试总结

前言我20年毕业于一所双非本科院校计算机专业,之前在小米实习和工作了一年,始终都是Android开发。 年中的时候因为集体起因打算来到小米到里面看看,投了很多简历,最终面试了字节跳动、腾讯、美团、快手,忧喜参半,本文对这这次面试做一个总结。 字节跳动字节是一个同学内推的,也是我很想去的一个公司,整个面试流程下来体验很nice,效率很高,面试官人也很亲切。 手写代码:计算View树上所有view的数量,参数ViewGroup主线程Looper始终循环查音讯为何没卡主线程?RecyclerView绝对ListView区别?Bitmap resize相干,设置option,decode用MultiDex解决何事?其根本原因在于?Dex如何优化?主Dex放哪些货色?主Dex和其余Dex调用、关联?Odex优化点在于什么?Dalvik和Art虚拟机区别?多渠道打包如何实现(Flavor、Dimension利用)?从母包生出渠道包实现办法?渠道标识替换原理?Android打包哪些类型文件不能混同?Retrofit次要实现机制?Retrofit的作用、原理动静代理动态代理区别?模块化怎么做?怎么设计?接口发现暴漏怎么做?基于什么根本思维?MVC、MVP、MVVM利用和彼此本质区别?Glide缓存特点善于哪个方向?算法题:两个线程别离继续打印奇数和偶数,实现两个线程的交替打印(从小到大)模块化、工程化架构思维腾讯腾讯是一个哥们帮忙内推的,我也挺想去腾讯的,但没有面过,能记住的内容就这么多了。 GC机制;RxJava有没有理解;内存透露怎么排查;app的页面忽然卡了一下,怎么排查?ANR怎么排查?定义是什么?应用过哪些开源库;对OKHttp有哪些理解?这个框架设计怎么样?Databinding有哪些理解?EventBus理解吗?安卓的注解有什么理解?RelativeLayout和LinearLayout怎么选?为什么?自定义Layout次要有那几个流程?滑动过程卡顿,刷新率太低,怎么排查?美团美团是这几次面试中最顺利的一次了。 tcp中的3次握手。get和post的区别TCP和UDP的区别,五层协定线程和过程的区别,线程状态,同步锁,Java外面利用到同步锁的情景,Android哪里用到了同步锁我的项目中做过哪些优化?简略说下。List中的ArrayList和LinkedList的区别,hashmap和hashtable的区别,hashmap的底层实现,如何解决hash抵触算法,一个三叉树,求深度,求最大节点数IPC有哪些(Messenger,AIDL,socket),如果让你分类,如何将它们分类,为什么?Broadcast能够跨过程么?如果能够,是通过什么实现的理解Binder么?理解Service么?说下bindService和startService的区别?我的项目中的bug,你是如何解决的?快手这次面试流程比拟长,快手感觉很重视算法,我起初也被HR回答算法须要增强,想去快手的话多刷点题吧。 Android/ 布局优化Activity启动模式RecyclerView和ListView区别Handler机制,loop办法为何不会造成ANRView绘制流程SingleTop和standard启动模式下,生命周期回调有何不同onStart和onResume区别Java/ 面向对象三大个性Array和Linked区别HashMap底层过程间通信形式equals和==区别线程间加锁的形式设计模式synchronized的不同应用异样线程池创立线程的形式OS/ 死锁网络/ tcp和udp的区别合并k个有序链表最初这就是本次面试记录下来的一些内容,从投简历到面试一系列环节中还是能够感触到待业比拟难,我本人程度也有很大的晋升空间,总之不要轻易裸辞,时刻做好技术晋升的筹备。 借此机会分享几套字节跳动、腾讯、美团、快手等公司2021年的面试题,把技术点整顿成了视频和PDF(实际上比预期多花了不少精力),蕴含常识脉络 + 诸多细节,因为篇幅无限,这里以图片的模式给大家展现一部分,心愿能对你有帮忙。 上述【高清技术脑图】以及【配套的架构技术PDF】能够点击这里收费获取!

December 20, 2021 · 1 min · jiezi

关于android:Android-面试之必问Android基础

1,Activity1.1 生命周期失常状况系,Activity会经验如下几个阶段: onCreate:示意Activity正在被创立。onRestart:示意Activity正在被重新启动。onStart:示意Activity正在被启动,这时曾经可见,但没有呈现在前台无奈进行交互。onResume:示意Activity曾经可见,并且处于前台。onPause:示意Activity正在进行(可做一次保留状态进行动画等非耗时操作)。onStop:示意Activity行将进行(可进行重量级回收工作)。onDestroy:示意Activity行将被销毁。 对于生命周期,通常还会问如下的一些问题: 第一次启动:onCreate->onStart->onResume;关上新的Activity或者返回桌面:onPause->onStop。如果关上新的Activity为通明主题,则不会调用onStop;当回到原来Activity时:onRestart->onStart->onResume;当按下返回键:onPause->onStop->onDestroy1.2 启动模式Activity的启动模式有四种:Standard、SingleTop、SingleTask和SingleInstance。 Standard:规范模式,也是默认模式。每次启动都会创立一个全新的实例。SingleTop:栈顶复用模式。这种模式下如果Activity位于栈顶,不会新建实例。onNewIntent会被调用,接管新的申请信息,不会再低啊用onCreate和onStart。SingleTask:栈内复用模式。升级版singleTop,如果栈内有实例,则复用,并会将该实例之上的Activity全副革除。SingleInstance:零碎会为它创立一个独自的工作栈,并且这个实例独立运行在一个 task中,这个task只有这个实例,不容许有别的Activity 存在(能够了解为手机内只有一个)。1.3 启动流程在了解Activity的启动流程之前,先让咱们来看一下Android系统启动流程。总的来说,Android系统启动流程的次要经验init过程 -> Zygote过程 –> SystemServer过程 –> 各种零碎服务 –> 利用过程等阶段。 启动电源以及系统启动:当电源按下时疏导芯片从预约义的中央(固化在ROM)开始执行,加载疏导程序BootLoader到RAM,而后执行。疏导程序BootLoader:BootLoader是在Android零碎开始运行前的一个小程序,次要用于把零碎OS拉起来并运行。Linux内核启动:当内核启动时,设置缓存、被爱护存储器、打算列表、加载驱动。当其实现零碎设置时,会先在系统文件中寻找init.rc文件,并启动init过程。init过程启动:初始化和启动属性服务,并且启动Zygote过程。Zygote过程启动:创立JVM并为其注册JNI办法,创立服务器端Socket,启动SystemServer过程。SystemServer过程启动:启动Binder线程池和SystemServiceManager,并且启动各种零碎服务。Launcher启动:被SystemServer过程启动的AMS会启动Launcher,Launcher启动后会将已装置利用的快捷图标显示到零碎桌面上。Launcher过程启动后,就会调用Activity的启动了。首先,Launcher会调用ActivityTaskManagerService,而后ActivityTaskManagerService会调用ApplicationThread,而后ApplicationThread再通过ActivityThread启动Activity。 2,Fragment2.1 简介Fragment,是Android 3.0(API 11)提出的,为了兼容低版本,support-v4库中也开发了一套Fragment API,最低兼容Android 1.6,如果要在最新的版本中应用Fragment,须要引入AndroidX的包。 相比Activity,Fragment具备如下一些特点: 模块化(Modularity):咱们不用把所有代码全副写在Activity中,而是把代码写在各自的Fragment中。可重用(Reusability):多个Activity能够重用一个Fragment。可适配(Adaptability):依据硬件的屏幕尺寸、屏幕方向,可能不便地实现不同的布局,这样用户体验更好。Fragment有如下几个外围的类: Fragment:Fragment的基类,任何创立的Fragment都须要继承该类。FragmentManager:治理和保护Fragment。他是抽象类,具体的实现类是FragmentManagerImpl。FragmentTransaction:对Fragment的增加、删除等操作都须要通过事务形式进行。他是抽象类,具体的实现类是BackStackRecord。2.2 生命周期Fragment必须是依存于Activity而存在的,因而Activity的生命周期会间接影响到Fragment的生命周期。相比Activity的生命周期,Fragment的生命周期如下所示。 onAttach():Fragment和Activity相关联时调用。如果不是肯定要应用具体的宿主 Activity 对象的话,能够应用这个办法或者getContext()获取 Context 对象,用于解决Context上下文援用的问题。同时还能够在此办法中能够通过getArguments()获取到须要在Fragment创立时须要的参数。onCreate():Fragment被创立时调用。onCreateView():创立Fragment的布局。onActivityCreated():当Activity实现onCreate()时调用。onStart():当Fragment可见时调用。onResume():当Fragment可见且可交互时调用。onPause():当Fragment不可交互但可见时调用。onStop():当Fragment不可见时调用。onDestroyView():当Fragment的UI从视图构造中移除时调用。onDestroy():销毁Fragment时调用。onDetach():当Fragment和Activity解除关联时调用。如下图所示。 上面是Activity的生命周期和Fragment的各个生命周期办法的对应关系。 2.3 与Activity传递数据2.3.1 Fragment向Activity传递数据首先,在Fragment中定义接口,并让Activity实现该接口,如下所示。 public interface OnFragmentInteractionListener { void onItemClick(String str); }而后,在Fragment的onAttach()中,将参数Context强转为OnFragmentInteractionListener对象传递过来。 public void onAttach(Context context) { super.onAttach(context); if (context instanceof OnFragmentInteractionListener) { mListener = (OnFragmentInteractionListener) context; } else { throw new RuntimeException(context.toString() + " must implement OnFragmentInteractionListener"); }}2.3.2 Activity向Fragment传递数据在创立Fragment的时候,能够通过setArguments(Bundle bundle)形式将值传递给Activity,如下所示。 ...

December 20, 2021 · 9 min · jiezi

关于android:项目应用篇RecyclerView嵌套滑动置顶效果实践~

都2021了,RecyclerView嵌套滑动置顶应该曾经被说烂了吧,然而如果我的项目中真的须要一个这样的构造利用到首页,想找到一个成熟的计划并不容易。这篇文章给出的是已稳固运行大半年的嵌套滑动代码。代码地址: https://github.com/youlookwha... 我的项目起源半年前接到的工作须要将首页改为天猫或京东的一样,当初仿佛滑动置顶都是标配了,之前在网上看到那么多这相似的文章,找找应该不难,后果我简直找遍了所有的文章与我的项目根本都不能应用,有卡顿的bug,问作者有没有利用到我的项目中也没有回应。 原本想像以前的滑动置顶应用CoordinatorLayout+TabLayout+RecyclerView的模式解决,然而感觉欠妥,用uiautomatorviewer剖析了天猫/京东/网易考拉所有App的首页都是应用的RecyclerView-ViewPager-RecyclerView的模式,而后持续寻找时发现了一个最靠近的我的项目 xmuSistone/PersistentRecyclerView。这应该是我找过的最欠缺的代码,而后利用到理论我的项目中发现还是有问题: 1.在华为设施上滑动子RecyclerView时会有跳动2.父RecyclerView下拉刷新应用的是SmartRefreshLayout有issues反馈有卡顿3.子RecyclerView加载更多须要解决4.子RecyclerView嵌套横向的RecyclerView滑动抵触问题5.Android4.4惯性滑动解体问题 当然轮子不可能完满贴合我的项目的需要,于是在下面批改了局部代码。欠缺1.在华为设施上滑动子RecyclerView时会有跳动这个问题我在好几个作者写的滑动置顶代码那里都发现了,其余手机都是没问题的,起因是华为设施灵敏度很高,在手指放在ChildRecyclerView时很容易触发parent.requestDisallowInterceptTouchEvent(false)将事件丢给ParentRecyclerView,而后导致卡顿。解决形式是在dispatchTouchEvent里如果垂直滑动的间隔超过24f才丢给ParentRecyclerView。具体代码: override fun dispatchTouchEvent(e: MotionEvent): Boolean { val x = e.rawX val y = e.rawY when (e.action) { MotionEvent.ACTION_DOWN -> { //将按下时的坐标存储 downX = x downY = y // true 示意让ParentRecyclerView不要拦挡 parent.requestDisallowInterceptTouchEvent(true) } MotionEvent.ACTION_MOVE -> { //获取到间隔差 val dx: Float = x - downX val dy: Float = y - downY // 通过间隔差判断方向 val orientation = getOrientation(dx, dy) val location = intArrayOf(0, 0) getLocationOnScreen(location) when (orientation) { "d" -> if (canScrollVertically(-1)) { // 能够向下滑动时让ParentRecyclerView不要拦挡 parent.requestDisallowInterceptTouchEvent(true) } else { //内层RecyclerView下拉到最顶部时 if(dy < 24f){ // 如果滑动的间隔小于这个值仍然让Parent不拦挡 parent.requestDisallowInterceptTouchEvent(true) }else{ // 将滑动事件抛给Parent,这样能够随着Parent一起滑动 parent.requestDisallowInterceptTouchEvent(false) } } "u" -> { // 向上滑动时,始终由ChildRecyclerView解决 parent.requestDisallowInterceptTouchEvent(true) } } } } return super.dispatchTouchEvent(e)}private fun getOrientation(dx: Float, dy: Float): String { return if (Math.abs(dx) > Math.abs(dy)) { //X轴挪动 if (dx > 0) "r" else "l" //右,左 } else { //Y轴挪动 if (dy > 0) "d" else "u" //下//上 }}2.解决下拉刷新/上拉加载问题(问题2/3)因为之前花了一番功夫写了 ByRecyclerView,反对下拉刷新和上拉加载,其本质上就是Adapter上加一个非凡的viewType来解决,所带来的兼容性也好很多,于是将BaseRecyclerView继承ByRecyclerView后就达到了要求,给ParentRecyclerView和ChildRecyclerView别离加下拉刷新和上拉加载的监听就好了: ...

December 20, 2021 · 1 min · jiezi

关于android:Android性能优化一份详细的布局优化实战指南太特么重要了

前言对于Android开发者来说,懂得根本的利用开发技能往往是不够,因为不论是工作还是面试,都须要开发者懂得大量的性能优化,这对晋升利用的体验是十分重要的。对于Android开发来说,性能优化次要围绕如下方面开展:启动优化、渲染优化、内存优化、网络优化、卡顿检测与优化、耗电优化、安装包体积优化、平安问题等。上面是我整顿了网上很多大佬的教训分享对Android性能优化做了一个总结。 Android性能优化的计划比拟多,在开发过程中,次要思考从以下几个方面优化: 布局优化绘制优化内存透露优化响应速度优化Listview优化Bitmap优化线程优化接下来咱们从这几个方面为大家简略介绍优化计划。 布局优化大家必定都晓得Android中有许多布局,比方Linerlayout、RelativeLayout等,布局优化就是缩小布局文件层级,层级缩小了,那么程序绘制时就快了许多,所以能够进步性能。 在布局代码中,应用什么布局根本恪守以下规定: 如果布局中既能够应用LinearLayout也能够应用RelativeLayout,那么就采纳LinearLayout,这是因为RelativeLayout的性能比较复杂,它的布局过程须要破费更多的CPU工夫。如果布局须要通过嵌套的形式来实现。这种状况下还是倡议采纳RelativeLayout,因为ViewGroup的嵌套就相当于减少了布局的层级,同样会升高程序的性能。3.应用<include>或<merge>标签和ViewStub,提取布局中公共局部的布局,可进步布局初始化效率。 绘制优化绘制优化就是不要再view的onDraw办法中做大量操作。 第一、不要在onDraw办法中创立新的对象,因为onDraw办法可能被频繁调用,这样会产生大量的临时文件,导致内存占用过多,程序执行效率升高。 第二、尽可能的不做耗时的操作,大数量的循环也会占用CPU的工夫 内存透露优化内存透露优化换句话说,就是什么状况可能会导致内存透露,置信大家都比较清楚,因为这也算是高级比拟经典的面试题了。次要有以下几种状况: 不要再Acticity中申明动态变量,这样会是的Activity无奈齐全销毁开释单例设计模式一起的内存透露,单例设计模式的动态个性会使他的生命周期和应用程序的生命周期一样长,这就阐明了如果一个对象不在应用了,而这时单例对象还在持有该对象的援用,这时GC就会无奈回收该对象,造成了内存泄露的状况。所以应用单例模式时,传入的context应该应用ApplicationContext非动态外部类创立的动态实例造成的内存透露Handler造成的内存透露,不要在Activity中用非动态匿名外部类的形式去援用hanlder,比方:public class MainActivity extends AppCompatActivity { private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); loadData(); } private void loadData(){ Message message = Message.obtain(); mHandler.sendMessage(message); }}这样hanlder会持有Activity的援用,handler是运行在一个Looper线程中的,而Looper线程是轮询来解决音讯队列中的音讯的,假如咱们解决的音讯有10条,而当他执行到第6条的时候,用户退出销毁了以后的Activity,这个时候音讯还没有解决完,handler还在持有Activity的援用,这个时候就会导致无奈被GC回收,造成了内存透露。 响应速度优化响应速度优化的核心思想是防止在主线程中做耗时操作,Android规定,Activity如果5秒钟之内无奈响应屏幕触摸事件或者键盘输入事件就会呈现ANR,而BroadcastReceiver如果10秒,Service时20s当然这是小概率事件,如果在相应工夫内未失去反映就会呈现ANR。当有耗时操作时,能够独自开启一个线程去操作。listview优化listview优化置信大家也都比拟相熟了,也是比拟经典的面试题,在这里就不具体赘述了,次要有复用view,首先判断view是否为空,如果不为空间接援用,为空再创立应用ViewHolder类,settag的形式保留布局的控件初始化信息,防止每次都去findviewbyid影响效率Bitmap优化其实思维也很简略,那就是采纳BitmapFactory.Options来加载所需尺寸的图片。这里假如通过ImageView来显示图片,很多时候ImageView并没有图片的原始尺寸那么大,这个时候把整个图片加载进来后再设给imageView,这显然是没必要的,因为ImageView并没有方法显示原始的图片。通过BitmapFactory.Options就能够按肯定的采样率来加载放大后的图片,将放大后的图片在ImageView中显示,这样就会升高内存占用从而在肯定水平上防止OOM,进步了Bitmap加载时的性能。线程优化线程优化的思维是采纳线程池,防止程序中存在大量的Thread。线程池能够重用外部的线程,从而防止了线程的创立和销毁所带来的性能开销,同时线程池还能无效地控制线程池的最大并发数,防止大量的线程因相互抢占系统资源从而导致阻塞景象的产生。因而在理论开发中,咱们要尽量采纳线程池,而不是每次都要创立一个Thread对象。Android性能优化实践方面Android的性能优化牵扯的知识点很多,除了下面讲过的这些罕用解决方案,底层原理也值得咱们深入探讨,此外还有性能监控还有工具的应用。我依据本人的Android开发教训把这些性能优化的底层原理还有各种问题的解决方案和常识纲要都整顿成了材料。心愿能帮到你们。 ..... 因为文章篇幅无限,文档资料内容较多,本能够提供链接下载,但无奈容易被谐和,所以全副存档,须要这些文档这里的敌人,能够点击我的【Gitee】,心愿可能共同进步,共勉!

December 20, 2021 · 1 min · jiezi

关于android:Android笔记ViewPager嵌套fragment

ViewPager嵌套Fragment 新建4个Fragment; 新建ViewPagerAdapter继承FragmentPagerAdapter; public class ViewpagerAdapter extends FragmentPagerAdapter { private ArrayList<Fragment> arrayList; public ViewpagerAdapter(@NonNull FragmentManager fm,ArrayList<Fragment> arrayList) { super(fm); this.arrayList=arrayList; } @NonNull @Override public Fragment getItem(int position) { return arrayList.get(position); } @Override public int getCount() { return arrayList.size(); }}在MainActivity中为ViewPager绑定适配器; arrayList=new ArrayList<>(); arrayList.add(new Fragment1()); arrayList.add(new Fragment2()); arrayList.add(new Fragment3()); arrayList.add(new Fragment4()); viewpagerAdapter= new ViewpagerAdapter(getSupportFragmentManager(),arrayList); viewpager.setAdapter(viewpagerAdapter);结语:后续会继续更新哦,喜爱的话记得点赞关注一下吧。 相干视频【Android进阶】ViewPager嵌套fragment架构解析

December 20, 2021 · 1 min · jiezi

关于android:Python连接MongoDB服务

MongoDB是由C++语言编写的非关系型数据库,是一个基于分布式文件存储的开源数据库系统,其内容存储模式相似JSON对象,它的字段值能够蕴含其余文档、数组及文档数组,非常灵活。在这一节中,咱们就来看看Python 3下MongoDB的存储操作。 1. 筹备工作在开始之前,请确保曾经装置好了MongoDB并启动了其服务,并且装置好了Python的PyMongo库。 2. 连贯MongoDB连贯MongoDB时,咱们须要应用PyMongo库外面的MongoClient。一般来说,传入MongoDB的IP及端口即可,其中第一个参数为地址host,第二个参数为端口port(如果不给它传递参数,默认是27017): import pymongoclient = pymongo.MongoClient(host='localhost', port=27017)这样就能够创立MongoDB的连贯对象了。 另外,MongoClient的第一个参数host还能够间接传入MongoDB的连贯字符串,它以mongodb结尾,例如: client = MongoClient('mongodb://localhost:27017/')这也能够达到同样的连贯成果。 3. 指定数据库MongoDB中能够建设多个数据库,接下来咱们须要指定操作哪个数据库。这里咱们以test数据库为例来阐明,下一步须要在程序中指定要应用的数据库: db = client.test这里调用client的test属性即可返回test数据库。当然,咱们也能够这样指定: db = client['test']这两种形式是等价的。 4. 指定汇合MongoDB的每个数据库又蕴含许多汇合(collection),它们相似于关系型数据库中的表。 下一步须要指定要操作的汇合,这里指定一个汇合名称为students。与指定数据库相似,指定汇合也有两种形式: collection = db.studentscollection = db['students']这样咱们便申明了一个Collection对象。 5. 插入数据接下来,便能够插入数据了。对于students这个汇合,新建一条学生数据,这条数据以字典模式示意: student = { 'id': '20170101', 'name': 'Jordan', 'age': 20, 'gender': 'male'}这里指定了学生的学号、姓名、年龄和性别。接下来,间接调用collection的insert()办法即可插入数据,代码如下: result = collection.insert(student)print(result)在MongoDB中,每条数据其实都有一个_id属性来惟一标识。如果没有显式指明该属性,MongoDB会主动产生一个ObjectId类型的_id属性。insert()办法会在执行后返回_id值。 运行后果如下: 5932a68615c2606814c91f3d当然,咱们也能够同时插入多条数据,只须要以列表模式传递即可,示例如下: student1 = { 'id': '20170101', 'name': 'Jordan', 'age': 20, 'gender': 'male'}student2 = { 'id': '20170202', 'name': 'Mike', 'age': 21, 'gender': 'male'}result = collection.insert([student1, student2])print(result)返回后果是对应的_id的汇合: ...

December 20, 2021 · 2 min · jiezi

关于android:做Android开发怎么才能不被淘汰kotlin语言就是你最好的选择

前言Kotlin语言有什么劣势?Kotlin语言被赞美为Android世界里的Swift. 简略来说,能够这样概括: 齐全兼容JavaNull safe反对lambda表达式(比Java8更好)反对扩大体验统一的开发工具链应用Kotlin对Android开发者意味着什么?应用Kotlin开发,对于安卓开发来说,次要有上面几个无利的影响: 更少的空指针异样更少的代码量更快的开发速度更统一的开发体验kotlin语言将来发展趋势 能够从招聘信息看到,kotlin和java语言曾经是安卓开发师所必须具备的,所以学会这个也是至关重要的。 我整顿了一份详【Android版kotlin协程入门进阶实战】材料。第一章 Kotlin协程的根底介绍协程是什么什么是Job 、Deferred 、协程作用域Kotlin协程的根底用法 第二章 kotlin协程的要害知识点初步解说协程调度器协程调度器协程启动模式协程作用域挂起函数 第三章 kotlin协程的异样解决协程异样的产生流程协程的异样解决 第四章 kotlin协程在Android中的根底利用Android应用kotlin协程在Activity与Framgent中应用协程ViewModel中应用协程其余环境下应用协程 第五章 kotlin协程的网络申请封装协程的罕用环境协程在网络申请下的封装及应用高阶函数形式多状态函数返回值形式间接返回值的形式 第六章 深刻kotlin协程原理(一)suspend 的花花肠子藏在身后的- Continuation村里的心愿- SuspendLambda 第七章 深刻kotlin协程原理(二)协程的那些小机密协程的创立过程协程的挂起与复原协程的执行与状态机 第八章 Kotlin Jetpack 实战从一个膜拜大神的 Demo 开始Kotlin 写 Gradle 脚本是一种什么体验?Kotlin 编程的三重境界Kotlin 高阶函数Kotlin 泛型Kotlin 扩大Kotlin 委托协程“鲜为人知”的调试技巧图解协程原理 第九章 Kotlin + 协程 + Retrofit + MVVM优雅的实现网络申请我的项目配置实现思路协程实现协程 + ViewModel + LiveData实现后续优化异样解决更新Retrofit 2.6.0 因为篇幅无限,敌人们如果须要这份完整版《Android版kotlin协程入门进阶实战》,点击这里支付哦最初Kotlin 的确能够进步开发效率,缩小代码量,作为 Java 的超集,能够齐全兼容并且使得转化无风险,不再呈现空指针异样。so,学好Kotlin语言能让你更加省时省力。如果我的这篇文章能帮忙到你的话,那就多多反对一下我。

December 20, 2021 · 1 min · jiezi

关于android:字节跳动年薪50w的-Android-高级工程师写下的面试总结值得珍藏

前言面试的过程其实也是一个自我认识和学习的过程,即使临时没打算跳槽,隔段时间进来面一面对本人还是有些益处的:不仅能够评估一下本人在市场的价值和竞争力,同时也能理解一些新技术、更新一下本人的技术栈。 而且在一个中央待久了,可能不盲目的就会陷入到一种「舒服区」,长此以往,就像温水里的青蛙,万一哪天被“优化”了可能会手足无措。 本文次要从我的项目和技术两个方面进行总结,除此之外还有一些比拟开放式的问题。 我的项目有人说:五年一道坎。 对于曾经工作五年左右的搭档们来说,我的项目经验堪称重中之重,能够说比具体的技术点更重要。 技术点其实大同小异,有些长期刷刷题就能理解个大略。但我的项目经验往往难以长期假造,如果不是本人实在做过的我的项目、或者没有充沛的筹备,一旦面试官问得略微深刻很可能 hold 不住,面试扣分不少、甚至可能间接挂掉。 因而大厂的不少面试官都喜爱从我的项目动手,抽丝剥茧、步步深刻,通过我的项目把技术点串起来考查。 不同人的我的项目千差万别,但还是有一些独特亮点的:比方APP解体时的解决,简单的架构设计,性能调优及问题排查等。 这些亮点有的话诚然更好,但如果平时 写业务居多、没太多的亮点,其实也不用太慌,技术亮点不多的话,能够多思考一些业务上的亮点。比方: 业务模型比较复杂对业务整体的架构设计很相熟业务模块拆分比拟正当本人在业务中做过哪些扩大和优化?业务数据的上下游流转是怎么的?遇到过什么问题,如何解决的?等等这些其实也是亮点,能够让面试官看到你平时对业务有本人的思考和了解,而不是只关注本人的那一块,不只是写代码的机器。 其实面试官对你的我的项目是无所不知的,他的印象仅仅停留在你简历上形容的那些文字(而且有些面试官可能是被长期拉过来的,别问我为什么晓得 )。面试官通常的开场白就是让你自我介绍,其实这也是一个考查语言组织能力和口头表达能力的中央。 技术咱们面的毕竟是Android开发岗,技术自身的重要性显而易见。 技术面试中,最重要的能够说是技术体系。也就是你不仅要有技术的深度和广度,更要能把它们串起来,其实有不少技术点是相通或类似的,如果面试中可能举一反三、触类旁通,是一个很好的加分项。比方: Android Framework层的源码剖析熟练掌握音视频开发相熟Kotlin语法、或者把握Flutter混合开发技术这里整顿了我面试前刷过的《Android高工技术常识体系PDF》,外面蕴含了诸多Android开发所要进阶的核心技术栈。当初无偿分享给正在浏览中的敌人们。然而因为简书的举荐机制,不能展示全副的核心内容,只能截图分享;须要获取这份《Android高工技术常识体系PDF》文档PDF版的敌人能够在文末获取; 我心愿拿到这份PDF的敌人们能在年前多多刷下,能造成本人的技术常识体系后在去面试,这样对你而言无疑是最大的帮忙。 《Android高工技术常识体系PDF》目录截图 残缺目录版 《Android高工技术常识体系PDF》外围常识截图 末了面试流程我所接触的面试大部分是「四轮技术面 + HR 面」的模式,也有一些是三轮技术面,不同公司可能不太一样。一面个别是电话面初筛,前面二三轮技术面和 HR 面通常在一起。这样其实也挺好,跑一趟就行了。 心态 面试的心态也很重要。 我刚开始面的时候,因为好久没面试,再加上原本就不太爱谈话,刚开始缓和的不行,起初面了几次之后才逐步有点感觉。如果较长时间没面试,能够先面一两家练练手、找找感觉。 当然,整个面试工夫也不倡议拖得太久,否则整个过程会比拟累,倡议还是一鼓作气。 啰里啰嗦一堆,其实面试还是挺看运气的,如果跟面试官聊得比拟投机,对你的评分天然也不错。 最初,预祝在往年想跳槽的敌人们一路绿灯!早日拿到offer! 最初,须要残缺《Android高工常识体系PDF》的敌人们能够点击这里收费支付!

December 20, 2021 · 1 min · jiezi

关于android:Android性能-RocketX

一、背景形容在我的项目体量越来越大的状况下,编译速度也随着增长,有时候一个批改须要期待长达好几分钟的编译工夫。 基于这种广泛的状况,推出了 RocketX ,通过在编译流程 动静 替换 module 为 aar ,进步全量编译的速度。 二、成果展现2.1、测试项目介绍指标我的项目一共 3W+ 个类与资源文件,全量编译 4min 左右(测试应用 18 年 mbp 8代i7 16g)通过 RocketX 全量增速之后的成果(每一个操作取 3 次平均值) 我的项目依赖关系如下图,app 依赖 bm 业务模块,bm 业务模块依赖顶层 base/comm 模块 rx(RocketX) 编译 - 能够看到 rx(RocketX) 在无论哪一个模块的编译速度根本都是在管制在 30s 左右,因为只编译 app 和 改变的模块,其余模块是 aar 包不参加编译。原生编译 - 当 base/comm 模块改变,底部的所有模块都必须参加编译。因为 app/bmxxx 模块可能应用了 base 模块中的接口或变量等,并且不晓得是否有改变到。(那么速度就十分慢)原生编译 - 当 bmDiscover 做了改变,只须要 app 模块和 bmDiscover 两个模块参加编译(速度较快) 对于 rx(RocketX) 编译顶层模块速度晋升 300%+三、思路问题剖析与模块搭建:3.1、思路问题剖析须要通过 gradle plugin 的模式动静批改没有改变过的 module 依赖为 绝对应的 aar 依赖,如果 module 改变,进化成 project 工程依赖,这样每次只有改变的 module 和 app 两个模块编译。须要把 implement/api moduleB,批改为implement/api aarB,并且须要晓得插件中如何退出 aar 依赖和剔除原有依赖须要构建 local maven 存储未被批改的 module 对应的 aar(也能够通过 flatDir 代替速度更快)编译流程启动,须要找到哪一个 module 做了批改须要遍历每一个 module 的依赖关系进行置换, module 依赖怎么获取?一次性能获取到所有模块依赖,还是分模块各自回调?批改其中一个模块依赖关系会阻断前面模块依赖回调?每一个 module 换变成 aar 之后,本身依赖的 child 依赖 (网络依赖,aar),给到 parent module (如何找到所有 parent module) ? 还是间接给 app module ? 有没有 app 到 module 依赖断掉的危险? 这里须要出一个技术计划。须要hook 编译流程,实现后置换 loacal maven 中被批改的 aar提供 AS 状态栏 button, 实现开启敞开性能,减速编译还是让开发者应用曾经习惯性的三角形 run 按钮3.2、模块搭建按照下面的剖析,尽管问题很多,然而大抵能够把整个我的项目分成以下几块: ...

December 20, 2021 · 4 min · jiezi

关于android:Android-10-和Android-11的适配

背景最近在我的项目中着手做Android10和Android11 适配时候,期间遇到了不少的坑。之前有专门写过qq、微信分享的适配。然而此次在针对偏业务侧适配工作的时候还是碰到了一些新的问题。记录下来,不便当前查阅,心愿能帮到碰到此问题的相干同学。 一、 公有目录下资源拜访存在这样一个场景:咱们要分享一张图片到qq或者微信,首先第一步是要是失去这个bitmap(通过本地生成或者网络加载),而后存储到本地sd卡上,最初把存储的图片的绝对路径传给qq或者微信即可。 在以上的场景中,波及到了这些关键点: 把图片存储到sd卡把绝对路径path传递给qq或者微信1.1 间接拜访sd卡的根目录通过FileOutPutStream来实现,在Android10以下都没问题。门路如下: /storage/emulated/0/demo/sharePicture/1637048769163_share.jpg然而在Android10及以上,就会存在会报错: java.io.FileNotFoundException: /storage/emulated/0/demo/sharePicture/1637048769163_share.jpg: open failed: EACCES (Permission denied)//其实存储权限是批准了的这是因为,咱们被存储分区限度了,不能间接拜访内部目录。因而,咱们须要批改存储门路为scope的App-specific目录。 1.2 改为App-specific公有目录该目录本人拜访不须要权限,如果第三方拜访须要权限! 因而,咱们前面通过FileProvider去长期受权即可。 如果对 FileProvider 不相熟,可参考篇头的文章。 /storage/emulated/0/Android/data/com.demo.test/files当你再通过FileOutPutStream来存储图片时候,是胜利的。 private fun saveImage(bitmap: Bitmap, storePath: String, filePath: String): Boolean { val appDir = File(storePath) if (!appDir.exists()) { appDir.mkdirs() } val file = File(filePath) if (file.exists()) { file.delete() } var fos: FileOutputStream? = null try { fos = FileOutputStream(file) bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos) fos.flush() return true } catch (e: IOException) { e.printStackTrace() } catch (e: FileNotFoundException) { e.printStackTrace() } finally { fos?.close() } return false }通过测试,在29的下和29 的设施下,分享qq、微信都胜利了。 ...

December 20, 2021 · 2 min · jiezi

关于android:还在用shapeselector试试自定义圆角组件吧

在进行Android利用开发过程中,设计师常常会给利用中波及的卡片和按钮来个圆角。对于卡片,咱们能够间接应用CardView等,对于圆角按钮通常会shape、selector等xml的形式进行配置。 尽管shape、selector的xml写法能够解决视觉问题,然而写的很多,对于代码的简洁性来说的确大打折扣,并且xml对于Apk包的大小来说也不是很敌对。所以,咱们无妨思考试试自定义圆角组件的形式来解决问题。 基于按钮的一些罕用的属性,咱们提供了如下的一些属性,比方,按钮的圆角大小、圆角色彩、按钮色彩、文字色彩、独自设置4个角的圆角大小等。 <declare-styleable name="RectgleTextView"> <attr name="shapeType" format="integer|enum"> <enum name="rectangle" value="0" /> <enum name="oval" value="1" /> <enum name="LINE" value="2" /> </attr> <attr name="totalRadius" format="dimension" /> <attr name="radiusTopLeft" format="dimension" /> <attr name="radiusBottomLeft" format="dimension" /> <attr name="radiusTopRight" format="dimension" /> <attr name="radiusBottomRight" format="dimension" /> <attr name="topLeft" format="dimension" /> <attr name="topRight" format="dimension" /> <attr name="bottomLeft" format="dimension" /> <attr name="bottomRight" format="dimension" /> <attr name="strColor" format="color" /> <attr name="strWidth" format="dimension" /> <attr name="solidBac" format="color" /> <attr name="textPadding" format="dimension" /> <attr name="textLeft" format="string" /> <attr name="textRight" format="string" /> <attr name="iconColor" format="reference|color" /> <attr name="textLeftColor" format="reference|color" /> <attr name="textRightColor" format="reference|color" /> <attr name="textLeftSize" format="dimension" /> <attr name="textRightSize" format="dimension" /> <attr name="textLeftStyle"> <enum name="bold" value="1" /> <enum name="italic" value="2" /> </attr> <attr name="textRightStyle"> <enum name="bold" value="1" /> <enum name="italic" value="2" /> </attr> <attr name="textCenterStyle"> <enum name="bold" value="1" /> <enum name="italic" value="2" /> </attr> <attr name="autoMaxHeight" format="boolean" /> <attr name="gradientOrientation"> <enum name="top_bottom" value="0" /> <enum name="tp_bl" value="1" /> <enum name="right_left" value="2" /> <enum name="br_tl" value="3" /> <enum name="bottom_top" value="4" /> <enum name="bl_tr" value="5" /> <enum name="left_right" value="6" /> <enum name="tl_br" value="7" /> </attr> <attr name="startSolid" format="reference|color" /> <attr name="centerSolid" format="reference|color" /> <attr name="endSolid" format="reference|color" /> </declare-styleable>而后,咱们创立一个自定义的View,RectgleTextView继承自AppCompatTextView。而后,就是对咱们自定义的属性进行解决,具体不再解释,能够看文末的源码。最初,只须要在布局中引入咱们自定义的组件即可,比方。 ...

December 18, 2021 · 1 min · jiezi

关于android:面试官-说一下你做过哪些性能优化

1、 你对 APP 的启动有过钻研吗? 有做过相干的启动优化吗?程序员:之前做热修复的时候钻研过 Application 的启动原理。我的项目中也做过一些启动优化。 面试官: 哦,你之前钻研过热修复? (这个时候有可能就会深刻的问问热修复的原理,这里咱们就不探讨热修复原理) 那你说说对启动方面都做了哪些优化? 程序员: 我发现程序在冷启动的时候,会有 1s 左右的白屏闪现,低版本是黑屏的景象,在这期间我通过翻阅零碎主题源码,发现了零碎 AppTheme 设置了一个 windowBackground ,由此推断就是这个属性捣的鬼,开始我是通过设置 windowIsTranslucent 通明属性,发现尽管没有了白屏,然而两头还是有一小段不可见,这个用户体验还是不好的。最初我察看了市面上大部分的 Android 软件在冷启动的时候都会有一个 Splash 的广告页,同时在减少一个倒数的计时器,最初才进入到登录页面或者主页面。我最初也是这样做的,起因是这样做的益处能够让用户先基于广告对本 APP 有一个根本意识,而且在倒数的时候也预留给咱们一些对插件和一些必须或者耗时的初始化做一些筹备。 Ps:这里会让面试官感觉你是一个重视用户体验的通过翻阅 Application 启动的源码,当咱们点击桌面图标进入咱们软件应用的时候,会由 AMS 通过 Socket 给 Zygote 发送一个 fork 子过程的音讯,当 Zygote fork 子过程实现之后会通过反射启动 ActivityThread##main 函数,最初又由 AMS 通过 aidl 通知 ActivityThread##H 来反射启动创立Application 实例,并且顺次执行 attachBaseContext 、onCreate 生命周期,由此可见咱们不能在这 2 个生命周期里做主线程耗时操作。 Ps: 这里会让面试官感觉你对 App 利用的启动流程钻研的比拟深,有过实在的翻阅底层源码,而并不是背诵答案。晓得了 attachBaseContext 、onCreate 在利用中最先启动,那么咱们就能够通过 TreceView 等性能检测工具,来检测具体函数耗时工夫,而后来对其做具体的优化。我的项目不及时须要的代码通过异步加载。将对一些使用率不高的初始化,做懒加载。将对一些耗时工作通过开启一个 IntentService来解决。还通过 redex 重排列 class 文件,将启动阶段须要用到的文件在 APK 文件中排布在一起,尽可能的利用 Linux 文件系统的 pagecache 机制,用起码的磁盘 IO 次数,读取尽可能多的启动阶段须要的文件,缩小 IO 开销,从而达到晋升启动性能的目标。通过抖音公布的文章通晓在 5.0 低版本能够做 MultiDex 优化,在第一次启动的时候,间接加载没有通过 OPT 优化的原始 DEX,先使得 APP 可能失常启动。而后在后盾启动一个独自过程,缓缓地做完 DEX 的 OPT 工作,尽可能防止影响到前台 APP 的失常应用。 ...

December 18, 2021 · 4 min · jiezi

关于android:2022中高级-Android-面试必知百题面试题答案解析

前言年年寒冬,年年也挡不住一个安卓程序员谋求大厂的信心。想要进入大厂,咱们须要把握哪些知识点呢? 这里,给大家分享一份《2022中高级 Android 面试必知百题》,总结 2021 年,也为行将到来的 2022 年的面试做好筹备。材料整体包含 Java 方面,Android 方面,kotlin 方面,心愿能给大家面试提供一些帮忙。上面一起来看看具体的面试题: 第一章 Java 方面(一)Java 根底局部抽象类与接口的区别?别离讲讲 final,static,synchronized 关键字能够润饰什么,以及润饰后的作用?请简述一下String、StringBuffer和StringBuilder的区别?“equals”与“==”、“hashCode”的区别和应用场景?Java 中深拷贝与浅拷贝的区别?谈谈Error和Exception的区别?什么是反射机制?反射机制的利用场景有哪些?谈谈如何重写equals()办法?为什么还要重写hashCode()?Java 中 IO 流分为几种?BIO,NIO,AIO 有什么区别?谈谈你对Java泛型中类型擦除的了解,并说说其局限性?String为什么要设计成不可变的?说说你对Java注解的了解?谈一谈Java成员变量,局部变量和动态变量的创立和回收机会?请说说Java中String.length()的运作原理?(二)Java 汇合谈谈List,Set,Map的区别?谈谈ArrayList和LinkedList的区别?请说一下HashMap与HashTable的区别谈一谈ArrayList的扩容机制?HashMap 的实现原理?请简述 LinkedHashMap 的工作原理和应用形式?谈谈对于ConcurrentHashMap的了解?(三)Java 多线程Java 中应用多线程的形式有哪些?说一下线程的几种状态?如何实现多线程中的同步?谈谈线程死锁,如何无效的防止线程死锁?谈谈线程阻塞的起因?请谈谈 Thread 中 run() 与 start() 的区别?synchronized和volatile关键字的区别?如何保障线程平安?谈谈ThreadLocal用法和原理?Java 线程中notify 和 notifyAll有什么区别?什么是线程池?如何创立一个线程池?谈一谈java线程常见的几种锁?谈一谈线程sleep()和wait()的区别?什么是乐观锁和乐观锁?什么是BlockingQueue?请剖析一下其外部原理并谈谈它的应用场景?谈一谈java线程平安的汇合有哪些?Java中为什么会呈现Atomic类?试剖析它的原理和毛病?说说ThreadLocal的应用场景?与Synchronized相比有什么个性?(四)Java 虚拟机谈一谈JAVA垃圾回收机制?答复一下什么是强、软、弱、虚援用以及它们之间的区别?简述JVM中类的加载机制与加载过程?JVM、Dalvik、ART三者的原理和区别?请谈谈Java的内存回收机制?JMM是什么?它存在哪些问题?该如何解决?第二章 Android 方面(一)Android 四大组件相干Activity 与 Fragment 之间常见的几种通信形式?LaunchMode 的利用场景?BroadcastReceiver 与 LocalBroadcastReceiver 有什么区别?对于 Context,你理解多少?IntentFilter是什么?有哪些应用场景?谈一谈startService和bindService的区别,生命周期以及应用场景?Service如何进行保活?简略介绍下ContentProvider是如何实现数据共享的?说下切换横竖屏时Activity的生命周期?Activity中onNewIntent办法的调用机会和应用场景?Intent传输数据的大小有限度吗?如何解决?说说ContentProvider、ContentResolver、ContentObserver 之间的关系?说说Activity加载的流程?(二)Android 异步工作和音讯机制HandlerThread 的应用场景和用法?IntentService 的利用场景和应用姿态?AsyncTask 的长处和毛病?谈谈你对 Activity.runOnUiThread 的了解?子线程是否更新 UI?为什么?谈谈 Handler 机制和原理?为什么在子线程中创立 Handler 会抛异样?试从源码角度剖析 Handler 的 post 和 sendMessage 办法的区别和利用场景?Handler 中有 Loop 死循环,为什么没有阻塞主线程,原理是什么?(三)Android UI 绘制相干Android 补间动画和属性动画的区别?Window和DecorView是什么?DecorView又是如何和Window建立联系的?简述一下 Android 中 UI 的刷新机制?LinearLayout, FrameLayout, RelativeLayout 哪个效率高, 为什么?谈谈Android的事件散发机制?谈谈自定义View的流程?针对RecyclerView你做了哪些优化?谈谈如何优化ListView?谈谈自定义LayoutManager的流程?什么是 RemoteViews?应用场景有哪些?谈一谈获取View宽高的几种办法?谈一谈插值器和估值器?getDimension、getDimensionPixelOffset 和 getDimensionPixelSize 三者的区别?请谈谈源码中StaticLayout的用法和利用场景?有用过ConstraintLayout吗?它有哪些特点?对于LayoutInflater,它是如何通过 inflate 办法获取到具体View的?谈一谈Fragment懒加载?谈谈RecyclerView的缓存机制?请谈谈View.inflate和LayoutInflater.inflate的区别?请谈谈invalidate()和postInvalidate()办法的区别和利用场景?谈一谈自定义View和自定义ViewGroup?谈一谈SurfaceView与TextureView的应用场景和用法?谈一谈RecyclerView.Adapter的几种刷新形式有何不同?谈谈你对Window和WindowManager的了解?谈一谈Activity,View,Window三者的关系?有理解过WindowInsets吗?它有哪些利用?Android中View几种常见位移形式的区别?为什么ViewPager嵌套ViewPager,外部的ViewPager滚动没有被拦挡?请谈谈Fragment的生命周期?请谈谈什么是同步屏障?谈一谈ViewDragHelper的工作原理?谈一谈屏幕刷新机制?(四)Android 性能调优相干谈谈你对Android性能优化方面的理解?个别什么状况下会导致内存透露问题?自定义 Handler 时如何无效地防止内存透露问题?哪些状况下会导致oom问题?ANR 呈现的场景以及解决方案?谈谈Android中内存优化的形式?谈谈布局优化的技巧?Android 中的图片优化计划?Android Native Crash问题如何剖析定位?谈谈怎么给apk瘦身?谈谈你是如何优化App启动过程的?谈谈代码混同的步骤?谈谈如何对WebView进行优化?如何解决大图的加载?谈谈如何对网络申请进行优化?请谈谈如何加载Bitmap并避免内存溢出?(五)Android 中的 IPC请答复一下Android过程间的通信形式?请谈谈你对Binder机制的了解?谈谈 AIDL?(六)Android 零碎 SDK 相干请简要谈谈Android零碎的架构组成?SharedPreferences 是线程平安的吗?它的 commit 和 apply 办法有什么区别?Serializable和Parcelable的区别?请简述一下 Android 7.0 的新个性?谈谈ArrayMap和HashMap的区别?简要说说 LruCache 的原理?为什么举荐用SparseArray代替HashMap?PathClassLoader和DexClassLoader有何区别?说说HttpClient与HttpUrlConnection的区别?并谈谈为何前者会被代替?什么是Lifecycle?请剖析其外部原理和应用场景?谈一谈Android的签名机制?谈谈安卓apk构建的流程?简述一下Android 8.0、9.0 别离减少了哪些新个性?谈谈Android10更新了哪些内容?如何进行适配?请简述Apk的装置过程?Java与JS代码如何互调?有做过相干优化吗?什么是JNI?具体说说如何实现Java与C++的互调?请简述从点击图标开始app的启动流程?(七)第三方框架剖析谈一谈LeakCanray的工作原理?谈一谈EventBus的原理?谈谈网络申请中的拦截器(Interceptor)?谈一谈Glide的缓存机制?ViewModel的呈现是为了解决什么问题?并简要说说它的外部原理?请说说依赖注入框架ButterKnife的实现原理?谈一谈RxJava背压原理?(八)综合技术请谈谈你对 MVC 和 MVP 的了解?别离介绍下你所晓得Android的几种存储形式?简述下热修复的原理?谈谈如何适配更多机型的?请谈谈你是如何进行多渠道打包的?MVP中你是如何解决Presenter层以避免内存透露的?如何计算一张图片所占的内存空间大小?有没有遇到64k问题,应该如何解决?如何优化 Gradle 的构建速度?如何获取Android设施惟一ID?谈一谈Android P禁用http对咱们开发有什么影响?什么是AOP?在Android中它有哪些利用场景?什么是MVVM?你是如何将其利用于具体我的项目中的?请谈谈你是如何实现数据埋点的?如果让你实现断点上传性能,你认为应该怎么去做?webp和svg格局的图片各自有什么特点?应该如何在Android中应用?说说你是如何进行单元测试的?以及如何利用在MVP和MVVM中?对于GIF 图片加载有什么思路和倡议?为什么要将我的项目迁徙到AndroidX?如何进行迁徙?(九)数据结构方面什么是冒泡排序?如何优化?请用 Java 实现一个简略的单链表?如何反转一个单链表?谈谈你对工夫复杂度和空间复杂度的了解?谈一谈如何判断一个链表成环?什么是红黑树?为什么要用红黑树?什么是疾速排序?如何优化?说说循环队列?如何判断单链表穿插(十)设计模式请简要谈一谈单例模式?对于面向对象的六大根本准则理解多少?请列出几种常见的工厂模式并阐明它们的用法?说说我的项目中用到的设计模式和应用场景?什么是代理模式?如何应用?Android源码中的代理模式?谈一谈单例模式,建造者模式,工厂模式的应用场景?如何正当抉择?谈谈你对原型模式的了解?请谈谈策略模式原理及其利用场景?动态代理和动静代理的区别,什么场景应用?谈一谈责任链模式的应用场景?(十一)计算机网络方面请简述 Http 与 Https 的区别?说一说 https,udp,socket 区别?请简述一次 http 网络申请的过程?谈一谈 TCP/IP 三次握手,四次挥手?为什么说 Http 是牢靠的数据传输协定?TCP/IP协定分为哪几层?TCP 和 HTTP 别离属于哪一层?(十二)Kotlin方面请简述一下什么是 Kotlin?它有哪些个性?Kotlin 中注解 @JvmOverloads 的作用?Kotlin中List与MutableList的区别?Kotlin中实现单例的几种常见形式?谈谈你对Kotlin中的 data 关键字的了解?相比于一般类有哪些特点?什么是委托属性?请简要说说其应用场景和原理?请举例说明Kotlin中with与apply函数的利用场景和区别?Kotlin中 Unit 类型的作用以及与Java中 Void 的区别?Kotlin 中 infix 关键字的原理和应用场景?Kotlin中的可见性修饰符有哪些?相比于Java有什么区别?你感觉Kotlin与Java混合开发时须要留神哪些问题?在Kotlin中,何为解构?该如何应用?在Kotlin中,什么是内联函数?有什么作用?谈谈kotlin中的构造方法?有哪些注意事项?谈谈Kotlin中的Sequence,为什么它解决汇合操作更加高效?请谈谈Kotlin中的Coroutines,它与线程有什么区别?有哪些长处?Kotlin中该如何平安地解决可空类型?说说Kotlin中的Any与Java中的Object有何异同?Kotlin中的数据类型有隐式转换吗?为什么?Kotlin中汇合遍历有哪几种形式?因为篇幅无限,这里只展现了面试题和局部内容截图,有须要完整版《2022中高级 Android 面试必知百题》(面试题+答案解析)的敌人能够【点击此处收费支付!】 ...

December 18, 2021 · 1 min · jiezi

关于android:RecyclerView预加载

列表的内容是由服务器返回的分页数据,每次浏览到当前页的尾部,都会拉取下一页的数据。这中断用户的浏览,未免产生期待。产品心愿让这个过程无感知。一种实现计划是预加载,即在一页数据还未看完时就申请下一页数据,让用户感觉列表的内容是无穷的。 监听列表滚动状态第一个想到的计划是监听列表滚动状态,当列表快滚动到底部时执行预加载,RecyclerView.OnScrollListener提供了两个回调: public class RecyclerView { public abstract static class OnScrollListener { public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState){} public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy){} }}在onScrolled()能够拿到LayoutManager,它提供了很多和表项地位无关的办法: // 为 RecyclerView 新增扩大办法,用于监听预加载事件fun RecyclerView.addOnPreloadListener(preloadCount: Int, onPreload: () -> Unit) { // 监听 RecyclerView 滚动状态 addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy) // 获取 LayoutManger val layoutManager = recyclerView.layoutManager // 如果 LayoutManager 是 LinearLayoutManager if (layoutManager is LinearLayoutManager) { // 如果列表正在往上滚动,并且表项最初可见表项索引值 等于 预加载阈值 if (dy > 0 && layoutManager.findLastVisibleItemPosition() == layoutManager.itemCount - 1 - preloadCount) { onPreload() } } } })}当列表滚动时,实时检测列表中最初一个可见表项索引 和 预加载阈值 是否相等,若相等则示意列表快滚动到底部了,则触发预加载回调。而后就能够像这样实现预加载: ...

December 18, 2021 · 2 min · jiezi

关于android:收藏Dropbox-是如何解决-Android-App-的内存泄漏问题的

当应用程序为对象分配内存,而对象不再被应用时却没有开释,就会产生内存透露。随着工夫的推移,透露的内存会累积,导致应用程序性能变差,甚至解体。透露可能产生在任何程序战争台上,但因为流动生命周期的复杂性,这种状况在 Android 利用中尤其广泛。最新的 Android 模式,如 ViewModel 和 LifecycleObserver 能够帮忙防止内存透露,但如果你遵循旧的模式或不晓得要留神什么,很容易漏过谬误。 常见例子 援用长期运行的服务 Fragment 援用了一个流动,而该流动援用一个长期运行的服务 在这种状况下,咱们有一个规范设置,流动持有一个长期运行的服务的援用,而后是 Fragment 及其视图持有流动的援用。例如,假如流动以某种形式创立了对其子 Fragment 的援用。而后,只有流动还在,Fragment 也会持续存在。那么在 Fragment 的onDestroy和流动的onDestroy之间就产生了内存透露。 该 Fragment 永远不会再应用,但它会始终在内存中  长期运行的服务援用了 Fragment 视图 另一方面,如果服务取得了 Fragment 视图的援用呢? 首先,视图当初将在服务的整个持续时间内放弃活动状态。此外,因为视图持有对其父流动的援用,所以该流动当初也会透露。 只有服务存在,FragmentView 和 Activity 都会节约内存 检测内存透露 当初,咱们曾经晓得了内存透露是如何产生的。让咱们探讨下如何检测它们。显然,第一步是查看你的利用是否会因为OutOfMemoryError而解体。除非单个屏幕占用的内存比手机可用内存还多,否则必定在某个中央存在内存透露。 这种办法只通知你存在的问题,而不是根本原因。内存透露可能产生在任何中央,记录的解体并不没有指向透露,而是指向最终提醒内存应用超过限度的屏幕。 你能够查看所有的面包屑控件,看看它们是否有一些相似之处,但很可能罪魁祸首并不容易辨认。让咱们钻研下其余选项。  LeakCanary LeakCanary 是目前最好的工具之一,它是一个用于 Android 的内存透露检测库。咱们只需在构建中增加一个 build.gradle 文件依赖项。下一次,咱们装置和运行咱们的利用时,LeakCanary 将与它一起运行。当咱们在利用中导航时,LeakCanary 会偶然暂停以转储内存,并提供检测到的透露痕迹。 这个工具比咱们之前的办法要好得多。然而这个过程依然是手动的,每个开发人员只有他们集体遇到的内存透露的本地正本。咱们能够做得更好!  LeakCanary 和 Bugsnag LeakCanary 提供了一个十分不便的代码配方(code recipe),用于将发现的透露上传到 Bugsnag。咱们能够跟踪内存透露,就像咱们在应用程序中跟踪任何其余正告或解体。咱们甚至能够更进一步,应用 Bugsnag Integration 将其连贯到项目管理软件,如 Jira,以取得更好的可见性和问责制。 Bugsnag 连贯到 Jira  LeakCanary 和集成测试 ...

December 18, 2021 · 3 min · jiezi

关于android:引入Jetpack架构后你的App会发生哪些变化

前言常识储备:须要对Lifcycle、LiveData、ViewModel、DataBinding有根本理解 1. 有了Lifecycle,再也不必放心生命周期同步问题1.1 为什么要做生命周期绑定?对于Activity/Fragment其最重要的概念就是生命周期治理,咱们开发者须要在不同生命周期回调中做不同事件。比方onCreate做一些初始化操作,onResume做一些复原操作等等等等,以上这些操作都比拟繁多间接去写也没有多大问题。 但有一些组件须要强依赖于Activity/Fragment生命周期,惯例写法一旦忽略便会引发平安问题,比方上面这个案例: 现有一个视频播放界面,咱们须要做到当跳到另一个界面就暂停播放,返回后再持续播放,退出后重置播放,惯例思路: #class PlayerActivity onCreate(){ player.init() } onResume(){ player.resume() } onPause(){ player.pause() } onDestroy(){ player.release() }读过我上篇文章的小伙伴可能一眼就能看进去这违反了管制反转,人不是机器很容易写错或者忘写,特地是player.release()如果忘写便会引发内存透露 此时咱们能够基于管制反转思维(将player生命周期控制权交给不会出错的框架)进行革新: 第一步: interface ObserverLifecycle{ onCreate() ... onDestroy()}首先定义一个观察者接口,蕴含Activity/Fragment次要生命周期办法 第二步: class BaseActivity{ val observers = mutableList<ObserverLifecycle>() onCreate(){ observers.forEach{ observer.onCreate() } } ... onDestroy(){ observers.forEach{ observer.onDestroy() } }}在BaseActivity中察看生命周期并逐个告诉到observers的观察者 第三步: class VideoPlayer : ObserverLifecycle{ onCreate(){ init() } ... onDestroy(){ release() }}class PlayerActivity : BaseActivity{ observers.add(videoPlayer)}播放器实现ObserverLifecycle接口,并在每个机会调用相应办法。PlayerActivity只需将videoPlayer注册到observers即可实现生命周期同步。 其实不光videoPlayer,任何须要依赖Activity生命周期的组件 只需实现ObserverLifecycle接口最初注册到Activity的observers即可实现生命周期自动化治理,进而能够躲避误操作带来的危险 1.2 Lifecycle解决了哪些问题?既然生命周期的同步如此重要,Google必定不会熟视无睹,尽管自定义ObserverLifecycle能够解决这种问题,但并不是每个人都能想到。所以Google就制订了一个标准化的生命周期管理工具Lifecycle,让开发者碰到生命周期问题自然而然的想到Lifecycle,就如同想在Android手机上新建一个界面就会想到Activity一样。 同时Activity和Fragment外部均内置了Lifecycle,应用非常简单,以1.1 案例通过Lifecycle革新后如下: class VideoPlayer : LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) fun onCreate(){ init() } .. @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) fun onDestroy(){ release() }}class PlayerActivity : BaseActivity{ lifecycle.addObserver(videoPlayer)}两步操作即可,不必咱们本人向观察者(videoPlayer)做生命周期散发解决。 ...

December 18, 2021 · 2 min · jiezi

关于android:Android入门教程-Android-压缩字符串

Android 压缩字符串Android 端能够对字符串进行压缩。 在进行大量简略文本传输时,能够先压缩字符串再发送。接收端接管后再解压。也能够将字符串压缩后存入数据库中。 应用到的类库 GZIPInputStreamGZIPOutputStream代码示例 import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.util.zip.GZIPInputStream;import java.util.zip.GZIPOutputStream;public class StrZipUtil { /** * @param input 须要压缩的字符串 * @return 压缩后的字符串 * @throws IOException IO */ public static String compress(String input) throws IOException { if (input == null || input.length() == 0) { return input; } ByteArrayOutputStream out = new ByteArrayOutputStream(); GZIPOutputStream gzipOs = new GZIPOutputStream(out); gzipOs.write(input.getBytes()); gzipOs.close(); return out.toString("ISO-8859-1"); } /** * @param zippedStr 压缩后的字符串 * @return 解压缩后的 * @throws IOException IO */ public static String uncompress(String zippedStr) throws IOException { if (zippedStr == null || zippedStr.length() == 0) { return zippedStr; } ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayInputStream in = new ByteArrayInputStream(zippedStr .getBytes("ISO-8859-1")); GZIPInputStream gzipIs = new GZIPInputStream(in); byte[] buffer = new byte[256]; int n; while ((n = gzipIs.read(buffer)) >= 0) { out.write(buffer, 0, n); } // toString()应用平台默认编码,也能够显式的指定如toString("GBK") return out.toString(); }}红米手机测试输入 ...

December 17, 2021 · 3 min · jiezi

关于android:史上最全的Android面试题集锦

Android根本知识点1、惯例知识点1、 Android类加载器在Android开发中,不论是插件化还是组件化,都是基于Android零碎的类加载器ClassLoader来设计的。只不过Android平台上虚拟机运行的是Dex字节码,一种对class文件优化的产物,传统Class文件是一个Java源码文件会生成一个.class文件,而Android是把所有Class文件进行合并、优化,而后再生成一个最终的class.dex,目标是把不同class文件反复的货色只需保留一份,在晚期的Android利用开发中,如果不对Android利用进行分dex解决,那么最初一个利用的apk只会有一个dex文件。 Android中罕用的类加载器有两种,DexClassLoader和PathClassLoader,它们都继承于BaseDexClassLoader。区别在于调用父类结构器时,DexClassLoader多传了一个optimizedDirectory参数,这个目录必须是外部存储门路,用来缓存零碎创立的Dex文件。而PathClassLoader该参数为null,只能加载外部存储目录的Dex文件。所以咱们能够用DexClassLoader去加载内部的apk文件,这也是很多插件化技术的根底。 2、 Service了解Android的Service,能够从以下几个方面来了解: Service是在main Thread中执行,Service中不能执行耗时操作(网络申请,拷贝数据库,大文件)。能够在xml中设置Service所在的过程,让Service在另外的过程中执行。Service执行的操作最多是20s,BroadcastReceiver是10s,Activity是5s。Activity通过bindService(Intent,ServiceConnection,flag)与Service绑定。Activity能够通过startService和bindService启动Service。IntentServiceIntentService是一个抽象类,继承自Service,外部存在一个ServiceHandler(Handler)和HandlerThread(Thread)。IntentService是解决异步申请的一个类,在IntentService中有一个工作线程(HandlerThread)来解决耗时操作,启动IntentService的形式和一般的一样,不过当执行完工作之后,IntentService会主动进行。另外能够屡次启动IntentService,每一个耗时操作都会以工作队列的模式在IntentService的onHandleIntent回调中执行,并且每次执行一个工作线程。IntentService的实质是:封装了一个HandlerThread和Handler的异步框架。 2.1、生命周期示意图Service 作为 Android四大组件之一,利用十分宽泛。和Activity一样,Service 也有一系列的生命周期回调函数,具体如下图。 通常,启动Service有两种形式,startService和bindService形式。 2.2、startService生命周期当咱们通过调用了Context的startService办法后,咱们便启动了Service,通过startService办法启动的Service会始终无限期地运行上来,只有在内部调用Context的stopService或Service外部调用Service的stopSelf办法时,该Service才会进行运行并销毁。 onCreateonCreate: 执行startService办法时,如果Service没有运行的时候会创立该Service并执行Service的onCreate回调办法;如果Service曾经处于运行中,那么执行startService办法不会执行Service的onCreate办法。也就是说如果屡次执行了Context的startService办法启动Service,Service办法的onCreate办法只会在第一次创立Service的时候调用一次,当前均不会再次调用。咱们能够在onCreate办法中实现一些Service初始化相干的操作。 onStartCommandonStartCommand: 在执行了startService办法之后,有可能会调用Service的onCreate办法,在这之后肯定会执行Service的onStartCommand回调办法。也就是说,如果屡次执行了Context的startService办法,那么Service的onStartCommand办法也会相应的屡次调用。onStartCommand办法很重要,咱们在该办法中依据传入的Intent参数进行理论的操作,比方会在此处创立一个线程用于下载数据或播放音乐等。 public @StartResult int onStartCommand(Intent intent, @StartArgFlags int flags, int startId) {}当Android面临内存匮乏的时候,可能会销毁掉你以后运行的Service,而后待内存短缺的时候能够从新创立Service,Service被Android零碎强制销毁并再次重建的行为依赖于Service中onStartCommand办法的返回值。咱们罕用的返回值有三种值,START_NOT_STICKY、START_STICKY和START_REDELIVER_INTENT,这三个值都是Service中的动态常量。 START_NOT_STICKY如果返回START\_NOT\_STICKY,示意当Service运行的过程被Android零碎强制杀掉之后,不会从新创立该Service,当然如果在其被杀掉之后一段时间又调用了startService,那么该Service又将被实例化。那什么情境下返回该值比拟失当呢?如果咱们某个Service执行的工作被中断几次无关紧要或者对Android内存缓和的状况下须要被杀掉且不会立刻从新创立这种行为也可承受,那么咱们便可将 onStartCommand的返回值设置为START\_NOT\_STICKY。举个例子,某个Service须要定时从服务器获取最新数据:通过一个定时器每隔指定的N分钟让定时器启动Service去获取服务端的最新数据。当执行到Service的onStartCommand时,在该办法内再布局一个N分钟后的定时器用于再次启动该Service并开拓一个新的线程去执行网络操作。假如Service在从服务器获取最新数据的过程中被Android零碎强制杀掉,Service不会再从新创立,这也没关系,因为再过N分钟定时器就会再次启动该Service并从新获取数据。 START_STICKY如果返回START\_STICKY,示意Service运行的过程被Android零碎强制杀掉之后,Android零碎会将该Service仍然设置为started状态(即运行状态),然而不再保留onStartCommand办法传入的intent对象,而后Android零碎会尝试再次从新创立该Service,并执行onStartCommand回调办法,然而onStartCommand回调办法的Intent参数为null,也就是onStartCommand办法尽管会执行然而获取不到intent信息。如果你的Service能够在任意时刻运行或完结都没什么问题,而且不须要intent信息,那么就能够在onStartCommand办法中返回START\_STICKY,比方一个用来播放背景音乐性能的Service就适宜返回该值。 START_REDELIVER_INTENT如果返回START\_REDELIVER\_INTENT,示意Service运行的过程被Android零碎强制杀掉之后,与返回START\_STICKY的状况相似,Android零碎会将再次从新创立该Service,并执行onStartCommand回调办法,然而不同的是,Android零碎会再次将Service在被杀掉之前最初一次传入onStartCommand办法中的Intent再次保留下来并再次传入到从新创立后的Service的onStartCommand办法中,这样咱们就能读取到intent参数。只有返回START\_REDELIVER\_INTENT,那么onStartCommand重的intent肯定不是null。如果咱们的Service须要依赖具体的Intent能力运行(须要从Intent中读取相干数据信息等),并且在强制销毁后有必要从新创立运行,那么这样的Service就适宜返回START\_REDELIVER\_INTENT。 onBindService中的onBind办法是形象办法,所以Service类自身就是抽象类,也就是onBind办法是必须重写的,即便咱们用不到。在通过startService应用Service时,咱们在重写onBind办法时,只须要将其返回null即可。onBind办法次要是用于给bindService办法调用Service时才会应用到。 onDestroyonDestroy: 通过startService办法启动的Service会无限期运行,只有当调用了Context的stopService或在Service外部调用stopSelf办法时,Service才会进行运行并销毁,在销毁的时候会执行Service回调函数。 2.3、bindService生命周期 bindService形式启动Service次要有以下几个生命周期函数: onCreate():首次创立服务时,零碎将调用此办法。如果服务已在运行,则不会调用此办法,该办法只调用一次。 onStartCommand():当另一个组件通过调用startService()申请启动服务时,零碎将调用此办法。 onDestroy():当服务不再应用且将被销毁时,零碎将调用此办法。 onBind():当另一个组件通过调用bindService()与服务绑定时,零碎将调用此办法。 onUnbind():当另一个组件通过调用unbindService()与服务解绑时,零碎将调用此办法。 onRebind():当旧的组件与服务解绑后,另一个新的组件与服务绑定,onUnbind()返回true时,零碎将调用此办法。 3、fragemnt3.1、创立形式(1)动态创立首先咱们须要创立一个xml文件,而后创立与之对应的java文件,通过onCreatView()的返回办法进行关联,最初咱们须要在Activity中进行配置相干参数即在Activity的xml文件中放上fragment的地位。 <fragment android:name="xxx.BlankFragment" android:layout_width="match_parent" android:layout_height="match_parent"> </fragment>(2)动态创建动态创建Fragment次要有以下几个步骤: 创立待增加的fragment实例。获取FragmentManager,在Activity中能够间接通过调用 getSupportFragmentManager()办法失去。开启一个事务,通过调用beginTransaction()办法开启。向容器内增加或替换fragment,个别应用repalce()办法实现,须要传入容器的id和待增加的fragment实例。提交事务,调用commit()办法来实现。3.2、Adapter比照FragmnetPageAdapter在每次切换页面时,只是将Fragment进行拆散,适宜页面较少的Fragment应用以保留一些内存,对系统内存不会多大影响。 FragmentPageStateAdapter在每次切换页面的时候,是将Fragment进行回收,适宜页面较多的Fragment应用,这样就不会耗费更多的内存 3.3、Activity生命周期Activity的生命周期如下图: (1)动静加载:动静加载时,Activity的onCreate()调用完,才开始加载fragment并调用其生命周期办法,所以在第一个生命周期办法onAttach()中便能获取Activity以及Activity的布局的组件; (2)动态加载:1.动态加载时,Activity的onCreate()调用过程中,fragment也在加载,所以fragment无奈获取到Activity的布局中的组件,但为什么能获取到Activity呢? 2.原来在fragment调用onAttach()之前其实还调用了一个办法onInflate(),该办法被调用时fragment曾经是和Activity互相联合了,所以能够获取到对方,然而Activity的onCreate()调用还未实现,故无奈获取Activity的组件; 3.Activity的onCreate()调用实现是,fragment会调用onActivityCreated()生命周期办法,因而在这儿开始便能获取到Activity的布局的组件; 3.4、与Activity通信fragment不通过构造函数进行传值的起因是因为横屏切换的时候获取不到值。 Activity向Fragment传值:Activity向Fragment传值,要传的值放到bundle对象里; 在Activity中创立该Fragment的对象fragment,通过调用setArguments()传递到fragment中; 在该Fragment中通过调用getArguments()失去bundle对象,就能失去外面的值。 Fragment向Activity传值:第一种:在Activity中调用getFragmentManager()失去fragmentManager,,调用findFragmentByTag(tag)或者通过findFragmentById(id),例如: FragmentManager fragmentManager = getFragmentManager();Fragment fragment = fragmentManager.findFragmentByTag(tag);第二种:通过回调的形式,定义一个接口(能够在Fragment类中定义),接口中有一个空的办法,在fragment中须要的时候调用接口的办法,值能够作为参数放在这个办法中,而后让Activity实现这个接口,必然会重写这个办法,这样值就传到了Activity中 ...

December 17, 2021 · 5 min · jiezi

关于android:ConstraintLayout20之MotionEffect简单的代码实现炫酷的动效

MotionEffectMotionEffect是2.1中的一个新的MotionHelper,能够让你依据视图的整体静止方向,主动为其援用的视图增加关键帧。它能够简化很多过渡动画的创作。 为了更好地了解它的作用,请看上面的例子。这个例子只应用了MotionLayout的start和end性能,它主动创立了两种场景下的过渡成果。 默认的两种状态之间的过渡做了一个线性插值的挪动成果——这个展现后果是凌乱的,并不令人欢快。 如果咱们看这个例子,咱们能够辨认出只向西挪动的元素(2、3、6、9),而其余元素则以其它不同的模式挪动(1、4、5、7、8)。 咱们能够应用MotionEffect对这些元素利用淡入淡出的成果,给人带来更愉悦的成果。 能够查看上面的demo。 <androidx.constraintlayout.motion.widget.MotionLayout ... >    <TextView android:id="@+id/t1" ... />    <TextView android:id="@+id/t2" ... />    <TextView android:id="@+id/t3" ... />    <TextView android:id="@+id/t4" ... />    <TextView android:id="@+id/t5" ... />    <TextView android:id="@+id/t6" ... />    <TextView android:id="@+id/t7" ... />    <TextView android:id="@+id/t8" ... />    <TextView android:id="@+id/t9" ... />    ...    <androidx.constraintlayout.helper.widget.MotionEffect        android:id="@+id/fade"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        app:constraint_referenced_ids="t1,t2,t3,t4,t5,t6,t7,t8,t9"    /></androidx.constraintlayout.motion.widget.MotionLayout>Controling which views get the effect首先,只有MotionEffect中援用的视图才有可能失去成果。 其次,默认状况下,咱们会主动计算这些视图的次要挪动方向(在北、南、东、西之间),只有与该方向相同挪动的视图才会失去利用于它们的成果。 应用motionEffect_move=auto|north|south|east|west,你能够笼罩它来指定你想要成果利用到哪个方向。 你也能够应用motionEffect_strict=true|false来让这个成果严格地利用于(或不利用于)做这个静止的元素。 默认成果 默认状况下,成果将利用淡出/淡入;你能够通过以下属性管制alpha的数量以及成果的开始/完结。 app:motionEffect_start="keyframe"app:motionEffect_end="keyframe" 你也能够管制alpha和translation的数值。 app:motionEffect_alpha="alpha"app:motionEffect_translationX="dimension"app:motionEffect_translationX="dimension"Custom effect你也能够援用一个ViewTransition来代替默认的淡入淡出成果利用到widget上,只需设置motionEffect_viewTransition,你就能够无限度地管制你想要利用的成果类型。 例如,要失去以下动画。 你能够创立一个ViewTransition,并在MotionEffect中援用它。 在layout xml中: <androidx.constraintlayout.helper.widget.MotionEffect...app:motionEffect_viewTransition="@+id/coolFade"/>在motion scene中: <ViewTransition android:id="@+id/coolFade">    <KeyFrameSet>        <KeyAttribute            motion:framePosition="20"            android:scaleX="0.1"            android:scaleY="0.1"            android:rotation="-90"            android:alpha="0" />        <KeyAttribute            motion:framePosition="80"            android:scaleX="0.1"            android:scaleY="0.1"            android:rotation="-90"            android:alpha="0" />    </KeyFrameSet></ViewTransition>文末您的点赞珍藏就是对我最大的激励! 欢送关注我,分享Android干货,交换Android技术。 对文章有何见解,或者有何技术问题,欢送在评论区一起留言探讨!

December 17, 2021 · 1 min · jiezi

关于android:Kotlin-风格应该这样写drawable

前言通常咱们在res/drawable上面自定义shape和selector来满足一些UI的设计,然而因为xml最终转换为drawable须要通过IO或反射创立,会有一些性能损耗,另外随着我的项目的增大和模块化等,很多通用的款式并不能疾速复用,须要正当的我的项目资源管理标准能力施行。那么通过代码间接创立这些drawable,能够在肯定水平上升高这些副作用。本篇介绍用kotlin DSL简洁的语法个性来实现常见的drawable。 代码对应成果预览 集成和应用在我的项目级的build.gradle文件种增加仓库Jitpack: allprojects {    repositories {        ...        maven { url 'https://jitpack.io' }    }}增加依赖 dependencies {   implementation 'com.github.forJrking:DrawableDsl:0.0.3’}摈弃xml创立形式示例(其余参见demo) // infix用法用于去掉括号更加简洁,具体前面阐明image src shapeDrawable {    //指定shape款式    shape(ShapeBuilder.Shape.RECTANGLE)    //圆角,反对4个角独自设置    corner(20f)    //solid 色彩    solid("#ABE2E3")    //stroke 色彩,边框dp,虚线设置    stroke(R.color.white, 2f, 5f, 8f)}//按钮点击款式btn.background = selectorDrawable {    //默认款式    normal = shapeDrawable {        corner(20f)        gradient(90, R.color.F97794, R.color.C623AA2)    }    //点击成果    pressed = shapeDrawable {        corner(20f)        solid("#84232323")    }}实现思路xml如何转换成drawablexml变成drawable,通过android.graphics.drawable.DrawableInflater这个类来IO解析标签创立,而后通过解析标签再设置属性: //标签创立private Drawable inflateFromTag(@NonNull String name) {    switch (name) {        case "selector":            return new StateListDrawable();        case "level-list":            return new LevelListDrawable();        case "layer-list":            return new LayerDrawable();        ....        case "color":            return new ColorDrawable();        case "shape":            return new GradientDrawable();        case "vector":            return new VectorDrawable();        ...    }}//反射创立private Drawable inflateFromClass(@NonNull String className) {    try {        Constructor<? extends Drawable> constructor;        synchronized (CONSTRUCTOR_MAP) {            constructor = CONSTRUCTOR_MAP.get(className);            if (constructor == null) {                final Class<? extends Drawable> clazz = mClassLoader.loadClass(className).asSubclass(Drawable.class);                constructor = clazz.getConstructor();                CONSTRUCTOR_MAP.put(className, constructor);            }        }        return constructor.newInstance();    } catch (NoSuchMethodException e) {    ...}代码实现因为创立shape等须要设置各种属性来构建,比拟合乎build设计模式,那咱们首先封装build模式的shapeBuilder,这样做尽管代码比起间接应用apply{}要多,然而能够让纯java我的项目用起来很难受,其余实现请查看源码: class ShapeBuilder : DrawableBuilder {    private var mRadius = 0f    private var mWidth = 0f    private var mHeight = 0f    ...    private var mShape = GradientDrawable.RECTANGLE    private var mSolidColor = 0    /**别离设置四个角的圆角*/    fun corner(leftTop: Float,rightTop: Float,leftBottom: Float,rightBottom: Float): ShapeBuilder {        ....if(dp)dp2px(leftTop) else leftTop        return this    }    fun solid(@ColorRes colorId: Int): ShapeBuilder {        mSolidColor = ContextCompat.getColor(context, colorId)        return this    }    // 省略其余参数设置办法 具体代码查看源码    override fun build(): Drawable {        val gradientDrawable = GradientDrawable()        gradientDrawable = GradientDrawable()        gradientDrawable.setColor(mSolidColor)        gradientDrawable.shape = mShape        ....其余参数设置        return gradientDrawable    }    }把build模式转换为dsl实践上所有的build模式都能够轻松转换为dsl写法: inline fun shapeDrawable(builder: ShapeBuilder.() -> Unit): Drawable {    return ShapeBuilder().also(builder).build()}//应用办法 val drawable = shapeDrawable{    ...}备注:dsl用法参见juejin.cn/post/695318… 中dsl大节函数去括号通过下面封装曾经实现了dsl的写法,通常setBackground能够通过setter简化,然而我发现因为有些api设计还须要加括号,这样不太kotlin: //容易浏览iv1.background = shapeDrawable {    shape(ShapeBuilder.Shape.RECTANGLE)    solid("#ABE2E3")}//多了括号看起来不难受iv2.setImageDrawable(shapeDrawable {    solid("#84232323")})怎么去掉括号呢?2种形式infix函数(中断表白)和property setter infix函数特点和标准: Kotlin容许在不应用括号和点号的状况下调用函数必须只有一个参数必须是成员函数或扩大函数不反对可变参数和带默认值参数/**为所有ImageView增加扩大infix函数 来去掉括号*/infix fun ImageView.src(drawable: Drawable?) {    this.setImageDrawable(drawable)}//应用如下iv2 src shapeDrawable {    shape(ShapeBuilder.Shape.OVAL)    solid("#E3ABC2")}当然了代码是用来浏览的。集体认为如果咱们大量应用infix函数,浏览艰难会大大增加,所以倡议函数命名必须能够直击函数性能,而且函数性能简略且繁多。 property setter形式,次要应用kotlin能够简化setter为 变量 =来去括号: /**扩大变量*/var ImageView.src: Drawable    get() = drawable    set(value) {        this.setImageDrawable(value)    }//应用如下   iv2.src = shapeDrawable {    shape(ShapeBuilder.Shape.OVAL)    solid("#E3ABC2")}优缺点长处: 代码间接创立比起xml形式能够晋升性能dsl形式比起build模式和调用办法设置更加简洁合乎kotlin格调通过适合的代码治理能够复用这些代码,比xml治理不便毛病: 没有as的预览性能,只有通过上机观测api还没有笼罩所有drawable属性(例如shape = ring等)后语下面把的DrawableDsl根底用法介绍完了,欢送大家应用,欢送提Issues,记得给个star哦。Github链接:https://github.com/forJrking/... 文末您的点赞珍藏就是对我最大的激励!欢送关注我,分享Android干货,交换Android技术。对文章有何见解,或者有何技术问题,欢送在评论区一起留言探讨!

December 17, 2021 · 1 min · jiezi

关于android:Android-学习笔记androidActivity学习

Activity创立的三要素:1、创立的类要去继承activity2、setContentView();利用布局文件3、在清单文件中进行配置android:name="com.example.ex_0310_01.MainActivity"(包名.类名) 1、A---->B调用startActivity(intent);A界面: //取得一个用意对象Intent intent = new Intent();intent.setClass(MainActivity.this, SecondActivity.class); //传递附加音讯 //以键值对的模式去传递音讯//key:必须是字符串//value:根本数据类型,以及实现了序列化接口的对象intent.putExtra("key1", "你好");intent.putExtra("key2", true);//开启一个新的activitystartActivity(intent);B界面: //获取A界面传过来的用意对象Intent intent = getIntent();//通过key去把用意对象里的信息获取到boolean extra = intent.getBooleanExtra("key3", false);String str = intent.getStringExtra("key1");2、A---->B---->AA: // 取得一个用意对象Intent intent = new Intent();intent.setClass(MainActivity.this, SecondActivity.class);// 传递音讯// 以键值对的模式去传递音讯// key:必须是字符串// value:根本数据类型,以及实现了序列化接口的对象intent.putExtra("key1", "你好");intent.putExtra("key2", true);// 开启一个新的activity 并且期待音讯返回startActivityForResult(intent, 0);B: Intent data = new Intent();data.putExtra("msg", "音讯已收到");setResult(0, data );//敞开以后界面finish();A: //接管B界面返回的音讯@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data){ super.onActivityResult(requestCode, resultCode, data); String msg = data.getStringExtra("msg"); mTextView.setText(msg);}申请码:A有两个按钮,都是跳转到B,B界面解决完返回音讯,就用申请码进行辨别,是点击了哪一个按钮跳转到B,而后返回A的startActivityForResult(intent , 申请码); 后果码:B有两个按钮,都是跳回到A,A界面就是通过后果码来进行判断返回不同的解决信息setResult(后果码, data ); 对于音讯的解决都是在onActivityResult这个办法中去实现的。 ...

December 17, 2021 · 1 min · jiezi

关于android:深入探索-Paging-30-分页加载来自网络和数据库的数据-MAD-Skills

欢送回到 MAD Skills 系列之 Paging 3.0!在上一篇文章《获取数据并绑定到 UI | MAD Skills》中,咱们在 ViewModel 中集成了 Pager,并利用配合 PagingDataAdapter 向 UI 填充数据,咱们也增加了加载状态指示器,并在呈现谬误时从新加载。 这次,咱们把难度晋升一个品位。目前为止,咱们都是间接通过网络加载数据,而这样的操作只实用于现实环境。咱们有时候可能遇到网络连接迟缓,或者齐全断网的状况。同时,即便网络状况良好,咱们也不会心愿本人的利用成为数据黑洞——在导航到每个界面时都拉取数据是一种非常节约的行为。 解决这一问题的办法便是从 本地缓存 加载数据,并且只在必要的时候进行刷新。对缓存数据的更新必须先达到本地缓存,再流传至 ViewModel。这样一来,本地缓存便可成为惟一可信的数据源。对咱们来说非常不便的是 Paging 库在 Room 库一些小小的帮忙下曾经能够应答这种场景。上面就让咱们开始吧!点击这里 查看 Paging: 显示数据及其加载状态视频,理解更多详情。 应用 Room 创立 PagingSource因为咱们将要分页的数据源会来自本地而不是间接依赖 API,那么咱们要做的第一件事便是更新 PagingSource。好消息是,咱们要做的工作很少。是因为我后面提到的 "来自 Room 的小小帮忙" 吗?事实上这里的帮忙远不止于一点: 只须要在 Room 的 DAO 中为 PagingSource 增加申明,便可通过 DAO 获取 PagingSource! @Daointerface RepoDao { @Query( "SELECT * FROM repos WHERE " + "name LIKE :queryString" ) fun reposByName(queryString: String): PagingSource<Int, Repo>}咱们当初能够在 GitHubRepository 中更新 Pager 的构造函数来应用新的 PagingSource 了: ...

December 17, 2021 · 2 min · jiezi

关于android:学好插件化年薪50w原来这是真的

前言随着互联网公司业务的倒退,公司我的项目的增多,然而开发源又是无限的。如何在无限的开发源中满足更多我的项目的需要,成为了各个大厂比拟器重的问题。此时,插件化技术正好风生水起,所以各公司都开始物色有这方面技术的人才。 插件化的性能及劣势:当初美团,支付宝外面都有很多很多性能, “美食,电影,购物,打车,游览”等。这都是实现插件化的益处,如果没有这些插件化,那这些app会有多大,咱们用户手机外面得下载多少个app?举个例子,原本下载一个app能够实现好几个性能的使用,如果没有插件化这个技术,那咱们就须要下载好几个app来满足咱们的需要。然而每个手机的内存又是有限度的,如果下载的货色过多,会导致运行卡顿,带来极差的体验感。 插件化能给咱们业务上带来的帮忙:APP因为业务的频繁变更而频繁降级客户端,会造成较差的用户体验,插件化能够做到动静降级,不须要更新整个客户端APP往往须要集成许多的性能,插件化能够使模块解藕并行开发,进步开发效率插件化冲破最大办法数的限度插件化做到了按需加载,进步了内存的应用效率节俭了降级流量。插件化能够让一个app的性能模块化。插件化能够并行高效开发、模块解耦、有利于前期的保护。 对于Android开发者而言,插件化技术曾经是进阶Android高级工程师的必备技能之一。我这里有一份【高级Android插件化强化实战】材料,心愿能帮到大家!次要内容分成四大模块:第一章:插件化技术的前世今生 第二章:插件化原理 第三章:Android插件化初探 第四章:架构演变(大长篇) 第一章:插件化技术的前世今生1. 插件化提要 2. 插件化发展历史 第二章:插件化原理1. 类加载 2. 双亲委托机制 3. 资源加载 4. 四大组件反对 5. ProxyActivity代理 6. hook形式 7. 其余组件 … 第三章:Android插件化初探1. 从零开始实现一个插件化框架(上) 概念插件化解决的问题各插件化框架比照插件化实现ClassLoader实现类 2. 从零开始实现一个插件化框架(中) Activity的启动流程寻找Hook点撸码阶段代理对象偷天换日,替换原来的IntentActivityThread将代理的intent替换回来 … 3.从零开始实现一个插件化框架(下) 插件资源加载Android中资源加载流程ActivityManagerActivityThreadAppCompatActivity总结 第四章:架构演变(大厂篇)1. 360插件开发之DroidPluginDroidPlugin是360手机助手在Android零碎上实现了一种新的插件机制。它能够在无需装置、批改的状况下运行APK文件,此机制对改良大型APP的架构,实现多团队合作开发具备肯定的益处。 2.滴滴VirtualApk实战VirtualAPK是滴滴在2017年6月开源的一款插件化框架,反对Android四大组件,以及简直所有的Android个性,通过Gradle来构建插件,集成与构建非常便捷,目前曾经利用在 滴滴出行 App上,兼容市面上简直所有的Android设施。 3.爱奇艺插件化原理剖析之 Neptune框架Neptune是爱奇艺挪动端研发的一套灵便,稳固,轻量级的插件化解决方案。通过一直的研发,迭代和线上验证,目前曾经齐全适配了Android P,可能在数亿的设施上动静加载和运行插件APK,为爱奇艺泛滥的垂直业务团队提供了稳固的服务。 4. 360开源全面插件化框架RePlugin 实战RePlugin 是一套残缺的、稳固的、适宜全面应用的,占坑类插件化计划,由360手机卫士的RePlugin Team研发,也是业内首个提出”全面插件化“(全面个性、全面兼容、全面应用)的计划。 5.腾讯插件化框架 Shadow我的项目解析Shadow是一个腾讯自主研发的Android插件框架,通过线上亿级用户量测验。Shadow不仅开源分享了插件技术的要害代码,还残缺的分享了上线部署所须要的所有设计。更是具备复用独立装置App的源码、零反射无Hack实现插件技术、全动静插件框架、宿主增量极小、Kotlin反对等特点。 因为文章篇幅无限,须要完整版《高级Android插件化强化实战》点这里支付哦!最初插件化技术对于一个进阶Android高级工程师的必备技能之一。一个好的工程师,他不仅要懂得原理,还得去学习把技术使用到实际中去,这是一个优良的程序员所必须具备的。如果我的这篇文章能帮忙到你的话,那就多多反对一下我。

December 17, 2021 · 1 min · jiezi

关于android:AndroidFragment-Activity-二合一

前言是否在不蕴含侧滑菜单的时候,增加一个侧滑返回,边缘finish以后Fragment?明天把这项工作实现了,做成了独自的SwipeBackFragment库以及Fragmentation-SwipeBack拓展库 个性: 1、SwipeBackFragment , SwipeBackActivity二合一:当Activity内的Fragment数大于1时,滑动finish的是Fragment,如果小于等于1时,finish的是Activity。 2、反对左、右、左&右滑动(将来可能会减少更多滑动区域) 3、反对Scroll中的滑动监听 4、帮你解决了app被零碎强杀后引起的Fragment重叠的状况 成果 效果图 谈谈实现拖拽局部大部分是靠ViewDragHelper来实现的,ViewDragHelper帮咱们解决了大量Touch相干事件,以及对速度、开释后的一些逻辑监控,大大简化了咱们对触摸事件的解决。(本篇不对ViewDragHelper做具体介绍,有不相熟的小伙伴能够自行查阅相干文档) 对Fragment以及Activiy的滑动退出,原理是一样的,都是在Activity/Fragment的视图上,增加一个父View:SwipeBackLayout,该Layout里创立ViewDragHelper,管制Activity/Fragment视图的拖拽。 1、Activity的实现对于Activity的SwipeBack实现,网上有大量剖析,这里我简要介绍下原理,如下图: 咱们只有保障SwipeBackLayout、DecorView和Window的背景是通明的,这样拖拽Activity的xml布局时,能够看到上个Activity的界面,把布局滑走时,再finish掉该Activity即可。 public void attachToActivity(FragmentActivity activity) { ... ViewGroup decor = (ViewGroup) activity.getWindow().getDecorView(); ViewGroup decorChild = (ViewGroup) decor.getChildAt(0); decorChild.setBackgroundResource(background); decor.removeView(decorChild); // 移除decorChild addView(decorChild); // 增加decorChild到SwipeBackLayout(FrameLayout) setContentView(decorChild); decor.addView(this);} // 把SwipeBackLayout增加到DecorView下2、Fragment的实现重点来了,Fragment的实现! 在实现前,我先阐明Fragment的几个相干知识点: 1、Fragment的视图局部其实就是在onCreateView返回的View; **2、同一个Activity里的多个通过add装载的Fragment,他们在视图层是叠加下来的: hide()并不销毁视图,仅仅让视图不可见,即View.setVisibility(GONE);, show()让视图变为可见,即View.setVisibility(VISIBLE);;** add+show/hide的状况 3、通过replace装载的Fragment,他们在视图层是替换的,replace()会销毁以后的Fragment视图,即回调onDestoryView,返回时,从新创立视图,即回调onCreateView; replace的状况 4、不论add还是replace,Fragment对象都会被FragmentManager保留在内存中,即便app在后盾因系统资源有余被强杀,FragmentManager也会为你保留Fragment,当重启app时,咱们能够从FragmentManager中获取这些Fragment。 剖析:Fragment之间的启动无非下图中的2种: 而这个库我并没有思考replace的状况,因为咱们的SwipeBackFragment应该是在"流式"应用的场景(FragmentA -> FragmentB ->....),而这种场景下联合下面的2、3、4条,add+show(),hide()无疑更优于replace,性能更佳、响应更快、咱们app的代码逻辑更简略。 add+hide的形式的实现从第1条,咱们能够晓得onCreateView的View就是须要放入SwipeBackLayout的子View,咱们给该子View一个背景色,而后SwipeBackLayout通明,这样在拖拽时,即可看到"上个Fragment"。 当咱们拖拽时,上个Fragment A的View是GONE状态,所以咱们要做的就是当判断拖拽产生时,Fragment A的View设置为VISIBLE状态,这样拖拽的时候,上个Fragment A就被完整的显示进去了。 外围代码: @Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(...); return attachToSwipeBack(view);}protected View attachToSwipeBack(View view) { mSwipeBackLayout.addView(view); mSwipeBackLayout.setFragment(this, view); return mSwipeBackLayout;}然而相比Activity,上个Activity的视图状态是VISIBLE的,而咱们的上个Fragment的视图状态是GONE的,所以咱们须要FragmentA.getView().setVisibility(VISIBLE),然而机会是什么时候呢? ...

December 17, 2021 · 2 min · jiezi

关于android:还不知道如何学习音视频

音视频的利用越来越宽泛,特地是挪动端的音视频利用,包含短视频、音视频直播、音视频通话等;挪动端的音视频开发需要也会十分大。作为一名挪动开发者,学习和理解音视频开发也是十分必要的。 但 Android 音视频开发这块目前没有比拟零碎的教程和书籍,这里给大家分享两份音视频材料《Android音视频开发进阶指南》《音视频精编源码解析》,置信能够给大家在音视频的学习上提供一些帮忙。 音视频开发学习路线图 Android音视频开发进阶指南《Android音视频开发进阶指南》分为五个大章节:Android音视频硬解码篇、应用OpenGL渲染视频画面篇、Android FFmpeg音视频解码篇、直播零碎聊天技术、直播零碎聊天技术、阿里IM技术分享。最初两个章节分享了包含阿里电商,微信,百度等技术实际。一、Android音视频硬解码篇音视频基础知识音视频硬解码流程:封装根底解码框架音视频播放:音视频同步音视频解封和封装:生成一个MP4二、应用OpenGL渲染视频画面篇初步理解OpenGL ES应用OpenGL渲染视频画面OpenGL渲染多视频,实现画中画深刻理解OpenGL之EGLOpenGL FBO数据缓冲区Android音视频硬编码:生成一个MP4三、Android FFmpeg音视频解码篇FFmpeg so库编译Android 引入FFmpegAndroid FFmpeg视频解码播放Android FFmpeg+OpenSL ES音频解码播放Android FFmpeg+OpenGL ES播放视频FFmpeg简略合成MP4:视屏解封与从新封装Android FFmpeg 视频编码四、直播零碎聊天技术百万在线的美拍直播弹幕零碎的实时推送技术实际之路阿里电商IM音讯平台,在群聊、直播场景下的技术实际微信直播聊天室单房间1500万在线的音讯架构演进之路百度直播的海量用户实时音讯零碎架构演进实际微信小游戏直播在Android端的跨过程渲染推流实际五、阿里IM技术分享企业级IM王者——钉钉在后端架构上的过人之处闲鱼IM基于Flutter的挪动端跨端革新实际闲鱼亿级IM音讯零碎的架构演进之路闲鱼亿级IM音讯零碎的牢靠投递优化实际音视频精编源码解析《音视频精编源码解析》,内容分为7个章节,涵盖 WebRTC Native 源码导读、X264 源码解读、FFmpeg、ijkplayer 源码剖析系列、jsmpeg 源码解析、Live555 源码解析、Opus 源码解析,一共 675 页。第一章 WebRTC Native 源码导读第一节-安卓相机采集实现剖析第二节-安卓预览实现剖析第三节-安卓视频硬编码实现剖析第四节-VideoCRE 与内存抖动优化第五节-安卓 P2P 连贯过程和 DataChannel 应用第六节-视频数据 native 层之旅第七节-混音第八节-P2P 连贯过程齐全解析第九节-API 概览第十节-RTP H.264 封包与解包 第二章 X264源码解读第一节-概述第二节-x264命令行工具第三节-编码器骨干局部-2第四节-x264_slice_write()第五节-滤波(Filter)局部第六节-宏块剖析(Analysis)局部-帧内宏块(Intra) 第三章 FFmpeg第一节-FFmpeg 编译和集成第二节-FFmpeg + ANativeWindow 实现视频解码播放第三节-FFmpeg + OpenSLES 实现音频解码播放第四节-FFmpeg + OpenGLES 实现音频可视化播放第五节-FFmpeg + OpenGLES 实现视频解码播放和视频滤镜第六节-FFmpeg 播放器实现音视频同步的三种形式第七节-FFmpeg + OpenGLES 实现 3D 全景播放器第八节-FFmpeg 播放器视频渲染优化第九节-FFmpeg、x264以及fdk-aac 编译整合第十节-FFmpeg 视频录制 - 视频增加滤镜和编码第十一节-FFmpeg + Android AudioRecorder 音频录制编码第十二节-Android FFmpeg 实现带滤镜的微信小视频录制性能 ...

December 16, 2021 · 1 min · jiezi

关于android:Android入门教程-MediaCodec-编解码使用方式

Android MediaCodec 编解码应用形式应用 MediaCodec 进行编解码。输出 H.264 格局的数据,输入帧数据并发送给监听器。 接下来咱们简称 MediaCodec 为 codec H.264的配置创立并配置 codec。配置 codec 时,若手动创立 MediaFormat 对象的话,肯定要记得设置 "csd-0" 和 "csd-1" 这两个参数。 "csd-0" 和 "csd-1" 这两个参数肯定要和接管到的帧对应上。 输出数据给 codec 输出数据时,如果对输出数据进行排队,须要查看排队队列的状况。 例如一帧数据暂用 1M 内存,1秒30帧,排队队列有可能会暂用30M的内存。当内存暂用过高,咱们须要采取肯定的措施来减小内存占用。 codec 硬解码时会受到手机硬件的影响。若手机性能不佳,编解码的速度有可能慢于原始数据输出。不得已的状况咱们能够将排队中的旧数据摈弃,输出新数据。 解码器性能对视频实时性要求高的场景,codec 没有可用的输出缓冲区,mCodec.dequeueInputBuffer 返回 -1。 为了实时性,这里会强制开释掉输入输出缓冲区 mCodec.flush()。 问题与异样问题1 - MediaCodec输出数据和输入数据数量之间有没有特定的关系 对于 MediaCodec,输出数据和输入数据数量之间有没有特定的关系?假如输出10 帧的数据,能够失去多少次输入? 实测发现,不能百分百保障输入输出次数是相等的。例如 vivo x6 plus,输出30 帧,能失去 28 帧后果。或者 300 次输出,失去 298 次输入。 异样1 - dequeueInputBuffer(0) 始终返回 -1 某些手机长时间编解码后,可能会呈现尝试获取 codec 输出缓冲区时下标始终返回 -1。 例如 vivo x6 plus,运行约 20 分钟后,mCodec.dequeueInputBuffer(0) 始终返回 -1。 ...

December 16, 2021 · 6 min · jiezi

关于android:在线教育报告上线助力职业与成人教育行业高效运营

继MMO游戏、RPG游戏、静止衰弱行业、通用行业报告及埋点模板上线后,华为剖析服务6.1.0版本新增在线教育-职业与成人教育行业报告与埋点模板,力求贴合使用者的实在利用场景,给企业提供场景化、智能化、个性化的数据服务,帮忙产品和经营人员轻松上手自助式用户行为剖析。 次要亮点包含: 新增教育行业报告与埋点模板:残缺、全面的指标体系,配套的埋点代码样例,帮您洞察用户规模变动、付费转化、学习与考试、流动经营等状况,数据驱动用户体验晋升。 反对转化事件回传HUAWEI Ads:您可通过将“用户首次启动、用户登录、利用内领取”等转化事件回传HUAWEI Ads,无效掂量广告成果,并进行深层优化。 1.职业教育行业报告上线,欠缺、成熟的指标体系开箱即用互联网经济时代,信息量、常识量的更迭速度放慢,对于职场人技能的要求也越来越高、越来越多样化,加之疫情的催化,推动了在线职业教育市场的凋敝,迎来了一波新的用户增量。但如何抓住这来之不易的机会,将这些用户短暂的留在APP内,一直晋升其粘性、用户价值,对企业来说是个不小的考验。职场人自身的工夫较为碎片化,在线教育平台如果能依据用户爱好为其精准举荐适宜的课程,并辅以肯定的优惠力度,一站式解决用户的自我晋升需要,就能更容易的留住用户。 基于对在线职业教育行业的深刻调研、对标杆企业实操办法论证的提炼,华为剖析6.1.0版本上线了在线教育行业报告,并提供了配套的埋点体系,旨在帮忙企业全面洞察用户行为的同时,最大水平节俭埋点工作量,晋升数据采集与剖析、利用的效率。 1.1报告内容概览报告分为四个板块:数据概览、付费转化、学习与考试、流动经营,帮您全面理解用户规模变动、拜访时长散布、新增会员渠道散布、人均付费金额、完课率、热门课程、热门付费课程、课程销售额、用户付费情、首购付费转化周期散布、到期会员散布、会员购买门路、领取完成率等。 该报告能够帮忙您建设残缺的在线职业教育指标体系,大大降低数据分析的应用门槛,助力企业实现全员自助式多维数据分析,对症下药做增长。 *数据概览——华为剖析报告示意 *付费转化——华为剖析报告示意图 *学习与考试——华为剖析报告示意图 *流动经营——华为剖析报告示意图 ### 1.2 开启智能埋点 在“智能数据接入-埋点开发”菜单下,您能够抉择“教育-职业与成人”模板,预置了4个场景的埋点模板及代码样例——“数据概览、付费转化、学习与考试、流动经营”,开箱即用。依照模板提供的事件及参数进行埋点后,即可查看上述职业与成人报告数据。 *职业与成人埋点模板示意 反对代码埋点与可视化埋点,其中代码埋点提供了复制代码埋点、表格埋点、工具埋点三种形式,可视化埋点须要您集成DTM Kit,以将App或Web界面同步至DTM控制台,通过可视化圈选的形式增加埋点事件与参数。 *埋点开发示意 当实现了选定模板的埋点开发后,可通过埋点验证性能疾速验证已埋点事件与参数是否正确,及时发现埋点脱漏及异常情况,进步埋点开发的准确度,升高业务危险。 *埋点验证性能示意 埋点实现后,您可通过埋点治理菜单理解埋点验证事件数、注册事件数详情,埋点事件配额占比和参数占比等,及时理解埋点进度、埋点构造,做到一站式埋点闭环治理。 *埋点治理性能示意 2.转化事件回传HUAWEI Ads,深度优化广告成果广告投放是企业拉新的次要形式,联合华为剖析和HUAWEI Ads,您能够依据业务需要设置有价值的“转化事件”,来跟踪广告带来的用户中产生转化事件的比例,以此掂量广告成果。 通过华为剖析,将转化事件(如“首次启动、用户登录、用户注册、利用内购买”等)回传HUAWEI Ads后,可对广告成果进行深层次的优化,更精准的圈选指标人群,确保广告投放的用户是对产品感兴趣且有价值的用户,晋升ROI。 比方,您发现某些广告工作的曝光数/点击数高,而新增启动数低,阐明该广告的成果差强人意,应该立刻暂停,尝试调整广告素材或关键词,来吸引更精准的受众群体。 欢送拜访华为剖析服务官网,收费体验Demo:华为剖析 | 一站式用户行为剖析平台 | Demo体验 。 获取开发领导文档:Android、iOS、Web、快利用 更多精彩内容,请见华为开发者官方论坛→https://developer.huawei.com/...

December 16, 2021 · 1 min · jiezi

关于android:高级Android插件化最全开源项目看这一篇就够了

前言插件化技术倒退到当初其实曾经很成熟了,然而相应的问题,如果没有真正地去实际过,基本不理解其中有多少问题,会牵涉到多少技术细节,多少被外人膜拜的表面光鲜的技术大牛都被『插件化』这三个字折磨地死去活来,这对于 Android 整个生态的侵害也让人无奈漠视。 那么这个组件化是什么意思呢?我说下我本人的了解,可能不对,还请指教: 通过 gradle 配置的形式,将打 debug 包和 release 包离开。这样会有一个益处,开发一个模块,在 debug 的时候,能够打成一个 apk ,独立运行测试,能够齐全独立于整个宿主 APP 的其余所有组件;待到要打 release 包的时候,再把这个模块作为一个 library ,打成 aar ,作为整个宿主 APP 的一部分。而 debug 和 release 的切换都是通过 gradle 配置,能够做到无缝切换。至于模块之间的跳转,能够用别名的形式,而不是用 Activity 和 Fragment 类名。这样所有的模块和宿主 APP 都是齐全解耦的,彻底解决了并行开发的可能造成的穿插依赖等问题。依照这个思路,咱们再来看看一些其余的细节: 在 Android 里有一个比拟爽的一点是,作为 library 的时候,aar 里的援用依赖,在宿主 Application 里也有同样的援用依赖,并不会打包两份到宿主 Application 里;模块之间的跳转,除了应用别名的形式,我能想到的还有另外一种形式,同样是通过 gradle 脚本,将跳转用到的类打成一个 jar ,作为一个 API 服务提供给其余模块作为编译期依赖(provided)引入;各个 library 在 debug 的时候作为 apk ,要独立打包运行测试,这时就须要有一个启动 Activity ,而 library 是不须要的,我的想法是搁置两个 AndroidManifest.xml ,应用 sourceSets 别离在 debug 和 release 的时候加载不同的 AndroidManifest.xml。对于Android开发者而言,插件化技术曾经是进阶Android高级工程师的必备技能之一。我这里有一份【高级Android插件化强化实战】材料,心愿能帮到大家! ...

December 16, 2021 · 1 min · jiezi

关于android:存量时代用户增长怎么做唤醒和召回很关键

用户增长的疲软态势让企业的经营重心缓缓由公域转向私域,存量的精细化经营帮忙他们在流量见顶的当下开掘了更多增长契机。昂扬的流量老本让拉新举步维艰,缄默和散失预警用户的持续性召回与唤醒势在必行。 在用户生命周期模型中,缄默期介于成熟期和散失期之间,一直地通过经营伎俩触达并放弃这部分用户沉闷,是决定产品是否放弃高留存的要害阶段。精准的用户标签联合多模式、多样化的促活伎俩,可帮忙咱们建设更加牢固的客户关系,从而留住用户。 策略制订以行为量化为根据缄默和濒临散失边缘的用户,他们的相干属性特色和后期产品应用行为不仅是咱们划分用户生命周期阶段的根据,同时,通过进一步下钻剖析,更能够为咱们制订迷信的针对性召回唤醒策略提供参考。 某电商平台,依靠于预测服务能力,将高概率散失人群提前圈定。在深度洞察剖析该局部人群特色的时候,他们发现:相比于长期缄默用户,这部分人群在近一周仍有低频会话次数,阐明近期他们仍然有购买需要,但以后库存、竞品价格优势等因素可能会造成他们的购买散失。 针对这部分人群以及他们的行为量化剖析论断,经营人员打算给他们推送相干优惠音讯达到刺激回流并产生付费行为的目标。 智能经营晋升转化通过智能经营画布,创立一个自动化经营流动,将预测的高概率散失人群作为本次流动的指标受众。 为了使优惠活动的推送音讯更具针对性,依据用户近期的消费行为数据,他们做了进一步的条件分流个性化编排。对近30天付费金额等级高的重点用户,推送“品质专场上新”,残余其余用户依据其近期的应用次数和时长做进一步分流: 例如,对于”近30天均匀日应用次数<1”的用户,他们已属于散失高危人群,面临随时散失危险,急需通过“无门槛优惠券”、“特价商品”这类的大额促销流动音讯来及时召回和唤醒;而对于”近30天沉闷天数>15”这类用户,应用频率尚可,可通过“满减券”这样的小额促销来放弃沉闷。 除依据高概率散失用户的登录频次、生产金额等指标个性化分流经营外,近期浏览品类商品的上新、举荐、库存告急等不同内容,也是经营在设计召回文案时思考的方向。除了通过Push的触达形式,对未点击音讯的其余高概率散失用户,该电商平台还通过短信模式做了进一步补充触达,使针对性的促活音讯尽可能笼罩到所有指标人群。 在大数据精准人群圈选的根底上,联合智能经营平台,共性多样的人群分流和多渠道的用户触达形式,帮忙该电商平台在存量时代仍旧放弃着用户快速增长。 欲了解更多智能经营服务能力,请参阅: 智能经营介绍 更多精彩内容,请见华为开发者官方论坛→https://developer.huawei.com/...

December 16, 2021 · 1 min · jiezi

关于android:Android-官方架构组件一Lifecycle

什么是Lifecycle?Lifecycle 组件指的是 android.arch.lifecycle 包下提供的各种类与接口,能够让开发者构建能感知其余组件(次要指Activity 、Fragment)生命周期(lifecycle-aware)的类。 为什么要引进Lifecycle?后面说了,Lifecycle可能让开发者构建能感知其余组件(次要指Activity 、Fragment)生命周期(lifecycle-aware)的类。划重点,让开发者构建能感知其余组件(次要指Activity 、Fragment)生命周期(lifecycle-aware)的类。在android开发的过程中,咱们经常须要让一些操作可能感知Activity/Fragment的生命周期,从而实现在活动状态下容许操作,而在销毁状态下须要主动禁止操作,开释资源,避免内存泄露。例如赫赫有名的图片加载框架Glide在Acticiy/Fragment处于前台的时候加载图片,而在不可见的状态下进行图片的加载,又例如咱们心愿RxJava的Disposable可能在Activity/Fragment销毁是主动dispose。Lifecycle的呈现,让开发者们可能轻易地实现上述的性能。 一个用Lifecycle革新的MVP例子比方咱们当初须要实现这样一个性能:监听某个 Activity 生命周期的变动,在生命周期扭转的时候打印日志。 个别做法结构回调的形式先定义根底IPresent接口: public interface IPresent { void onCreate(); void onStart(); void onResume(); void onPause(); void onStop(); void onDestory();}而后在自定义的Present中继承IPresent接口: public class MyPresent implements IPresent { private String TAG = "tag"; @Override public void onCreate() { LogUtil.i(TAG, "onCreate"); } @Override public void onStart() { LogUtil.i(TAG, "onStart"); } @Override public void onResume() { LogUtil.i(TAG, "onResume"); } @Override public void onPause() { LogUtil.i(TAG, "onPause"); } @Override public void onStop() { LogUtil.i(TAG, "onStop"); } @Override public void onDestory() { LogUtil.i(TAG, "onDestory"); }最初在Activity顺次调用回调办法散发事件: ...

December 16, 2021 · 11 min · jiezi

关于android:我们距离真正的互联互通还有多远

喜大普奔,互联互通政策终于有了停顿,11月29日晚,微信发表履行凋谢了电商类内部链接间接拜访的性能。当初在微信内,终于能够间接关上淘宝外链了! 此前,咱们曾预测在微信放开淘宝链接后,在微信里iOS端大概率能够间接关上淘宝App。但令人悲观的是,只管微信用户目前能够在聊天群里关上淘宝的商品链接,然而仅能在微信内的h5页面下单,想要通过微信唤起淘宝App下单,只能点击链接通过右上角浏览器中,间接关上淘宝。在Android端的用户体验不佳难能可贵,但在IOS端也遇到此类问题着实让人感到困惑。 Android端唤起App个别采取URL Scheme形式,但微信设定的门槛极高,只定向凋谢了多数的App,如:京东、拼多多。iOS唤端个别采取Universal link形式,此形式微信始终反对。所以,在失常状况下,大部分的App在iOS端的微信内是能够间接唤起App的。 但,目前在iOS端的微信内依然无奈唤起淘宝App! 据悉,淘宝App曾经适配Universal link的唤起形式,但在这段时间内,却频繁被微信封闭。而相似识货、得物、拼多多、京东等其余电商App,分享体验非常敌对。分享链路通常为:App-微信小程序-微信小程序或App-微信H5-App的微信闭环分享链路。 同时,京东和拼多多的分享形式体验也较好,会以小卡片的模式出现,蕴含商品详细信息等,而淘宝的链接临时只裸奔在对话框内。 据公开音讯称:淘宝特价版此前虽频繁申请小程序,但始终未被微信官网通过。加之H5唤起App链路被微信封闭,因而淘系App要想在微信生态内打造欠缺体验良好的分享裂变链路还须要很长的路要走,但对于很多开发者来说,互联互通下的新业务场景,能够借助技术工具实现裂变式的增长,通过小程序+APP+H5减速全平台端矩阵联动经营。微信凋谢淘宝外链是一个很重要的里程碑,但对于平台之间的互联互通仍任重道远。 对于这个问题你怎么看?欢送在评论区留言哦。 点击上面链接退出友盟+ 技术社群 与超过1000+挪动开发者独特探讨挪动开发最新动静 点击退出友盟+技术群 欢送点击【友盟+】,理解友盟+ 最新挪动技术 欢送关注【友盟全域数据】公众号

December 16, 2021 · 1 min · jiezi

关于android:如何改善应用启动性能-Facebook-应用的经验分享

作者 / Google 和 Facebook 团队撰稿 / Google Android 团队的 Kateryna Semenova 和 Facebook 团队的 Tim Trueman、Steven Harris、Subramanian Ramaswamy 简介缩短利用的启动工夫并非小事,咱们必须深刻理解其影响因素。往年,Google Android 团队和 Facebook 利用团队始终在单干钻研这方面的量化指标,并共享优化办法,以改善利用启动状况。Google Android 的公开文档中蕴含了很多对于 利用启动优化 的信息。这里咱们想进一步分享其在 Facebook 利用中的实际状况,以及哪些因素有助于改善利用启动性能。 当初,每个月有超过 29 亿人应用 Facebook。Facebook 帮忙人们构建社区,并让世界更严密地分割在一起。用户会在这里分享生存的霎时,理解和探讨正在产生的事件,建设和造就人际关系,独特单干以发明支出机会。 Facebook 利用开发者则致力于确保用户享受最佳体验,并让利用在任意设施、任何国家/地区和不同网络条件下都能流畅运行。Google Android 团队和 Facebook 团队精诚合作,在利用启动工夫的指标定义和最佳实际上达成共识,并在这里分享给大家。 从哪里开始首先天然是测量利用的启动工夫。您可借此获悉用户启动体验的衰弱水平,追踪启动工夫好转的状况,并计算进行改良须要投入的资源量。归根结底,您的启动工夫须要与用户满意度、参与度或用户增长相关联,以确定投入的优先秩序。 Android 定义了两个掂量利用启动工夫的指标: 齐全显示所用工夫 (TTFD) 和 初步显示所用工夫(TTID)。尽管您能够进一步将其划分为冷/暖启动工夫,但本文不会解释它们之间的区别,而 Facebook 的办法是,掂量和优化与利用交互的所有用户所经验的启动工夫 (有些是冷启动,有些是暖启动)。 齐全显示所用工夫 (Time-To-Full-Display, TTFD) TTFD 会记录您的利用实现渲染并可供用户交互和应用时所需的工夫,可能包含显示本地存储或来自网络上的内容所需的工夫。如果网络较慢,这可能会破费一段时间,并会视用户的应用设施而有所差别。因而,咱们有必要立刻展现一些内容,让用户看到利用启动的过程,而这就要提到 TTID 了…… 初步显示所用工夫 (Time-To-Initial-Display, TTID) TTID 会记录您的利用显示背景、导航、可疾速加载的本地内容、加载较慢的本地或网络内容的占位块所须要的工夫。TTID 应该是用户能够到处导航并返回其指标的所需工夫。 不要扭转太多: 有一件事须要留神,就是在 TTID 和 TTFD 之间利用内容的视觉变动问题,例如在页面里先展现的是已缓存的内容,而后在网络内容加载实现后忽然切换页面内容。这种忽然的变动可能会让用户感到不快和丧气,所以请确保您的利用可在 TTID 期间显示足够有意义的内容,尽可能地向用户展现其将在 TTFD 期间看到的内容。达成用户指标用户拜访您的利用是为了获取内容,这可能须要一段时间实现加载,而您心愿利用能够尽快把这些内容出现给他们。 ...

December 16, 2021 · 2 min · jiezi

关于android:OkHttp源码走心解析很细-很长

前言本文是对OkHttp开源库的一个具体解析,如果你感觉本人不够理解OkHttp,想进一步学习一下,置信本文对你会有所帮忙。 本文蕴含了具体的申请流程剖析、各大拦截器解读以及本人的一点反思总结,文章很长,欢送大家一起交换探讨。 应用办法应用办法非常简略,别离创立一个OkHttpClient对象,一个Request对象,而后利用他们创立一个Call对象,最初调用同步申请execute()办法或者异步申请enqueue()办法来拿到Response。 private final OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url("https://github.com/") .build(); //同步申请 Response response = client.newCall(request).execute(); //todo handle response //异步申请 client.newCall(request).enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { //todo handle request failed } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { //todo handle Response } });根本对象介绍正如应用办法中所述,咱们先后构建了 OkHttpClient对象、Request对象、Call对象,那这些对象都是什么意思,有什么作用呢?这个就须要咱们进一步学习理解了。 OkHttpClient一个申请的配置类,采纳了建造者模式,不便用户配置一些申请参数,如配置callTimeout,cookie,interceptor等等。 open class OkHttpClient internal constructor( builder: Builder) : Cloneable, Call.Factory, WebSocket.Factory { constructor() : this(Builder()) class Builder constructor() { //调度器 internal var dispatcher: Dispatcher = Dispatcher() //连接池 internal var connectionPool: ConnectionPool = ConnectionPool() //整体流程拦截器 internal val interceptors: MutableList<Interceptor> = mutableListOf() //网络流程拦截器 internal val networkInterceptors: MutableList<Interceptor> = mutableListOf() //流程监听器 internal var eventListenerFactory: EventListener.Factory = EventListener.NONE.asFactory() //连贯失败时是否重连 internal var retryOnConnectionFailure = true //服务器认证设置 internal var authenticator: Authenticator = Authenticator.NONE //是否重定向 internal var followRedirects = true //是否从HTTP重定向到HTTPS internal var followSslRedirects = true //cookie设置 internal var cookieJar: CookieJar = CookieJar.NO_COOKIES //缓存设置 internal var cache: Cache? = null //DNS设置 internal var dns: Dns = Dns.SYSTEM //代理设置 internal var proxy: Proxy? = null //代理选择器设置 internal var proxySelector: ProxySelector? = null //代理服务器认证设置 internal var proxyAuthenticator: Authenticator = Authenticator.NONE //socket配置 internal var socketFactory: SocketFactory = SocketFactory.getDefault() //https socket配置 internal var sslSocketFactoryOrNull: SSLSocketFactory? = null internal var x509TrustManagerOrNull: X509TrustManager? = null internal var connectionSpecs: List<ConnectionSpec> = DEFAULT_CONNECTION_SPECS //协定 internal var protocols: List<Protocol> = DEFAULT_PROTOCOLS //域名校验 internal var hostnameVerifier: HostnameVerifier = OkHostnameVerifier internal var certificatePinner: CertificatePinner = CertificatePinner.DEFAULT internal var certificateChainCleaner: CertificateChainCleaner? = null //申请超时 internal var callTimeout = 0 //连贯超时 internal var connectTimeout = 10_000 //读取超时 internal var readTimeout = 10_000 //写入超时 internal var writeTimeout = 10_000 internal var pingInterval = 0 internal var minWebSocketMessageToCompress = RealWebSocket.DEFAULT_MINIMUM_DEFLATE_SIZE internal var routeDatabase: RouteDatabase? = null ···省略代码···Request同样是申请参数的配置类,也同样采纳了建造者模式,但相比于OkHttpClient,Request就非常简略了,只有四个参数,别离是申请URL、申请办法、申请头、申请体。 ...

December 16, 2021 · 13 min · jiezi

关于android:知识点OkHttp-原理-8-连问

前言OkHttp能够说是Android开发中最常见的网络申请框架,OkHttp使用方便,扩展性强,功能强大,OKHttp源码与原理也是面试中的常客 然而OKHttp的源码内容比拟多,想要学习它的源码往往千头万绪,一时抓不住重点. 本文从几个问题登程梳理OKHttp相干知识点,以便疾速构建OKHttp常识体系,如果对你有用,欢送点赞~ 本文次要包含以下内容 OKHttp申请的整体流程是怎么的?OKHttp散发器是怎么工作的?OKHttp拦截器是如何工作的?利用拦截器和网络拦截器有什么区别?OKHttp如何复用TCP连贯?OKHttp闲暇连贯如何革除?OKHttp有哪些长处?OKHttp框架中用到了哪些设计模式?1. OKHttp申请整体流程介绍首先来看一个最简略的Http申请是如何发送的。 val okHttpClient = OkHttpClient() val request: Request = Request.Builder() .url("https://www.google.com/") .build() okHttpClient.newCall(request).enqueue(object :Callback{ override fun onFailure(call: Call, e: IOException) { } override fun onResponse(call: Call, response: Response) { } })这段代码看起来比较简单,OkHttp申请过程中起码只须要接触OkHttpClient、Request、Call、 Response,然而框架外部会进行大量的逻辑解决。 所有网络申请的逻辑大部分集中在拦截器中,然而在进入拦截器之前还须要依附散发器来调配申请工作。 对于散发器与拦截器,咱们在这里先简略介绍下,后续会有更加具体的解说 散发器:外部保护队列与线程池,实现申请调配;拦截器:五大默认拦截器实现整个申请过程。 整个网络申请过程大抵如上所示 通过建造者模式构建OKHttpClient与 RequestOKHttpClient通过newCall发动一个新的申请通过散发器保护申请队列与线程池,实现申请调配通过五大默认拦截器实现申请重试,缓存解决,建设连贯等一系列操作失去网络申请后果2. OKHttp散发器是怎么工作的?散发器的次要作用是保护申请队列与线程池,比方咱们有100个异步申请,必定不能把它们同时申请,而是应该把它们排队分个类,分为正在申请中的列表和正在期待的列表, 等申请实现后,即可从期待中的列表中取出期待的申请,从而实现所有的申请 而这里同步申请各异步申请又略有不同 同步申请 synchronized void executed(RealCall call) { runningSyncCalls.add(call);}因为同步申请不须要线程池,也不存在任何限度。所以散发器仅做一下记录。后续依照退出队列的程序同步申请即可 异步申请 synchronized void enqueue(AsyncCall call) { //申请数最大不超过64,同一Host申请不能超过5个 if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) { runningAsyncCalls.add(call); executorService().execute(call); } else { readyAsyncCalls.add(call); }}当正在执行的工作未超过最大限度64,同时同一Host的申请不超过5个,则会增加到正在执行队列,同时提交给线程池。否则先退出期待队列。 每个工作实现后,都会调用散发器的finished办法,这外面会取出期待队列中的工作继续执行 ...

December 16, 2021 · 3 min · jiezi

关于android:Kotlin-线程同步的方法

面试的时候常常会被问及多线程同步的问题,例如: “ 现有 Task1、Task2 等多个并行任务,如何期待全副工作执行实现后,开始执行 Task3 ? ”Kotlin 中有多种实现形式可供选择,本文将所有这些形式做了整顿: Thread.joinSynchronizedReentrantLockBlockingQueueCountDownLatchCyclicBarrierCASFutureCompletableFutureRxjavaCoroutineFlow咱们先定义三个Task,模仿上述场景, Task3 基于 Task1、Task2 返回的后果拼接字符串,每个 Task 通过 sleep 模仿耗时: val task1: () -> String = {    sleep(2000)    "Hello".also { println("task1 finished: $it") }}val task2: () -> String = {    sleep(2000)    "World".also { println("task2 finished: $it") }}val task3: (String, String) -> String = { p1, p2 ->    sleep(2000)    "$p1 $p2".also { println("task3 finished: $it") }}1. Thread.join()Kotlin 兼容 Java,Java 的所有线程工具默认都能够应用。其中最简略的线程同步形式就是应用 Thread 的 join() : @Testfun test_join() {    lateinit var s1: String    lateinit var s2: String    val t1 = Thread { s1 = task1() }    val t2 = Thread { s2 = task2() }    t1.start()    t2.start()    t1.join()    t2.join()        task3(s1, s2)}2. Synchronized应用 synchronized 锁进行同步  @Test    fun test_synchrnoized() {        lateinit var s1: String        lateinit var s2: String        Thread {            synchronized(Unit) {                s1 = task1()            }        }.start()        s2 = task2()        synchronized(Unit) {            task3(s1, s2)        }    }然而如果超过三个工作,应用 synchrnoized 这种写法就比拟顺当了,为了同步多个并行任务的后果须要申明n个锁,并嵌套n个 synchronized。 3. ReentrantLockReentrantLock 是 JUC 提供的线程锁,能够替换 synchronized 的应用  @Test    fun test_ReentrantLock() {        lateinit var s1: String        lateinit var s2: String        val lock = ReentrantLock()        Thread {            lock.lock()            s1 = task1()            lock.unlock()        }.start()        s2 = task2()        lock.lock()        task3(s1, s2)        lock.unlock()    }ReentrantLock 的益处是,当有多个并行任务时是不会呈现嵌套 synchrnoized 的问题,但依然须要创立多个 lock 治理不同的工作, 4. BlockingQueue阻塞队列外部也是通过 Lock 实现的,所以也能够达到同步锁的成果  @Test    fun test_blockingQueue() {        lateinit var s1: String        lateinit var s2: String        val queue = SynchronousQueue<Unit>()        Thread {            s1 = task1()            queue.put(Unit)        }.start()        s2 = task2()        queue.take()        task3(s1, s2)    }当然,阻塞队列更多是应用在生产/生产场景中的同步。 5. CountDownLatchJUC 中的锁大都基于 AQS 实现的,能够分为独享锁和共享锁。ReentrantLock 就是一种独享锁。相比之下,共享锁更适宜本场景。例如 CountDownLatch,它能够让一个线程始终处于阻塞状态,直到其余线程的执行全副实现:  @Test    fun test_countdownlatch() {        lateinit var s1: String        lateinit var s2: String        val cd = CountDownLatch(2)        Thread() {            s1 = task1()            cd.countDown()        }.start()        Thread() {            s2 = task2()            cd.countDown()        }.start()        cd.await()        task3(s1, s2)    }共享锁的益处是不用为了每个工作都创立独自的锁,即便再多并行任务写起来也很轻松 6. CyclicBarrierCyclicBarrier 是 JUC 提供的另一种共享锁机制,它能够让一组线程达到一个同步点后再一起持续运行,其中任意一个线程未达到同步点,其余已达到的线程均会被阻塞。 与 CountDownLatch 的区别在于 CountDownLatch 是一次性的,而 CyclicBarrier 能够被重置后重复使用,这也正是 Cyclic 的命名由来,能够循环应用  @Test    fun test_CyclicBarrier() {        lateinit var s1: String        lateinit var s2: String        val cb = CyclicBarrier(3)        Thread {            s1 = task1()            cb.await()        }.start()        Thread() {            s2 = task1()            cb.await()        }.start()        cb.await()        task3(s1, s2)    }7. CASAQS 外部通过自旋锁实现同步,自旋锁的实质是利用 CompareAndSwap 防止线程阻塞的开销。因而,咱们能够应用基于 CAS 的原子类计数,达到实现无锁操作的目标。   @Test    fun test_cas() {        lateinit var s1: String        lateinit var s2: String        val cas = AtomicInteger(2)        Thread {            s1 = task1()            cas.getAndDecrement()        }.start()        Thread {            s2 = task2()            cas.getAndDecrement()        }.start()        while (cas.get() != 0) {}        task3(s1, s2)    }while 循环空转看起来有些浪费资源,然而自旋锁的实质就是这样,所以 CAS 仅仅实用于一些cpu密集型的短工作同步。 volatile看到 CAS 的无锁实现,兴许很多人会想到 volatile, 是否也能实现无锁的线程平安?   @Test    fun test_Volatile() {        lateinit var s1: String        lateinit var s2: String        Thread {            s1 = task1()            cnt--        }.start()        Thread {            s2 = task2()            cnt--        }.start()        while (cnt != 0) {        }        task3(s1, s2)    }留神,这种写法是谬误的volatile 能保障可见性,然而不能保障原子性,cnt-- 并非线程平安,须要加锁操作 8. Future下面无论有锁操作还是无锁操作,都须要定义两个变量s1、s2记录后果十分不不便。Java 1.5 开始,提供了 Callable 和 Future ,能够在工作执行完结时返回后果。 @Testfun test_future() {    val future1 = FutureTask(Callable(task1))    val future2 = FutureTask(Callable(task2))    Executors.newCachedThreadPool().execute(future1)    Executors.newCachedThreadPool().execute(future2)    task3(future1.get(), future2.get())}通过 future.get(),能够同步期待后果返回,写起来十分不便 9. CompletableFuturefuture.get() 尽管不便,然而会阻塞线程。Java 8 中引入了 CompletableFuture  ,他实现了 Future 接口的同时实现了 CompletionStage 接口。CompletableFuture 能够针对多个 CompletionStage 进行逻辑组合、实现简单的异步编程。这些逻辑组合的办法以回调的模式防止了线程阻塞: ...

December 16, 2021 · 1 min · jiezi

关于android:终于来了Android端个人中心页面滑动冲突优化方案

背景抖音首页右滑可进入“集体核心”页面,对于首页日活上亿的 APP 来说,这个页面的pv实践上应该不会太小。然而某些时候在此页面会呈现滑动抵触的小问题,不太利于用户体验,通过重复的把玩测试,找到了必现的操作,作为一个资深的抖迷和一个非资深的 Android 开发的我,产生了钻牛角尖的想法—想看看问题是怎么产生的,以及有没有可优化的计划。 问题景象首页右滑可进入“集体核心”页面,而后在底部的 RecylerView 上先左右滑动,然而不触发它们父布局 ViewPager 的切换,而后手指不抬起,进行高低滑动,此时 RecylerView 会接管滑动事件,导致滑动错位,如下图所示: 起因剖析问题明确了,接下来就是剖析是如何产生的了。我通过综合剖析发现,抖音用的是自定义 LinearLayout 的形式来布局 header + Viewpager + RecyclerView 的,进而通过拦挡 LinearLayout 的 disptachTouchEvent 来解决的嵌套滑动。整体的滑动流程如图所示: 当手指触摸屏幕时,记录地位,滑动后,判断是横向竖向,只判断一次如果是高低滑动,则判断是触发最外层 LinearLayout 的滑动,还是触发 RecyclerView 的本身滑动。触发本身的滑动就是调用本人的 scrollBy(0,dy),留神 此时的事件还是会往下传递到 RecyclerView ,然而因为绝对于 RecyclerView 本身来说滑动差值很小,视觉上可疏忽。不触发本身的滑动就会间接散发上来,此时 RecyclerView 本身来说竖向(dy)差值变动较大,失常滑动。呈现问题时,用户的手先触发左右滑动,这时候因为 RecyclerView 父布局 ViewPager 中的一些临界判断没被触发,所以没拦挡事件,事件还是到了 RecyclerView 中,此时如果再次高低滑动,因为1中的判断单次滑动周期内只触发了一次,还被认为是左右滑动事件,所以 LinearLayout 布局自身没有滚动,然而 RecyclerView 失常响应滚动,导致的呈现滑动偏差。优化计划问题剖析的差不多了,其实原本也就完结了,然而惊喜的发现原来这个自定义的滑动布局是扩大自开源库:https://github.com/cpoopc/ScrollableLayout 然而曾经长时间没人保护了。不过通过这个原始的库。能够看到外围逻辑还是统一的,通过调试编译发现,的确这个库也同样存在这个问题,那就基于此库着手试着解决一下吧。 开源库的本来代码: 依据剖析就是在图中 else 中其实又触发了高低滑动逻辑,而外层的自定义 LinearLayout 布局没有追随滑动导致的。那咱们是不是能够在外面加个判断,除去真正的左右滑动逻辑(ViewPager事件),剩下的事件就是触发 RecylcerView 滑动的了(相当于过滤了横向的,留下的竖向的),咱们再次判断外层的自定义 LinearLayout 布局是否须要联动,如果须要再次联动就好了。 站在伟人肩膀上,零碎控件的解决个别都能够借鉴,源码之下,所有清晰,横向的能够参考 ViewPager 的事件拦挡,竖向的能够参考 RecyclerView 的事件处理逻辑。剖析两个控件的 onIntercepetTouchEvent() , 拿到其外围的判断是否响应滑动的逻辑为咱们所用。 ViewPager 相干源码: 外围拦挡逻辑: 如果横向上有可滑动的子 View ,就不拦挡,让子 View 去解决横向的滑动超过临界值 mTouchSlop ,并且大于竖向滑动间隔的2倍,进行拦挡咱们须要把相干的判断代码都 copy 过去,而后退出到咱们自定义 LinearLayout 中 ...

December 16, 2021 · 1 min · jiezi

关于android:一本毕业的打工人大厂安卓开发2年被裁重新出发终于拿下腾讯offer

前言自我介绍下,自己就是个屌丝程序猿,大学很一般名字就不说了,软件工程业余。大学毕业后去了一家大公司面试,胜利的拿到了Offer。说实话,拿到Offer的那一刻,我的心田是十分开心冲动的,入职后也十分顺利,就是因为太顺利,导致我始终很劳碌,也对将来没有什么思考。 起初的起初,因为我始终以来的劳碌,本身的技术也始终是那样,公司的倒退须要更高技术的人才。很显然,我曾经适应不了公司的倒退,最终,我被解雇了。 被解雇后,我心田深受打击,对这座城市也心灰意冷。一番考虑过后我决定买高铁票回老家。回到老家后,我看着这座相熟的城市,情绪舒缓了许多。在老家待了几天,我感觉不能再这么颓丧上来了。然而近年来的劳碌工作状态,让我的技术没有一点出息,我自知这个状态上来想要进到互联网头部公司定是不事实的,毕竟学历不能代表全副,技术才是最重要的。我决定从新登程,晋升本人的技术。 自己目前曾经在腾讯入职了,过程十分艰苦,我深知这来之不易的胜利是我始终以来致力付出失去的。 上面是我面试中的一些流程和面试的问题,给小伙伴们一些教训,心愿能帮忙到你们。 面试流程腾讯一面(全程大概1h左右)自我介绍TCP与UDP的区别TCP三次握手说一下(把流程说一遍,这里认为会持续问为什么不是两次或者四次,后果没有)看你我的项目用到线程池,说一下线程池工作原理,工作拒接策略有哪几种过程和线程的区别ArrayList与LinkedList的区别线程平安与非线程平安汇合说一下,底层怎么实现的(hashmap,concurrenthashmap)数据库事务隔离级别说一下synchronized和lock区别,可重入锁与非可重入锁的区别说说乐观锁和乐观锁的区别手写进制转换算法,求出一个数的二进制数1的个数JAVA根底 equals多线程形式、threadlocal,各种锁,synchronized和lock设计模式、spring类加载形式、实例保留在哪、aop ioc、反射机制类加载器,双亲委派模型,热部署jvm内存模型,内存构造、堆的分代算法、堆的分区、gc算法、gc过程tcp ip 七层模型 rest接口标准 get和post区别,长度,平安tcp ip的arp协定,两个同一网络的主机如何取得对方的mac地址负载平衡、高并发、高可用的架构mysql的引擎区别redis缓存,redis的集群部署,热备份,主从备份,主从数据库,hash映射找到晓得指定节点理解云计算么,理解云容器docker么,容器和虚拟机的区别(面试官问了很多根底的问题,有些答复的并不是很流畅,不晓得还有没有心愿。) 二面是在星期四的一个下午,间隔一面过来大概有一个星期了吧。工夫都有那么久了,我认为一面可能凉了,后果就收到了面试的邀约。腾讯二面(大概45min)说一下你对哪个我的项目比拟相熟、为什么做这个我的项目我的项目采纳了什么架构,数据库如何设计的数据库由哪些表,为什么有这些表次要有哪些外围模块,模块之间如何通信的如何保留会话状态,有哪些形式、区别如何分布式session如何治理,你有哪些计划学过数据结构和算法吗(当然),你说说二分搜寻的过程说一下快排的过程,写一下伪代码理解哪设计模式,举例说说在jdk源码哪些用到了你说的设计模式(二面大部分问的都是我的项目技术上的。感觉我答复的并不是特地好,所以感觉没什么心愿了。) 就在我筹备从新投简历的时候,他们给我打电话了,让我约个工夫视频面试,而后就开始了第三轮面试。腾讯三面(视频面,全程大略1h左右)说下你平时看的一些技术博客,书籍linux 下的一些指令工作中你感觉最不爽的事件是什么说下你的优缺点有没有想过来守业公司写个 strcpy 函数说说你本人的性情给你一个零碎,后盾的逻辑曾经实现了,然而前端加载很慢,怎么检测当前可能要学习很多新技术,你怎么看我的项目中遇到的艰难(提前想好,并且把实现或者优化办法说分明)零碎的量级、pv、uv 等应答高并发的解决办法(分布式)在我的项目中次要负责了哪些工作nginx 的负载平衡分布式缓存的一致性,服务器如何扩容(哈希环)(第三轮面试整体感觉还行,没有什么特地大的压力) HR面(大概30min)平时怎么学习的兴趣爱好感觉本人后面几轮面试怎么样除了Java还钻研过其它什么技术(我说AI,区块链)跟我介绍一下区块链~怎么对待国内区块链的倒退跟我说一下你认为最具备挑战性的我的项目我做了哪些?最终顺利拿到offer的?1.跟着视频学,从新开始 2.坚固常识,增强本人的专业技能 3.刷面试题,相熟面试流程 面试倡议1.有急躁且被动 面试不要焦急着去问后果,个别在hr面的时候,她的态度多少可能猜个七七八八的,如果等上一周还没有告诉,那就能够被动去问了。 2.刷题是为了晋升本人的运气 运气在面试过程中是十分重要的,刷题的目标很简略,除了坚固咱们所把握的,另一个就是为了能进步在面试中咱们的运气,如果可能问到一样的题是再好不过了,当然这个方法是实用于职级中低岗位。 3.把握根底,留神深度 腾讯面试最喜爱问两类问题,一类是根底,另一类就是深度。根底局部,无非就是咱们所把握的技术根底内容,基本上只有是有筹备的都没有太大的问题。另一部分就是深度问题,大多波及到本人之前的工作、我的项目,面试官所问的问题不仅仅是停留在外表那么简略,背地的原理是什么才是面试官想要问的。 想要视频和大厂面试题的敌人能够点这里支付哦最初其实Android开发的知识点就那么多,面试问来问去还是那么点货色。所以面试没有其余的窍门,只看你对这些知识点筹备的充沛水平。so,进来面试时先看看本人温习到了哪个阶段就好。 对于程序员来说,要学习的常识内容、技术有太多太多,要想不被环境淘汰就只有一直晋升本人,素来都是咱们去适应环境,而不是环境来适应咱们! 认真温习,认真对待面试,准备充分,一直总结。切实不会你就背,虽说有些特地根底的知识点在理论开发中用不到,但面试就是面试,面试就是问这些,连根底的问题都答复不好,切实很难让你通过。

December 16, 2021 · 1 min · jiezi

关于android:Python打包setuptools

setuptoolsPython打包散发工具setuptools:已经 Python 的散发工具是 distutils,但它无奈定义包之间的依赖关系。setuptools 则是它的增强版,能帮忙咱们更好的创立和散发 Python 包,尤其是具备简单依赖关系的包。其通过增加一个根本的依赖零碎以及许多相干性能,补救了该缺点。他还提供了主动包查问程序,用来主动获取包之间的依赖关系,并实现这些包的装置,大大降低了装置各种包的难度,使之更加不便,将程序打包当前能够能够装置到本人的虚拟环境中,也能够上传到PyPI,这样十分不便大我的项目开发 setuptools应用pip 装置: $ pip install setuptools第一个安装文件 在目录 learn\_setup 下新建安装文件 setup.py,而后创立包 myapp 模仿要打包源码包: ├── myapp│ └── __init__.py└── setup.pysetup.py 文件内容如下: from setuptools import setupsetup( name='firstApp001', # 利用名 version='0.0.1', # 版本号 packages=['myapp'], # 包含在安装包内的 Python 包)应用安装文件创立 wheel 有了下面的 setup.py 文件,咱们就能够打出各种安装包,次要分为两类:sdist 和 bdist。 Source distribution 应用 sdist 能够打包成 source distribution,反对的压缩格局有: 应用形式为: $ python setup.py sdist --formats=gztar,zip目录下便会多出 dist 和 *.egg-info 目录,dist 内保留了咱们打好的包,下面命令应用 --formats 指定了打出 .tar.gz 和 .zip 包,如果不指定则如上表依据具体平台默认格局打包。 包的名称为 setup.py 中定义的 name, version以及指定的包格局,格局如:firstApp01-0.0.1.tar.gz。 ...

December 16, 2021 · 4 min · jiezi

关于android:nextTick的理解和作用

场景阐明最近应用Vue全家桶做后盾零碎的时候,遇到了一个很奇葩的问题:有一个输入框只容许输出数字,当输出其它类型的数据时,输出的内容会被重置为null。为了实现这一性能,应用了一个父组件和子组件。为了不便陈说,这里将业务场景简化,具体代码如下: // 父组件<template> <Input v-model="form.a" @on-change="onChange"></Input></template><script type="javascript">export default { data() { return { form: { a: null } } }, methods: { async onChange(value) { if (typeof value !== 'number') { // await this.$nextTick() this.form.a = null } } }}</script>// 子组件<template> <input v-model="currentValue" @input="onInput" /></template><script type="javascript">export default { name: 'Input', props: { value: { type: [Number, Null], default: null } }, data() { return { currentValue: null } }, methods: { onInput(event) { const value = event.target.value this.$emit('input', value) const oldValue = this.value if (oldValue === value) return this.$emit('on-change', value) } }, watch: { value(value, oldValue) { this.currentValue = value } }}</script>将以上代码放到我的项目中去运行,你会很神奇地发现,在输入框输出字符串'abc'之后,输入框的值并没有被重置为空,而是放弃为'abc'没有变动。在将正文的nextTick勾销正文当前,输入框的值被重置为空。真的十分神奇。 ...

December 16, 2021 · 9 min · jiezi

关于android:coroutineflowRetrofit的接口调用

初始化Retrofit,Okhttpabstract class BaseRetrofitClient { companion object { private const val TIME_OUT = 5 const val BASE_URL = "https://www.wanandroid.com" } private val client: OkHttpClient get() { val builder = OkHttpClient.Builder() val logging = HttpLoggingInterceptor() if (BuildConfig.DEBUG) { logging.level = HttpLoggingInterceptor.Level.BODY } else { logging.level = HttpLoggingInterceptor.Level.BASIC } builder.addInterceptor(logging) .addNetworkInterceptor(ResponseInterceptor()) .connectTimeout(TIME_OUT.toLong(), TimeUnit.SECONDS) // 能够依据本人的口味自行定制 handleBuilder(builder) return builder.build() } protected abstract fun handleBuilder(builder: OkHttpClient.Builder) fun <S> getService(serviceClass: Class<S>, baseUrl: String? = null): S { return Retrofit.Builder() .client(client) .addConverterFactory(GsonConverterFactory.create())// .addCallAdapterFactory(RxJava2CallAdapterFactory.create())// .addCallAdapterFactory(CoroutineCallAdapterFactory.invoke()) .baseUrl( if (baseUrl.isNullOrBlank()) { BASE_URL } else baseUrl ) .build().create(serviceClass) }}object RetrofitClient : BaseRetrofitClient() { val userService by lazy{ getService(UserService::class.java, BASE_URL) } val wanService by lazy { getService(WanService::class.java, BASE_URL) } private val cookieJar by lazy { PersistentCookieJar(SetCookieCache(), SharedPrefsCookiePersistor(App.CONTEXT)) } override fun handleBuilder(builder: OkHttpClient.Builder) { val httpCacheDirectory = File(App.CONTEXT.cacheDir, "responses") val cacheSize = 10 * 1024 * 1024L // 10 MiB val cache = Cache(httpCacheDirectory, cacheSize) builder.cache(cache) .cookieJar(cookieJar) .addInterceptor { chain -> var request = chain.request() if (!NetWorkUtils.isNetworkAvailable(App.CONTEXT)) { request = request.newBuilder() .cacheControl(CacheControl.FORCE_CACHE) .build() } val response = chain.proceed(request) if (!NetWorkUtils.isNetworkAvailable(App.CONTEXT)) { val maxAge = 60 * 60 response.newBuilder() .removeHeader("Pragma") .header("Cache-Control", "public, max-age=$maxAge") .build() } else { val maxStale = 60 * 60 * 24 * 7 // tolerate 4-weeks stale response.newBuilder() .removeHeader("Pragma") .header("Cache-Control", "public, only-if-cached, max-stale=$maxStale") .build() } response } } val mCookieJar:PersistentCookieJar by lazy { PersistentCookieJar(SetCookieCache(), SharedPrefsCookiePersistor(App.CONTEXT)) }}新建业务registory suspend fun getArticleList(page: Int, isRefresh: Boolean) = flow<BaseViewModel.BaseUiModel<ArticleList>> { RetrofitClient.wanService.getHomeArticles(page).doSuccess { emit(BaseViewModel.BaseUiModel(showSuccess = it, showLoading = false, isRefresh = isRefresh)) } }.flowOn(Dispatchers.IO) // 切换线程 .onStart { emit(BaseViewModel.BaseUiModel(showLoading = true)) }.catch { emit(BaseViewModel.BaseUiModel(showError = it.message, showLoading = false, showEnd = false)) }新建ViewModel在HomeViewModel中实例化HomeRepository,调用getArticleList class HomeViewModel : BaseViewModel() { val repository = HomeRepository() val articleState = UnPeekLiveData<BaseUiModel<ArticleList>>() fun getArticleList(page: Int, isRefresh: Boolean) { launchOnUI { repository.getArticleList(page, isRefresh).collect { articleState.postValue(it) } } }}open class BaseViewModel : ViewModel() { fun launchOnUI(block: suspend CoroutineScope.() -> Unit) { viewModelScope.launch { block() } } suspend fun <T> launchOnIO(block: suspend CoroutineScope.() -> T) { withContext(Dispatchers.IO) { block } } open class UiState<T>( val isLoading: Boolean = false, val isRefresh: Boolean = false, val isSuccess: T? = null, val isError: String?= null ) open class BaseUiModel<T>( var showLoading: Boolean = false, var showError: String? = null, var showSuccess: T? = null, var showEnd: Boolean = false, // 加载更多 var isRefresh: Boolean = false // 刷新 ) override fun onCleared() { super.onCleared() viewModelScope.cancel() }}回到UI层,依据数据展现uiHomeFragment ...

December 16, 2021 · 3 min · jiezi

关于android:Android入门教程-Audio-音频二

应用 MediaExtractor 和 MediaMuxer 解析和封装 mp4 文件简介MP4 或称 MPEG-4第14局部是一种规范的数字多媒体容器格局。 MP4中的音频格式通常为 AAC(audio/mp4a-latm) MediaExtractor MediaExtractor 可用于拆散多媒体容器中视频 track 和音频 track setDataSource() 设置数据源,数据源能够是本地文件地址,也能够是网络地址getTrackFormat(int index) 来获取各个track的MediaFormat,通过MediaFormat来获取track的详细信息,如:MimeType、分辨率、采样频率、帧率等等selectTrack(int index) 通过下标抉择指定的通道readSampleData(ByteBuffer buffer, int offset) 获取以后编码好的数据并存在指定好偏移量的buffer中MediaMuxer MediaMuxer 可用于混合根本码流。将所有的信道的信息合成一个视频。 目前输入格局反对 MP4,Webm,3GP。从 Android Nougat 开始反对向 MP4 中混入 B-frames。 提取并输入 MP4 文件中的视频局部从一个 MP4 文件中提取出视频,失去不含音频的 MP4 文件。 实现流程,首先是应用 MediaExtractor 提取,而后应用 MediaMuxer 输入 MP4 文件。 MediaExtractor设置数据源,找到并抉择视频轨道的格局和下标MediaMuxer设置输入格局为MUXER_OUTPUT_MPEG_4,增加后面选定的格局,调用start()启动MediaExtractor读取帧数据,不停地将帧数据和相干信息传入MediaMuxer最初进行并开释MediaMuxer和MediaExtractor最好放在子线程中操作。 /** * 提取视频 * * @param sourceVideoPath 原始视频文件 * @throws Exception 出错 */ public static void extractVideo(String sourceVideoPath, String outVideoPath) throws Exception { MediaExtractor sourceMediaExtractor = new MediaExtractor(); sourceMediaExtractor.setDataSource(sourceVideoPath); int numTracks = sourceMediaExtractor.getTrackCount(); int sourceVideoTrackIndex = -1; // 原始视频文件视频轨道参数 for (int i = 0; i < numTracks; ++i) { MediaFormat format = sourceMediaExtractor.getTrackFormat(i); String mime = format.getString(MediaFormat.KEY_MIME); Log.d(TAG, "MediaFormat: " + mime); if (mime.startsWith("video/")) { sourceMediaExtractor.selectTrack(i); sourceVideoTrackIndex = i; Log.d(TAG, "selectTrack index=" + i + "; format: " + mime); break; } } MediaMuxer outputMediaMuxer = new MediaMuxer(outVideoPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4); outputMediaMuxer.addTrack(sourceMediaExtractor.getTrackFormat(sourceVideoTrackIndex)); outputMediaMuxer.start(); ByteBuffer inputBuffer = ByteBuffer.allocate(1024 * 1024 * 2); // 调配的内存要尽量大一些 MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); int sampleSize; while ((sampleSize = sourceMediaExtractor.readSampleData(inputBuffer, 0)) >= 0) { long presentationTimeUs = sourceMediaExtractor.getSampleTime(); info.offset = 0; info.size = sampleSize; info.flags = MediaCodec.BUFFER_FLAG_SYNC_FRAME; info.presentationTimeUs = presentationTimeUs; outputMediaMuxer.writeSampleData(sourceVideoTrackIndex, inputBuffer, info); sourceMediaExtractor.advance(); } outputMediaMuxer.stop(); outputMediaMuxer.release();    // 进行并开释 MediaMuxer sourceMediaExtractor.release(); sourceMediaExtractor = null;   // 开释 MediaExtractor }如果下面的 ByteBuffer 调配的空间太小,readSampleData(inputBuffer, 0) 可能会呈现 IllegalArgumentException 异样。 ...

December 15, 2021 · 4 min · jiezi

关于android:如果2021能重开我会告诉自己去做这些

<img src="https://s2.loli.net/2021/12/15/LUywOR3ExnHmvs5.jpg"/> 多年来,Android 生态系统及其开发工具产生了巨大变化。 Eason过后就是走了很多弯路,导致本人Android学习之路十分波折。这篇文章将向大家介绍如何正确地开始 Android 开发生涯,包含该学习哪些重要和不重要的常识,以及如何做能力找到第一份工作。 应该学习 Java 还是 Kotlin?谷歌在 2017 年发表官网 Kotlin 反对 Android 开发。古代 Android 应用程序和库是用 Kotlin 编写的,只管依然应用 Java,次要是出于遗留起因。这两种语言彼此十分类似,一个我的项目能够应用这两种语言。Java 比 Kotlin 更古老。这意味着对 Java 有更多的工具和反对。Kotlin 是一种古代语言,应用起来更简略。 只管 Kotlin 是官网举荐的 Android 语言,但 Google 对这两种语言都提供了杰出的反对。在行业中,大多数公司向 Android 开发人员询问 Kotlin 常识和教训,而不是 Java。因而Eason激励大家专一于学习 Kotlin。 同时,不要漠视网上的Java资源和教程,毕竟有大量的旧我的项目和github资源都是采纳用 Java 编写的。 <img src="https://s2.loli.net/2021/12/15/QfsxdkW3Fw1Rjnr.png"/> Android Studio 是 Android 开发的官网 IDE,基于 JetBrains IntelliJ IDEA。它具备的一项很酷的性能是将 Java 代码主动转换为 Kotlin。 如何学习Android开发<img src="https://s2.loli.net/2021/12/15/YXtuQFlzeSr7bI3.png"/> 只有有电脑且能上网,就能够 100% 收费学习 Android 开发。大家无需领有任何 Android 设施即可开始学习或构建应用程序。 官网 Android 开发者网站是一个很好的终点。大家将在那里找到无关如何开始学习和公布 Android 应用程序的资源。例如,Kotlin 中的 Android Basics非常适合涵盖 Android 基础知识,而且它也是 100% 收费的。 ...

December 15, 2021 · 1 min · jiezi

关于android:大厂Android启动优化出其不意的优化手段

惯例的伎俩优化后,咱们能解决根本的问题,然而咱们得持续谋求极致,本章将分享一些意想不到的伎俩。 1 首页合并通常咱们启动的时候分为闪屏和首页两个页面,咱们将闪屏和首页合并成一个,通过fragment来操作实在页面,广告设计成一个dialog fragment浮在首页就行。根本的收益在100ms左右。 首页合并后发现几个问题:首页治理、唤端启动问题。 首页无奈应用singletask,singletask的问题咱们通过手动保护一个activity栈去治理,保障一个首页。唤端启动,第三方app唤端没有加newtask标签,导致页面启动在第三方app内,这个临时没有遇到很好的解决形式,还是在推动比拟大的第三方平台去解决。 2 渲染音讯优先级队列咱们数据申请后,通过handler将音讯发送到主线程,handler音讯队列内可能比拟忙碌,咱们思考的是将数据回调和图片回调的音讯发送到音讯队列后面。MessageQueue其实提供了一个办法handler.sendMessageAtFrontOfQueue的形式。 3 dex2oatAndroid ART虚拟机后,能够将dex文件事后的翻译解决成机器码间接运行,在Android 5 - 7版本,dex解决是在app装置的时候解决的,然而因为dex2oat性能影响较大,装置的时候将耗时过长,Android 7后改为装置的时候不做翻译,运行时还是解释执行,运行时的时候记录运行的函数等信息,在手机闲置的状况上来把这些热办法做dex2oat,下次运行间接运行机器码。然而零碎判断闲置的条件比拟刻薄,导致大部分状况下app没有被dex2oat,另外互联网app疾速倒退,发版速度较快,所以dex2oat的利用率低,通过app本人手动调用零碎dex2oat达到疾速将app的dex转化,进步代码执行效率,该计划的收益大略在10%。相干的具体常识能够网上搜寻一下。 零碎记录热办法的数据文件存在 /data/misc/profiles/cur/0/packageName/primary.prof下,咱们能够通过FileObserver监听这个这个文件批改判断是否须要dex2oat。dex2oat能够通过shell命令执行cmd package compile -m speed-profile -f packageName 4 RedexLinux 文件系统从磁盘读文件的时候,会以 block 为单位去磁盘读取,个别 block 大小是 4KB。也就是说一次磁盘读写大小至多是 4KB,而后会把 4KB 数据放到页缓存 Page Cache 中。如果下次读取文件数据曾经在页缓存中,那就不会产生实在的磁盘 I/O,而是间接从页缓存中读取,大大晋升了读的速度。所以下面的例子,咱们尽管读了 1000 次,但事实上只会产生一次磁盘 I/O,其余的数据都会在页缓存中失去。 Dex 文件用的到的类和安装包 APK 外面各种资源文件个别都比拟小,然而读取十分频繁。咱们能够利用零碎这个机制将它们依照读取程序重新排列,缩小实在的磁盘 I/O 次数。 类重排 启动过程类加载程序能够通过插装动态代码块获取。 class A { static { //记录 }}而后通过 ReDex 的Interdex调整类在 Dex 中的排列程序,最初能够利用 010 Editor 查看批改后的成果。 从多方拿到的数据来看,收益在0-6%,整体不是很显著,而且须要把redex工程化、思考和proguard的兼容等问题。 5 黑科技微信Hardcoder构建了App与零碎(ROM)之间牢靠的通信框架,让零碎晓得App的需要,能够让app获取更多的系统资源。 原理 1、其实质是让App跨过Framework间接跟厂商ROM通信。2、分为Client端和Server端,Server端由厂商零碎侧自行实现。3、它们间接采纳 LocalSocket 形式,Hardcoder是 Native 实现的,应用了Linux的Socket接口实现了一套本人的LocalSocket。整体收益不是特地显著。 ...

December 15, 2021 · 1 min · jiezi

关于android:欢迎体验-Wear-OS-版-Compose-开发者预览版

作者 / 开发者关系工程师 Jeremy Walker 在往年的 Google I/O 大会 上,咱们发表将 Jetpack Compose 的优良个性引入 Wear OS。在顺利公布多个 alpha 版本之后,Wear OS 版 Compose 现已推出开发者预览版。 Compose 能 简化并减速 UI 开发,Wear OS 版 Compose 也是如此,借助内置的 Material You 反对,您能够用更少的代码构建更精美的利用。 除此之外,您在应用 Jetpack Compose 构建挪动利用的教训,也能够间接使用在 Wear OS 版本上。就像在挪动设施上一样,欢迎您立刻着手测试,咱们也心愿在公布 Beta 版前,将您的 反馈 纳入库的晚期迭代中。 本文将回顾咱们构建的几个次要可组合项,并介绍帮忙您开始应用的多种资源。 当初就开始吧! 依赖项您对 Wear 设施作出的大部分更改都将位于顶部 架构分层。 这就意味着面向 Wear OS 设计时,您搭配 Jetpack Compose 应用的许多依赖项不会发生变化。例如,UI、运行工夫、编译器和动画依赖项都将放弃不变。 不过,您须要应用适合的 Wear OS Material、导航及根底开发库,这与您之前在挪动利用中所应用的开发库是不一样的。 下方是相干比照,可帮忙您辨别两者差别: Wear OS 依赖项 (androidx.wear.*)比照挪动依赖项 (androidx.*)androidx.wear.compose:compose-material替换androidx.compose.material:material¹androidx.wear.compose:compose-navigation替换androidx.navigation:navigation-composeandroidx.wear.compose:compose-foundation额定增加androidx.compose.foundation:foundation1. 开发者能够持续应用其余与 Material 相干的开发库,如 Material 涟漪和通过 Wear Compose Material 开发库进行扩大的 Material 图标。 ...

December 15, 2021 · 2 min · jiezi

关于android:炫酷Flutter仿Dribbble漂亮的扫描闹钟UI效果

在空闲冲浪的时候,无意间看到了这张设计图,眼睛一亮,感觉这个设计和创意十分酷,打算着手实现一下。对于设计图的作者没找到,如果有人晓得的话,请告知我,我会增加设计援用的,欢送来我的Github 设计图如下: 整体效果图如下: 源码Github: https://github.com/DingMouRen... 剖析设计,咱们分两局部来实现:1.表盘局部  2.下部的开关局部。以下为了省略的逻辑代码,须要残缺的代码的请移步Github 1.表盘局部1.1 察看表盘的款式,把须要做的工作划分突变的背景,用作秒针绘制红色的小圆点绘制带暗影的黄色大圆点,用作时针绘制工夫文字开启定时器,让时钟动起来表盘局部很多都是须要咱们本人绘制的,这里咱们能够应用CustomPaint来实现所有的绘制。CustomPaint提供了自定义widget的能力,它会裸露一个canvas,能够通过这个canvas来绘制widget,有没有很相熟,跟原生android的canvas是不是很类似。 咱们这里将表盘作为背景来绘制,也就是painter属性,自定义CustomPainter,重写paint(Canvas canvas,Size size)和shouldRepaint(covariant CustomPainter oldDelegate)函数,来实现咱们所有的绘制操作。好的,让咱们欢快的开始吧o( ̄▽ ̄)ブ。 1.2 突变的背景,用作秒针从图中咱们能够晓得,渐变色是扫描突变,并布满屏幕,同时地位在整个屏幕的上半局部。首先创立扫描突变对象,这个扫描突变能够创立出一个着色器,而后咱们将这个着色器附着在一个画笔上,通过画布去绘制。留神画布绘制时canvas.save()和canvas.restore()在对应机会的调用。要让秒针动起来,须要开启一个Timer定时工作,每一秒刷新一下视图。 var circle = Rect.fromCircle(center: Offset(0, 0), radius: _screenHeight);    //扫面突变    var sweepGradient = SweepGradient(      colors: [        _startColor,        _endColor      ],    );    //画笔对象   Paint  _paintGradient = Paint()      ..isAntiAlias = true      ..shader = sweepGradient.createShader(circle)      ..style = PaintingStyle.fill;    //获取以后的工夫    DateTime dateTime = DateTime.now();    var hour = dateTime.hour;    var minute = dateTime.minute;    var second = dateTime.second;    //画布位移    canvas.translate(_screenWidth / 2, _screenHeight / 100 * 35);    //绘制突变背景    canvas.save();    //每秒旋转对应角度,模仿秒针挪动    canvas.rotate(_getRotate(second));    canvas.drawCircle(Offset(0, 0), _screenHeight, _paintGradient);    canvas.restore(); 1.3 绘制红色的小圆点这里须要绘制24个红色小圆点,平均分360度,通过画布的旋转来绘制不同角度的红色小圆点。 for (double i = 0; i < _numPoint; i++) {      canvas.save();      //      double deg = 360 / _numPoint * i;      canvas.rotate(deg / 180 * pi);        _paintDial.color = Colors.white;       //绘制红色小圆点       canvas.drawCircle(Offset(_radius, 0), 3, _paintDial);       canvas.restore();      ......      canvas.restore();    } 1.4 绘制带暗影的黄色大圆点,用作时针黄色的大圆点作为时针来解决,因为时针和画布的角度不是吻合的,须要换算,另外咱们为大圆点增加暗影。 for (double i = 0; i < _numPoint; i++) {      canvas.save();      double deg = 360 / _numPoint * i;      canvas.rotate(deg / 180 * pi);      _paintDial.color = Colors.white;      canvas.drawCircle(Offset(_radius, 0), 3, _paintDial);      //isShowBigCircle(hour, i)是判断以后圆点是不是以后的时针地位      if (isShowBigCircle(hour, i)) {        //绘制暗影        Path path = Path()          ..addArc(Rect.fromCircle(center: Offset(_radius, 0), radius: 8), 0,              pi * 2);        canvas.drawShadow(path, Colors.yellow, 4, true);        //绘制小时的圆点        _paintDial.color = Colors.yellow;        canvas.drawCircle(Offset(_radius, 0), 8, _paintDial);      } else {        _paintDial.color = Colors.white;        canvas.drawCircle(Offset(_radius, 0), 3, _paintDial);      }      canvas.restore();      ......    }1.5 绘制工夫文字画布绘制文字调用canvas.drawParagraph(Paragraph Offset)函数,Paragraph 对象通过ParagraphBuilder来创立,字体款式能够通过ParagraphBuilder来设置 //设置文字款式    _timeParagraphBuilder = ParagraphBuilder(ParagraphStyle(        textAlign: TextAlign.center,        fontSize: 70,        maxLines: 1,        fontWeight: FontWeight.bold));   //获取以后的工夫   DateTime dateTime = DateTime.now();    var hour = dateTime.hour;    var minute = dateTime.minute;    var second = dateTime.second;      //绘制文字      canvas.save();      _timeParagraphBuilder.addText(_getTimeStr(hour, minute));      Paragraph paragraph = _timeParagraphBuilder.build();      paragraph.layout(ParagraphConstraints(width: 230));      canvas.drawParagraph(paragraph, Offset(-115,-42));      canvas.restore();2. 开关局部整体布局剖析,开关局部的UI绝对于整个屏幕来讲位于底部,应用 Stack 和 Align就能够实现这种布局款式。   //整体布局  @override  Widget build(BuildContext context) {    return Scaffold(        body: Stack(      children: [        CustomPaint(painter: DialPlate(context,Color.fromARGB(255, 70, 0, 144),Color.fromARGB(255, 121, 83, 254))),        _getAlarms(),      ],    ));  }//下部视图  _getAlarms() {    return Align(      alignment: Alignment.bottomLeft,      child: Container(        margin: EdgeInsets.only(left: 16, right: 16),        height: 200,        width: double.infinity,        child: Column(          children: [            _getRow1(),            _getRow2(),            _getRow3(),          ],        ),      ),    );  }//_getRow1()、_getRow2()、_getRow3()相似 _getRow1() {    return Container(      alignment: Alignment.centerLeft,      width: double.infinity,      height: 50,      child: Row(        children: [          Text(            '06:45',            style: TextStyle(                fontSize: 25,                color: _firstSwitch == true ? _colorOn : _colorOff),          ),          Padding(            padding: EdgeInsets.only(left: 18),            child: Text(              'Wake up',              style: TextStyle(                  fontSize: 18,                  color: _firstSwitch == true ? _colorOn : _colorOff),            ),          ),          Expanded(child: SizedBox()),          Container(            width: 90,            height: 10,            child: Switch(                value: _firstSwitch,                onChanged: (onChanged) {                  setState(() {_firstSwitch = onChanged;});                },                activeColor: _switchActiveColor,                activeTrackColor: Colors.black.withAlpha(100),                inactiveThumbColor: _switchInActiveColor,                inactiveTrackColor: Colors.black.withAlpha(20),            ),          )        ],      ),    );  }原文链接:https://juejin.cn/post/695909... 文末您的点赞珍藏就是对我最大的激励! 欢送关注我,分享Android干货,交换Android技术。 对文章有何见解,或者有何技术问题,欢送在评论区一起留言探讨!

December 15, 2021 · 1 min · jiezi

关于android:作为-Android-开发者如何深入学习-Android-UI

前言Android 新技术层出不穷,要想不落后不被淘汰咱们只能不停的学! 作为好的安卓开发,首先明确Android是前端,重点是UI,做出稳固的利用是要害。 Compose 是 Android UI 的将来,如果将来你会持续在 Android 平台的话,你就肯定须要学习Compose。Flutter 的将来在于多平台,更稳固牢靠的多平台 UI 框架。如果你的路线方向是大前端或者多端开发者,那么 Flutter 就是不二之选。 不过,最初无论是先抉择哪一个,或者二者都学习,最终的目标都是晋升本身 UI 开发设计能力,解决问题和需要。想要玩转 Android UI ,就须要去全面的深刻理解 和把握UI 的底层原理。 如何深刻学习 Android UI?为了帮忙大家高效疾速学习高级 UI 框架底层关键技术及实现原理,这里给大家分享一份《Android高级UI开源框架进阶解密》,内容分为60个章节,一共333页。SmartRefreshLayoutAndroid之PullToRefresh控件源码解析Android-PullToRefresh下拉刷新库根本用法LoadSir-高效易用的加载反馈页治理框架Android通用LoadingView加载框架详解MPAndroidChart实现LineChart(折线图)hellocharts-android使用指南SmartTable使用指南开源我的项目android-uitableview介绍ExcelPanel 使用指南 Android开源我的项目SlidingMenu深切解析MaterialDrawer使用指南SwipeBackLayout的应用办法,右滑返回Android BoomMenu 使用指南PhotoView的使用指南SubsamplingScaleImageView使用指南CircleImageView用法及源码解析Android 图片裁切框架 uCrop 的用法Gif-drawable的应用Android抉择与上传图片之Matisse教程 Richeditor-Android应用阐明TextSurface源码解析Material-Dialogs应用阐明Taosty应用阐明DialogUtil源码解析FloatWindow源码解析ImmersionBar源码解析viewpagerindicator使用指南BottomBar应用阐明FlycoTabLayout使用指南 MagicIndicator使用指南Flexbox-Layout使用指南AndroidAutoSize使用指南FlowLayout应用阐明VLayout使用指南Rclayout使用指南AndroidSwipeLayout使用指南Android-ObservableScrollView使用指南UltimateRecyclerview使用指南 Android-PickerView使用指南DropDownMenu使用指南Android-ConvenientBanner使用指南AgentWeb使用指南500px-android-blur使用指南BlurKit-Android使用指南Android-Viewbadger使用指南BGABadgeView-Android使用指南Android-pathview使用指南RichPath使用指南 AndroidSlidingUpPanel使用指南AppIntro使用指南Android-Bootstrap使用指南Emojicon使用指南RippleEffect使用指南InfiniteCycleViewPager使用指南LoadingDrawable使用指南QMUI\_Android使用指南 因为篇幅无限,材料内容截取局部截图,有须要《Android高级UI开源框架进阶解密》完整版PDF的敌人能够点击这里收费支付! 最初 想要成为高级 Android 开发者,那么对于Android 高级 UI 必须要了然于心。UI 带给用户体验甚至把控着产品后续倒退的命根子。好的 UI 体验能够让用户爱不释手,蹩脚的 UI 体验则是分分钟把用户劝退。想要拥抱高薪,Android 高级UI 常识也是必不可少。

December 15, 2021 · 1 min · jiezi

关于android:自定义View属性动画实战-灵动的锦鲤

通过自定义View+属性动画 实现一个会动鱼 剖析: 1.画一条鱼 2.鱼原地动 3.鱼向点击处游动 画一条鱼 鱼分为:鱼头(圆) + 身材(两条直线+两条贝塞尔曲线) + 鱼鳍(一条直线+一个贝塞尔)+尾巴(两三角)+节肢*2 (梯形+两圆) 先把鱼程度朝右,画一个坐标系,鱼的重心为坐标系核心 先定下鱼的重心的坐标头圆半径的4.19倍,这个其实是本人定的,5f,6f都行,就是只扭转鱼的长度,用鱼头半径做初始单位有利于扭转整个鱼的大小。 因为重心坐标定下了,所以整个鱼的母布局ImageView的宽高,重心的两倍(鱼左右转都不会超出边界) 重点!求一个点的坐标。已知一个点、夹角、长度。求一个点的坐标初中常识: 所以能够得出:入参一个点、两点长度、对于x轴的角度。返回值 一个坐标 依据这个方程求解各个鱼身材。定义画笔 mPaint.setDither(true);防抖动 mPaint.setAntiAlias(true); 抗锯齿 画鱼头:找到鱼头圆心,入参:重心、鱼身长一半、鱼的朝向(默认180跟重心一个方向) 画鱼鳍 鱼鳍是一个直线+一个二阶贝塞尔曲线,所以重点就是求出三个点:鱼鳍左点、右点、贝塞尔控制点 通过鱼头的圆心求,间隔 0.9 * R ,角度110 。通过那个公式就能求进去 = 右鱼鳍点 左鱼鳍点 = 右鱼鳍点、间隔、角度-180 贝塞尔控制点 = (这个齐全靠本人试,只影响鱼鳍的胖瘦) 右鱼鳍点、间隔 * 1.8f、角度 115 试贝塞尔的网站:cubic-bezier.com/#.17,.67,.8… 三个点都有了,绘制鱼鳍: 绘制之前要将其余绘制重置: mPath.reset(); 而后mPath.moveTo()挪动到第一个点 mPath.lineTo()画直线 mPath.quadTo()画二阶贝塞尔曲线,入参第二个点、第三个点 最初 canvas.drawPath(mPath,mPaint);间接画进去 最初一个点不必关闭,零碎主动会关闭。 别的局部也都差不多,依据那个公式,通过参考点求出另一个点,而后求出各个局部的点,最初连线画就行 求出各个点 而后 mPath.reset()、 mPath.moveTo、 mPath.lineTo、canvas.drawPath ...

December 15, 2021 · 1 min · jiezi

关于android:Android-仿-Telegram-一样的上传文件炫酷动画

前段时间,我钻研了一个新性能:在 app 外部聊天中发送图片。这个性能自身很大,包含了多种货色,但实际上,最后并没有设计上传动画与勾销上传的性能。当我用到这部分的时候,我决定减少图片上传动画,所以咱们就给它们这个性能吧:) View vs. Drawable我在那里用了一个 Drawable。在我集体看来,StackOverflow 这里就有个很好的简洁的答案。 Drawable 只响应绘制操作,而 View 响应绘制和用户界面,比方触摸事件和敞开屏幕等等。 当初咱们来剖析一下,咱们想要做什么。咱们心愿有一条有限旋转的弧线做圆形动画,并且弧线的圆心角一直减少直到圆心角等于 2。我感觉一个 Drawable 应该可能帮上我的忙,而且实际上我也应该那样做,但我没有。 我没有这样做的起因在下面示例图片中的文字左边那三个小的点点的动画上。我曾经用自定义 View 实现了这个动画,并且我曾经为有限循环的动画筹备了背景。对我来说把动画筹备逻辑提取到父 View 中重用,而不是把所有货色都重写成 Drawable,应该是更简略的。所以我并不是说我的解决方案是正确的(其实没有什么是正确的),而是它满足了我的需要。 Base InfiniteAnimationView为了本人的须要,我将把想要的进度视图分成两个视图: ProgressView —— 负责绘制所需的进度 ViewInfiniteAnimateView  —— 形象 View,它负责动画的筹备、启动和进行。因为进度中蕴含了有限旋转的局部,咱们须要理解什么时候须要启动这个动画,什么时候须要进行这个动画在查看了 Android 的 ProgressBar 的源代码后,咱们能够最终失去这样的后果: // InfiniteAnimateView.ktabstract class InfiniteAnimateView @JvmOverloads constructor(    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : View(context, attrs, defStyleAttr) {    private var isAggregatedVisible: Boolean = false    private var animation: Animator? = null    override fun onVisibilityAggregated(isVisible: Boolean) {        super.onVisibilityAggregated(isVisible)        if (isAggregatedVisible != isVisible) {            isAggregatedVisible = isVisible            if (isVisible) startAnimation() else stopAnimation()        }    }    override fun onAttachedToWindow() {        super.onAttachedToWindow()        startAnimation()    }    override fun onDetachedFromWindow() {        stopAnimation()        super.onDetachedFromWindow()    }    private fun startAnimation() {        if (!isVisible || windowVisibility != VISIBLE) return        if (animation == null) animation = createAnimation().apply { start() }    }    protected abstract fun createAnimation(): Animator    private fun stopAnimation() {        animation?.cancel()        animation = null    }}遗憾的是,次要出于 onVisibilityAggregated 办法的起因,它并无奈工作 —— 因为[这个办法在 API 24 以上才被反对](developer.android.com/reference/a… !isVisible || windowVisibility != VISIBLE 上的问题,当视图是可见的,但它的容器却不可见。所以我决定重写这个: // InfiniteAnimateView.ktabstract class InfiniteAnimateView @JvmOverloads constructor(    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : View(context, attrs, defStyleAttr) {    private var animation: Animator? = null    /**     * 咱们不能够应用 `onVisibilityAggregated` 办法,因为它只在 SDK 24 以上被反对,而咱们的最低 SDK 是 21     */    override fun onVisibilityChanged(changedView: View, visibility: Int) {        super.onVisibilityChanged(changedView, visibility)        if (isShown) startAnimation() else stopAnimation()    }    override fun onAttachedToWindow() {        super.onAttachedToWindow()        startAnimation()    }    override fun onDetachedFromWindow() {        stopAnimation()        super.onDetachedFromWindow()    }    private fun startAnimation() {        if (!isShown) return        if (animation == null) animation = createAnimation().apply { start() }    }    protected abstract fun createAnimation(): Animator    private fun stopAnimation() {        animation?.cancel()        animation = null    }}可怜的是,这也没有用(尽管我感觉它应该可能失常工作的)。说实话,我不晓得问题的具体起因。可能在一般的状况下会无效,然而对于 RecyclerView 就不行了。前段时间我就遇到了这个问题:如果应用 isShown 来跟踪一些货色是否在 RecyclerView 中显示。因而可能我的最终解决方案并不正确,但至多在我的计划中,它能依照我的冀望工作: // InfiniteAnimateView.ktabstract class InfiniteAnimateView @JvmOverloads constructor(    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : View(context, attrs, defStyleAttr) {    private var animation: Animator? = null    /**     * 咱们不能够应用 `onVisibilityAggregated` 办法,因为它只在 SDK 24 以上被反对,而咱们的最低 SDK 是 21     */    override fun onVisibilityChanged(changedView: View, visibility: Int) {        super.onVisibilityChanged(changedView, visibility)        if (isDeepVisible()) startAnimation() else stopAnimation()    }    override fun onAttachedToWindow() {        super.onAttachedToWindow()        startAnimation()    }    override fun onDetachedFromWindow() {        stopAnimation()        super.onDetachedFromWindow()    }    private fun startAnimation() {        if (!isAttachedToWindow || !isDeepVisible()) return        if (animation == null) animation = createAnimation().apply { start() }    }    protected abstract fun createAnimation(): Animator    private fun stopAnimation() {        animation?.cancel()        animation = null    }    /**     * 可能这个函数上实现了 View.isShown,但我察觉到它有一些问题。     * 我在 Lottie lib 中也遇到了这些问题。不过因为咱们总是没有工夫去深入研究     * 我决定应用了这个简略的办法临时解决这个问题,只为确保它可能失常运行     * 我到底须要什么 = =     *     * 更新:尝试应用 isShown 代替这个办法,但没有胜利。所以如果你晓得     * 如何改良,欢送评论区讨论一下     */    private fun isDeepVisible(): Boolean {        var isVisible = isVisible        var parent = parentView        while (parent != null && isVisible) {            isVisible = isVisible && parent.isVisible            parent = parent.parentView        }        return isVisible    }    private val View.parentView: ViewGroup? get() = parent as? ViewGroup}进度动画筹备那么首先咱们来谈谈咱们 View 的构造。它应该蕴含哪些绘画组件?在以后情境下最好的表达方式就是申明不同的 Paint。 // progress_paints.ktprivate val bgPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {    style = Paint.Style.FILL    color = defaultBgColor}private val bgStrokePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {    style = Paint.Style.STROKE    color = defaultBgStrokeColor    strokeWidth = context.resources.getDimension(R.dimen.chat_progress_bg_stroke_width)}private val progressPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {    style = Paint.Style.STROKE    strokeCap = Paint.Cap.BUTT    strokeWidth = context.resources.getDimension(R.dimen.chat_progress_stroke_width)    color = defaultProgressColor}为了展现我将扭转笔触的宽度和其余货色,所以你会看到某些方面的不同。这 3 个 Paint 就与 3 个要害局部的进度相关联: 左:background; 中:stroke; 右:progress 你可能想晓得为什么我要用 Paint.Cap.BUTT。好吧,为了让这个进度更 "Telegram"(至多在 iOS 设施上是这样),你应该应用 Paint.Cap.ROUND。让我来演示一下这三种可能的款式之间的区别(这里减少了描边宽度以让差别更显著)。 左:Cap.BUTT,中:Cap.ROUND,右:Cap.SQUARE 因而,次要的区别是,Cap.ROUND给笔画的角以非凡的圆角,而 Cap.BUTT 和 Cap.SQUARE只是切割。Cap.SQUARE 也和 Cap.ROUND 一样预留了额定的空间,但没有圆角成果。这可能导致 Cap.SQUARE 显示的角度与 Cap.BUTT 雷同但预留了额定的空间。 试图用 Cap.BUTT 和 Cap.SQUARE 来显示 90 度。 思考到所有这些状况,咱们最好应用 Cap.BUTT,因为它比 Cap.SQUARE 显示的角度示意更失当。 顺便说一下 Cap.BUTT 是画笔默认的笔刷类型。这里有一个官网的文档链接。但我想向你展现真正的区别,因为最后我想让它变成 ROUND,而后我开始应用 SQUARE,但我留神到了一些个性。Base Spinning动画自身其实很简略,因为咱们有 InfiniteAnimateView: ...

December 15, 2021 · 1 min · jiezi

关于android:继承ViewGroup学习onMeasure和onLayout

在继承ViewGroup类时,须要重写两个办法,别离是onMeasure和onLayout。 1,在办法onMeasure中调用setMeasuredDimension办法void android.view.View.setMeasuredDimension(int measuredWidth, int measuredHeight)在onMeasure(int, int)中,必须调用setMeasuredDimension(int width, int height)来存储测量失去的宽度和高度值,如果没有这么去做会触发异样IllegalStateException。2,在办法onMeasure中调用孩子的measure办法 void android.view.View.measure(int widthMeasureSpec, int heightMeasureSpec) 这个办法用来测量出view的大小。父view应用width参数和height参数来提供constraint信息。实际上,view的测量工作在onMeasure(int, int)办法中实现。因而,只有onMeasure(int, int)办法能够且必须被重写。参数widthMeasureSpec提供view的程度空间的规格阐明,参数heightMeasureSpec提供view的垂直空间的规格阐明。 3,解析onMeasure(int, int)办法 void android.view.View.onMeasure(int widthMeasureSpec, int heightMeasureSpec) 测量view及其内容来确定view的宽度和高度。这个办法在measure(int, int)中被调用,必须被重写来准确和无效的测量view的内容。 在重写这个办法时,必须调用setMeasuredDimension(int, int)来存储测量失去的宽度和高度值。执行失败会触发一个IllegalStateException异样。调用父view的onMeasure(int, int)是非法无效的用法。 view的根本测量数据默认取其背景尺寸,除非容许更大的尺寸。子view必须重写onMeasure(int, int)来提供其内容更加精确的测量数值。如果被重写,子类确保测量的height和width至多是view的最小高度和宽度(通过getSuggestedMinimumHeight()和getSuggestedMinimumWidth()获取)。 4,解析onLayout(boolean, int, int, int, int)办法 void android.view.ViewGroup.onLayout(boolean changed, int l, int t, int r, int b) 调用场景:在view给其孩子设置尺寸和地位时被调用。子view,包含孩子在内,必须重写onLayout(boolean, int, int, int, int)办法,并且调用各自的layout(int, int, int, int)办法。 参数阐明:参数changed示意view有新的尺寸或地位;参数l示意绝对于父view的Left地位;参数t示意绝对于父view的Top地位;参数r示意绝对于父view的Right地位;参数b示意绝对于父view的Bottom地位。. 5,解析View.MeasureSpec类android.view.View.MeasureSpecMeasureSpec对象,封装了layout规格阐明,并且从父view传递给子view。每个MeasureSpec对象代表了width或height的规格。MeasureSpec对象蕴含一个size和一个mode,其中mode能够取以下三个数值之一:UNSPECIFIED,1073741824 [0x40000000],未加规定的,示意没有给子view增加任何规定。EXACTLY,0 [0x0],准确的,示意父view为子view确定准确的尺寸。AT_MOST,-2147483648 [0x80000000],子view能够在指定的尺寸内尽量大。 在这里给大家举一个例子demo:第一步:自定义一个View实现ViewGroup接口,即自定义ViewGroup: import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; public class MyViewGroup extends ViewGroup { public MyViewGroup(Context context) { super(context); } public MyViewGroup(Context context, AttributeSet attrs) { super(context, attrs); } public MyViewGroup(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * 计算控件的大小 */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int measureWidth = measureWidth(widthMeasureSpec); int measureHeight = measureHeight(heightMeasureSpec); // 计算自定义的ViewGroup中所有子控件的大小 measureChildren(widthMeasureSpec, heightMeasureSpec); // 设置自定义的控件MyViewGroup的大小 setMeasuredDimension(measureWidth, measureHeight); } private int measureWidth(int pWidthMeasureSpec) { int result = 0; int widthMode = MeasureSpec.getMode(pWidthMeasureSpec);// 失去模式 int widthSize = MeasureSpec.getSize(pWidthMeasureSpec);// 失去尺寸 switch (widthMode) { /** * mode共有三种状况,取值别离为MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY, * MeasureSpec.AT_MOST。 * * * MeasureSpec.EXACTLY是准确尺寸, * 当咱们将控件的layout_width或layout_height指定为具体数值时如andorid * :layout_width="50dip",或者为FILL_PARENT是,都是控件大小曾经确定的状况,都是准确尺寸。 * * * MeasureSpec.AT_MOST是最大尺寸, * 当控件的layout_width或layout_height指定为WRAP_CONTENT时 * ,控件大小个别随着控件的子空间或内容进行变动,此时控件尺寸只有不超过父控件容许的最大尺寸即可 * 。因而,此时的mode是AT_MOST,size给出了父控件容许的最大尺寸。 * * * MeasureSpec.UNSPECIFIED是未指定尺寸,这种状况不多,个别都是父控件是AdapterView, * 通过measure办法传入的模式。 */ case MeasureSpec.AT_MOST: case MeasureSpec.EXACTLY: result = widthSize; break; } return result; } private int measureHeight(int pHeightMeasureSpec) { int result = 0; int heightMode = MeasureSpec.getMode(pHeightMeasureSpec); int heightSize = MeasureSpec.getSize(pHeightMeasureSpec); switch (heightMode) { case MeasureSpec.AT_MOST: case MeasureSpec.EXACTLY: result = heightSize; break; } return result; } /** * 覆写onLayout,其目标是为了指定视图的显示地位,办法执行的前后程序是在onMeasure之后,因为视图必定是只有晓得大小的状况下, * 能力确定怎么摆放 */ @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // 记录总高度 int mTotalHeight = 0; // 遍历所有子视图 int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View childView = getChildAt(i); // 获取在onMeasure中计算的视图尺寸 int measureHeight = childView.getMeasuredHeight(); int measuredWidth = childView.getMeasuredWidth(); childView.layout(l, mTotalHeight, measuredWidth, mTotalHeight + measureHeight); mTotalHeight += measureHeight; } } }第二步,布局文件: ...

December 15, 2021 · 2 min · jiezi

关于android:Pythonlogging总结

在部署我的项目时,不可能间接将所有的信息都输入到控制台中,咱们能够将这些信息记录到日志文件中,这样不仅不便咱们查看程序运行时的状况,也能够在我的项目呈现故障时依据运行时产生的日志疾速定位问题呈现的地位。 1、日志级别Python 规范库 logging 用作记录日志,默认分为六种日志级别(括号为级别对应的数值),NOTSET(0)、DEBUG(10)、INFO(20)、WARNING(30)、ERROR(40)、CRITICAL(50)。咱们自定义日志级别时留神不要和默认的日志级别数值雷同,logging 执行时输入大于等于设置的日志级别的日志信息,如设置日志级别是 INFO,则 INFO、WARNING、ERROR、CRITICAL 级别的日志都会输入。 2、logging 流程官网的 logging 模块工作流程图如下: 从下图中咱们能够看出看到这几种 Python 类型,Logger、LogRecord、Filter、Handler、Formatter。 类型阐明: Logger:日志,裸露函数给应用程序,基于日志记录器和过滤器级别决定哪些日志无效。 LogRecord :日志记录器,将日志传到相应的处理器解决。 Handler :处理器, 将(日志记录器产生的)日志记录发送至适合的目的地。 Filter :过滤器, 提供了更好的粒度管制,它能够决定输入哪些日志记录。 Formatter:格式化器, 指明了最终输入中日志记录的布局。 判断 Logger 对象对于设置的级别是否可用,如果可用,则往下执行,否则,流程完结。创立 LogRecord 对象,如果注册到 Logger 对象中的 Filter 对象过滤后返回 False,则不记录日志,流程完结,否则,则向下执行。LogRecord 对象将 Handler 对象传入以后的 Logger 对象,(图中的子流程)如果 Handler 对象的日志级别大于设置的日志级别,再判断注册到 Handler 对象中的 Filter 对象过滤后是否返回 True 而放行输入日志信息,否则不放行,流程完结。如果传入的 Handler 大于 Logger 中设置的级别,也即 Handler 无效,则往下执行,否则,流程完结。判断这个 Logger 对象是否还有父 Logger 对象,如果没有(代表以后 Logger 对象是最顶层的 Logger 对象 root Logger),流程完结。否则将 Logger 对象设置为它的父 Logger 对象,反复下面的 3、4 两步,输入父类 Logger 对象中的日志输入,直到是 root Logger 为止。3、日志输入格局日志的输入格局能够认为设置,默认格局为下图所示。 ...

December 15, 2021 · 4 min · jiezi

关于android:建议收藏为什么公司宁愿-30K-重新招人也不给你加到-20K原因太现实

前言我的一个敌人在阿里下班,勤勤恳恳工作了两三年,公司却迟迟不给他涨工资。他来找到我,他说他很苦恼,说公司最近新来了一个员工都比他的工资要高,就因为他对性能调优这方面很善于。 什么是性能优化?在同一个手机外面,同样性能的app,哪个跑的快,哪个不卡,哪个就性能高;咱们要找到性能低的中央,并且把这些中央解决掉,这个就是性能优化;当初有很多软件开发公司以及开发者谋求的最终目标不再是简略地实现性能,更多的是提供更好的用户体验,而性能问题在用户体验中扮演着重要角色。 为什么要进行性能调优?如果用户想要实现一个同样的操作,一个 App 须要 10 秒,而同类 App 仅须要 3 秒,作为用户, 会怎么选?此外,欠佳的性能还可能导致 ANR(Application Not Responding,指应用程序无响应)状况的呈现。再加上一旦产生卡顿,就意味着接下来可能产生手机发热、电量疾速耗费等关联问题,这些都很可能导致用户的散失。 因而,改善 App 性能不容忽视。零碎性能调优不仅能够进步零碎性能,还能为公司节俭资源。这也是咱们做性能调优的最间接的目标。所以,公司也更违心招聘有这方面技术的人才. 上面给大家分享一份 722页的《360°全方面性能调优》文档,文档次要有四个大章节,设计思维与代码品质优化; 程序性能优化;开发效率优化;APP 性能优化实际;第一章 设计思维与代码品质优化一,六大准则繁多职责准则 里氏替换准则 依赖倒转准则 接口隔离准则 迪米特法令 合成复用准则 二,设计模式结构型模式 创立型模式 数据结构 三,数据结构数组 栈 队列 链表 树 图 堆 散列表 四,算法排序算法 查找算法 第二章 程序性能优化一,启动速度与执行效率优化冷启动和热启动解析 APP启动黑白屏解决办法 APP 卡顿问题剖析及解决方案 启动速度与执行效率优化之StrictMode 二,布局检测与优化布局层级优化 适度渲染 三,内存优化内存抖动和内存透露 内存小户,Bitmap 内存优化 Profile 内存监测工具 Mat 大对象与透露检测 四,耗电优化Doze&Standby Battery Historian JobScheduler、WorkManager 五,网络传输与数据存储优化google 序列化工具 protobuf 7z 极限压缩 六,APK 大小优化APK 瘦身 微信资源混同原理 ...

December 15, 2021 · 1 min · jiezi

关于android:Android换肤功能实现

Android换肤性能已不是什么新鲜事了,市面上有很多第三方的换肤库和实现计划。 之所以抉择腾讯的QMUI库来演示APP的换肤性能,次要起因: 1、换肤性能的实现过程较简略、容易了解; 2、能轻松适配Android 10 提供的Dark Mode(深色模式) ; 3、还能白嫖QMUI的各种组件、成果(这才是重要的,哈哈~); 1、换肤流程实现:1.1、新建工程通过AndroidStudio新建一个空工程(新建工程的过程,略),并增加QMUI依赖: implementation 'com.qmuiteam:qmui:2.0.0-alpha10' 1.2、定义 attr 以及其实现 style(重点)这一步须要咱们与设计师合作,整顿一套色彩、背景资源等供 App 应用。之后咱们在 xml 里以 attr 的模式给它命名,本工程案例: src/main/res/values/styles.xml: <resources> <attr name="colorPrimary" format="color" /> <attr name="colorBg1" format="color" /> <attr name="colorBg2" format="color" /> <attr name="colorBg3" format="color" /> <attr name="colorTextWhite" format="color" /> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <item name="colorPrimary">@color/colorPrimaryDefault</item> <item name="colorBg1">@color/colorBgDefault1</item> <item name="colorBg2">@color/colorBgDefault2</item> <item name="colorBg3">@color/colorBgDefault3</item> <item name="colorTextWhite">@color/colorTextWhite</item> </style> <style name="app_skin_1" parent="AppTheme"> <item name="colorPrimary">@color/colorPrimarySkin1</item> <item name="colorBg1">@color/colorBgDefault1Skin1</item> <item name="colorBg2">@color/colorBgDefault1Skin2</item> <item name="colorBg3">@color/colorBgDefault1Skin3</item> </style> <style name="app_skin_2" parent="AppTheme"> <item name="colorPrimary">@color/colorPrimarySkin2</item> <item name="colorBg1">@color/colorBgDefault2Skin1</item> <item name="colorBg2">@color/colorBgDefault2Skin2</item> <item name="colorBg3">@color/colorBgDefault2Skin3</item> </style> </resources>src/main/res/values/colors.xml: <?xml version="1.0" encoding="utf-8"?> <resources> <color name="colorPrimaryDefault">#FCE4EC</color> <color name="colorBgDefault1">#F06292</color> <color name="colorBgDefault2">#EC407A</color> <color name="colorBgDefault3">#880E4F</color> <color name="colorTextWhite">#FFFFFF</color> <color name="colorPrimarySkin1">#E3F2FD</color> <color name="colorBgDefault1Skin1">#90CAF9</color> <color name="colorBgDefault1Skin2">#42A5F5</color> <color name="colorBgDefault1Skin3">#0D47A1</color> <color name="colorPrimarySkin2">#FAFAFA</color> <color name="colorBgDefault2Skin1">#757575</color> <color name="colorBgDefault2Skin2">#424242</color> <color name="colorBgDefault2Skin3">#212121</color> </resources>style 是反对继承的, 以上述为例,app\_skin\_1 继承自 AppTheme, 在通过 attr 寻找其值时,如果在 app\_skin\_1 没找到,那么它就会去 AppTheme 寻找。因而咱们能够把 App 的 theme 作为咱们的一个 skin, 其它 skin 都继承自这个 skin。 ...

December 15, 2021 · 4 min · jiezi

关于android:Android-AAC架构实践

LiveData如何实现数据更新LiveData如何实现同activity申明周期绑定viewModel如何实现数据共享viewModel如何实现数据保留本文就如上问题联合aac框架源码进行逐渐解析 ##一.LiveData实现数据更新 既然是监测数据更新,必定是应用到观察者模式 观察者 GenericLifecycleObserver,其中LifecycleObserver为空接口public interface GenericLifecycleObserver extends LifecycleObserver { void onStateChanged(LifecycleOwner source, Lifecycle.Event event);}被观察者public abstract class Lifecycle { public abstract void addObserver(@NonNull LifecycleObserver observer); @MainThread public abstract void removeObserver(@NonNull LifecycleObserver observer); @MainThread @NonNull public abstract State getCurrentState(); @SuppressWarnings("WeakerAccess") public enum Event { /** * Constant for onCreate event of the {@link LifecycleOwner}. */ ON_CREATE, /** * Constant for onStart event of the {@link LifecycleOwner}. */ ON_START, /** * Constant for onResume event of the {@link LifecycleOwner}. */ ON_RESUME, /** * Constant for onPause event of the {@link LifecycleOwner}. */ ON_PAUSE, /** * Constant for onStop event of the {@link LifecycleOwner}. */ ON_STOP, /** * Constant for onDestroy event of the {@link LifecycleOwner}. */ ON_DESTROY, /** * An {@link Event Event} constant that can be used to match all events. */ ON_ANY } /** * Lifecycle states. You can consider the states as the nodes in a graph and * {@link Event}s as the edges between these nodes. */ @SuppressWarnings("WeakerAccess") public enum State { /** * Destroyed state for a LifecycleOwner. After this event, this Lifecycle will not dispatch * any more events. For instance, for an {@link android.app.Activity}, this state is reached * <b>right before</b> Activity's {@link android.app.Activity#onDestroy() onDestroy} call. */ DESTROYED, /** * Initialized state for a LifecycleOwner. For an {@link android.app.Activity}, this is * the state when it is constructed but has not received * {@link android.app.Activity#onCreate(android.os.Bundle) onCreate} yet. */ INITIALIZED, /** * Created state for a LifecycleOwner. For an {@link android.app.Activity}, this state * is reached in two cases: * <ul> * <li>after {@link android.app.Activity#onCreate(android.os.Bundle) onCreate} call; * <li><b>right before</b> {@link android.app.Activity#onStop() onStop} call. * </ul> */ CREATED, /** * Started state for a LifecycleOwner. For an {@link android.app.Activity}, this state * is reached in two cases: * <ul> * <li>after {@link android.app.Activity#onStart() onStart} call; * <li><b>right before</b> {@link android.app.Activity#onPause() onPause} call. * </ul> */ STARTED, /** * Resumed state for a LifecycleOwner. For an {@link android.app.Activity}, this state * is reached after {@link android.app.Activity#onResume() onResume} is called. */ RESUMED; /** * Compares if this State is greater or equal to the given {@code state}. * * @param state State to compare with * @return true if this State is greater or equal to the given {@code state} */ public boolean isAtLeast(@NonNull State state) { return compareTo(state) >= 0; } }}咱们来看看Lifecycle实现类LifecycleRegistry,次要看增加观察者以及接管被观察者,对应如下两个办法 ...

December 15, 2021 · 10 min · jiezi

关于android:2021年秋招小米Android面经已获offer

前言当代大部分打工人的一个现状——“降职有望、支出见顶、生存开销飙升、财务危机如影随形”。自己毕业三年,三年Android开发。往年7月面试了小米,半个月拿到offer,记录一下整个面试过程,须要的能够看一下。 小米面试分享:一面(9.5 60min)事件散发自定义view给了个布局问你的实现形式有没有理解过新的布局有没有理解过新的布局实习经验Android布局优化适度绘制及优化讲讲你认为你Android里了解最深的点理解过framework吗讲讲二叉树前中后序遍历数据库 写了个简略的sql触发器类加载的过程kotlin扩大办法 扩大属性看过哪些开源库(聊了聊retrofit)实习过程中最有成就感的事算法 反转链表(没写进去 我是个傻子吧)删除公共字符串冒泡排序怎么排的 稳固吗一面完感觉还不错能预料到会有二面,问的都比拟中规中矩 二面(9.8 50min)实习经验 做了哪些需要有什么播种对前人留下的代码有什么想法,怎么解决的Android 滑动工夫抵触解决handler原理Android跨过程通信Activity生命周期Android为啥要分四大组件弹一个dialog时Activity生命周期变动onstart onresume别离执行什么类型的业务Java 手写单例hashmap源码多线程,锁操作系统 过程和线程的区别算法 之字形打印二叉树(又没写进去 我是*)面的时候刚从天津坐车回来,头有点晕,感觉有点拉跨,答得很个别,没想到还有三面 三面(9.9 60min)Java 封装继承多态,重点说了解及利用static重写和重载的区别、了解及利用hashmap底层,把面试官当小白给面试官讲Android 四大组件的了解activity生命周期、横竖屏生命周期、有没有不让activity销毁的办法启动模式两种service有啥区别service执行耗时操作会咋样、咋解决intentservice底层service保活broadcastreciver权限(不会)Android跨过程形式intent底层是怎么跨过程的罕用布局,重点说了解及利用Android动画有哪几种,有没有底层钻研自定义view、本人写过的demo内存透露场景及解决办法网络 TCP三次握手/四次挥手 讲讲有没有间接在TCP层做过操作操作系统 过程和线程的区别闲聊 实习最大的播种是什么你当初在团队里算是外围吗(我一个实习生外围才怪)有没有感觉对本人能力晋升特地大的需要如果给你offer你来吗如果要来的话来到当初的团队融入新的团队你有什么想法三面的面试官说跟前两面面试官没怎么交换,可能问题有反复,理论也的确有反复,然而感觉更多的还是往深了问,面很广而且很深,很多问题都没答复上来,一下子给我整懵了。幸好之前连夜做了做功课,看了很多大佬总结的技术性问题,拓宽了对试题的知识面。 在这里我精心收录整顿了一些对于Android开发的知识点、面试题的一个总结,举荐给大家化解成长的懊恼。 《Android 高级开发面试题以及答案》1.Activity2.Service3.BroadcastReceive.4.ContentProvider5.Handler6.View绘制.7.View事件散发8.RecycleView 9.Viewpager&Fragment10.WebView11.动画12.Bitmap13.mvc&mvp&mvvm14.Binder15.内存透露&内存溢出16.性能优化 17.Window&WindowManager18.AMS19.系统启动20.App启动&打包&装置21.序列化22.Art & Dalvik及其区别23.模块化&组件化24.热修复&插件化25.AOP26.iectpack总结面试胜利的因素,我感觉还是要多多看技术博客,器重每一次面试,不在同一个问题上栽倒两次。每场面试也会有一两道平时不器重的一些细枝末节的问题,但每次挂完电话/面完 回去都会认真再针对性温习这一块的知识点,确保下一次被问到这类问题不会再被坑。 因为文章篇幅无限,文档资料内容较多,本能够提供链接下载,但无奈容易被谐和,所以全副存档,须要这些文档这里的敌人,能够点击我的【Gitee】,心愿可能共同进步,共勉! 最初,祝大家都能拿到心仪的offer~

December 15, 2021 · 1 min · jiezi

关于android:Android-Gradle-学习笔记整理

前言Gradle 是将软件编译、测试、部署等步骤分割在一起自动化构建工具。 对于Android开发人员曾经理解build.gradle 的 android{} 和 dependencies{} ,然而他的编译过程是什么样的?这个过程中能够干些什么事理解吗? 此文是学习Gradle时的学习笔记,让你重新认识Gradle,让Gradle放慢并提效构建你的我的项目。此时分享给大家,与大家共勉 此笔记次要内容如下Gradle 最根底的一个我的项目配置Groovy 根底语法 并解释 apply plugin: 'xxxx'和dependencies{}Gradle Project/Task 并自定义Task和Plugin自定义一个重命名APP名的插件 流程APT 技术- Java AbstractProcessorAndroid 字节码加强技术 - Transform (Android 中应用字节码加强技术)文章内容略长,如果你曾经把握Gradle基础知识,能够间接通过目录查看你想看的内容,回顾或者学习都还不错。 初识Gradle 我的项目构建配置gralde我的项目构造 如图所示,是一个比拟小的gradle配置,这里次要说两局部 绿色局部: gralde版本配置及gralde所须要的脚本,其中gradlew为linux/mac下的脚本,gradle.bat为windows下所需的脚本红色局部:settings.gradle 为根我的项目的我的项目配置,外层的build.gradle为根我的项目的配置,内层的build.gradle为子项目的配置gradle 配置程序gralde的我的项目配置是先辨认 settings.gradle,而后在配置各个build.gradle. 为了阐明构建执行程序,在上述最根底的gradle我的项目构造外面设置了对应的代码 // settings.gradleprintln "settings.gradle start"include ':app'println "settings.gradle end"//root build.gradleprintln "project.root start"buildscript { repositories { } dependencies { }}allprojects {}println "project.root end"//app build.gradleprintln "project.app start"project.afterEvaluate { println "project.app.afterEvaluate print"}project.beforeEvaluate { println "project.app.beforeEvaluate print"}println "project.app end"如果是mac/linux,执行./gradlew 失去如下后果: ...

December 14, 2021 · 6 min · jiezi

关于android:Android开发ComposeUI如何解决布局嵌套原理解析

概述背景:布局层级过多、布局适度的嵌套会导致测量工夫呈指数级增长,最终影响布局性能。现状:Compose没有上述布局嵌套问题,因为它基本上解决了布局层级对布局性能的影响。解决原理:Compose界面只容许一次测量,即随着布局层级的加深,测量工夫仅线性增长。本文将次要阐明: 布局嵌套过多如何影响布局性能?ComposeUI如何解决嵌套问题?为什么ComposeUI能够只容许一次测量?ComposeUI测量过程的源码剖析1. 布局嵌套过多如何影响布局性能?起因次要是:ViewGroup会对子View进行屡次测量。假如:父布局的布局属性是wrap_content、子布局是match_parent,此时的布局过程是: 父布局先以0为强制宽度测量子View、而后持续测量剩下的其余子View再用其余子View里最宽的宽度,二次测量这个match_parent的子 View,最终得出它的尺寸,并把这个宽度作为本人最终的宽度。即 这个过程就对单个子View进行了二次测量。 「而布局嵌套对性能影响则是指数模式的」,即:父布局会对每个子view做两次测量,子view也会对上面的子view进行两次测量,即相当于是 O(2)测量。 2. ComposeUI如何解决嵌套问题?ComposeUI规定:只容许一次测量,不容许反复测量。即每个父布局只对每个子组件测量一次,即测量复杂度变成了:O(n)。 3. 为什么ComposeUI能够只容许一次测量?ComposeUI引入了:固有个性测量(Intrinsic Measurement)。即 Compose 容许父组件在对子组件测量前先测量子组件的“固有尺寸”,这相当于下面说的两次测量的 第一次 “粗略测量“。 而这种固定个性测量是对整个组件布局树进行一次测量即可,从而防止了随着层级的加深而减少测量次数。 4. ComposeUI测量过程的源码剖析此处次要剖析:固定个性测量的测量过程。此处先介绍LayoutNodeWrapper链构建 4.1 LayoutNodeWrapper先来看两个外围论断: 子View都是以LayoutNode的模式,存在于Parent - children中的给Layout的设置的modifier会以LayoutNodeWrapper链的模式存储在LayoutNode中,而后后续做相应变换上面阐明LayoutNodeWrapper的构建: 默认的LayoutNodeWrapper链即由LayoutNode , OuterMeasurablePlaceable, InnerPlaceable 组成当增加了modifier时,LayoutNodeWrapper链会更新,modifier会作为一个结点插入到其中internal val innerLayoutNodeWrapper: LayoutNodeWrapper = InnerPlaceable(this)private val outerMeasurablePlaceable = OuterMeasurablePlaceable(this, innerLayoutNodeWrapper)override fun measure(constraints: Constraints) = outerMeasurablePlaceable.measure(constraints)override var modifier: Modifier = Modifier    set(value) {        // …… code        field = value        // …… code            // 创立新的 LayoutNodeWrappers 链        // foldOut 相当于遍历 modifier        val outerWrapper = modifier.foldOut(innerLayoutNodeWrapper) { mod /* modifier*/ , toWrap ->            var wrapper = toWrap            if (mod is OnGloballyPositionedModifier) {                onPositionedCallbacks += mod            }            if (mod is RemeasurementModifier) {                mod.onRemeasurementAvailable(this)            }            val delegate = reuseLayoutNodeWrapper(mod, toWrap)            if (delegate != null) {                wrapper = delegate            } else {                  // …… 省略了一些 Modifier判断                   if (mod is KeyInputModifier) {                    wrapper = ModifiedKeyInputNode(wrapper, mod).assignChained(toWrap)                }                if (mod is PointerInputModifier) {                    wrapper = PointerInputDelegatingWrapper(wrapper, mod).assignChained(toWrap)                }                if (mod is NestedScrollModifier) {                    wrapper = NestedScrollDelegatingWrapper(wrapper, mod).assignChained(toWrap)                }                // 布局相干的 Modifier                if (mod is LayoutModifier) {                    wrapper = ModifiedLayoutNode(wrapper, mod).assignChained(toWrap)                }                if (mod is ParentDataModifier) {                    wrapper = ModifiedParentDataNode(wrapper, mod).assignChained(toWrap)                }                           }            wrapper        }        outerWrapper.wrappedBy = parent?.innerLayoutNodeWrapper        outerMeasurablePlaceable.outerWrapper = outerWrapper        ……    }// 假如:给Layout设置一些modifierModifier.size(100.dp).padding(10.dp).background(Color.Blue)对应的LayoutNodeWrapper链如下图所示 <figcaption style="margin: 5px 0px 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; text-align: center; font-size: 13px;">image.png</figcaption> 这样始终链式调用下一个的measure,直到最初一个结点InnerPlaceable,最终调用到了自定义Layout时写的measure() 4.2 固有个性测量-实现原理论断:LayoutNodeWrapper链中插入了一个Modifier @Stablefun Modifier.height(intrinsicSize: IntrinsicSize) = when (intrinsicSize) {    IntrinsicSize.Min -> this.then(MinIntrinsicHeightModifier)    IntrinsicSize.Max -> this.then(MaxIntrinsicHeightModifier)}private object MinIntrinsicHeightModifier : IntrinsicSizeModifier { override fun MeasureScope.measure(        measurable: Measurable,        constraints: Constraints    ): MeasureResult {     //正式测量前先依据固有个性测量取得一个束缚        val contentConstraints = calculateContentConstraints(measurable, constraints)        //正式测量        val placeable = measurable.measure(            if (enforceIncoming) constraints.constrain(contentConstraints) else contentConstraints        )        return layout(placeable.width, placeable.height) {            placeable.placeRelative(IntOffset.Zero)        }    }    override fun MeasureScope.calculateContentConstraints(        measurable: Measurable,        constraints: Constraints    ): Constraints {        val height = measurable.minIntrinsicHeight(constraints.maxWidth)        return Constraints.fixedHeight(height)    }    override fun IntrinsicMeasureScope.maxIntrinsicHeight(        measurable: IntrinsicMeasurable,        width: Int    ) = measurable.minIntrinsicHeight(width)}汇总阐明: IntrinsicSize.Min其实也是个ModifierMinIntrinsicHeightModifier会在测量之间,先调用calculateContentConstraints计算束缚calculateContentConstraints中则会递归地调用子项的minIntrinsicHeight,并找出最大值,这样父项的高度就确定了固有个性测量实现后,再调用measurable.measure,开始真正的递归测量至此,对于Compose UI解决布局嵌套层级问题及其原理解说结束。 最初给大家分享我收集的Android源码解析学习材料,心愿对你有用,期待与大家一起提高 1.深刻解析微信 MMKV 源码 2.深刻解析阿里巴巴路由框架 ARouter源码 3.深刻解析 AsyncTask 源码(一款Android 内置的异步工作执行库) ...

December 14, 2021 · 1 min · jiezi

关于android:写一个MVVM快速开发框架谈一谈单Activity多Fragment模式

单Activity+多Fragment模式自从晓得这一招之后我根本不太违心应用activity了,fragment能够疾速创立和治理,能够正当设计页面跳转,设计炫酷的跳转动画,一些操作能够对立进行治理。用Fragment代替Activity以前大部分时候都是将Activity作为页面,Fragment作为页面中的子页面(过后称之为碎片),基本上大部分性能由activity实现,比方老版本的淘宝app就是有上百个activity,过后卡顿的不要不要的。随着技术迭代,咱们发现activtiy创立、切换、销毁所耗费的性能远比fragment要大,fragment现在也能代替activity实现大部分性能。 将Activity作为容器我了解的单Activity+多Fragment模式并不是指一个App肯定只有一个activity,对于一些业务相干的场景,能够整合成一个单Activity+多Fragment模块,将activity作为fragment的容器,让fragment去做UI绘制工作。 治理Fragment栈咱们能够应用navigation治理fragment,fragment之间的跳转、栈治理都轻而易举,navigation还能够设置切换动画、页面间的数据传递。 Navigation组件Navigation是Jetpack组件之一,很早之前iOS就是采纳的这种跳转形式,过后就在想Android为啥没有,没多久Navigation就面世了。Navigation能够了解为以一个治理fragment的容器,在容器中各个fragment能够实现任意跳转, 根底应用:咱们须要在布局中创立Fragment容器: <androidx.fragment.app.FragmentContainerView android:id="@+id/main_fragment_container" android:layout_width="match_parent" android:layout_height="0dp" android:name="androidx.navigation.fragment.NavHostFragment" app:defaultNavHost="true" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:navGraph="@navigation/nav_main"/>创立navigation.xml文件<?xml version="1.0" encoding="utf-8"?><navigation xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/navigation_main" app:startDestination="@+id/mainFragment"> <fragment android:id="@+id/mainFragment" android:name="com.example.mvvm_develop.MainFragment" android:label="MainFragment" /></navigation>应用NavControllerval navController = (childFragmentManager.findFragmentById(R.id.module_fragment_container) as NavHostFragment).navController//跳转navController.navigate(R.id.mainFragment)一些具体参数和用法:navGraph这个值指向xml文件,在xml文件中咱们能够定义fragment,跳转行为,目的地等。 创立、新增Fragment: 创立跳转行为: 动画、目的地、返回栈配置: NavController字面意思就是导航控制器,NavController能够管制跳转、返回、动画、监听等操作。咱们能够应用它进行灵便的跳转,Google还出了一些Navigation Demo演示如何配合Toolbar和底部导航栏进行应用。 对于具体的用法这里不解说了,很多文章都有,也能够参考官网。Navigation存在的问题:重走生命周期Navigation目前有个问题:Fragment回退重走生命周期,这个问题可能是Google想让Fragment和activity领有同样的工作模式,单重走生命周期真的很烦,咱们能够自定义NavHostFragment去修复这个问题,具体参考我的项目代码 批改之后应用如下: android:name="androidx.navigation.fragment.NavHostFragment" 批改为咱们自定义的NavHostFragment: android:name="com.example.baselibrary.navigation.NavHostFragment" <fragment android:id="@+id/navigation_main" android:name="com.example.baselibrary.navigation.NavHostFragment" android:layout_width="match_parent" android:layout_height="match_parent" app:defaultNavHost="true" app:navGraph="@navigation/nav_main"/>组件化中应用Navigation咱们通常应用底部导航栏将app划分出不同的性能,这些都是独自的module,然而在navigation中怎么进行module间的跳转呢? 比方: 其布局文件就是一个FragmentContainerView+BottomNavigationView,切换上面按钮的时候须要切换到不同的moduel页面。首先咱们将不同的moduel视为一个“单activity+多fragment”的模块,或者也能够省略activity。 形式一: google的demo中是在MainActivity中创立一个main\_navGraph,其中蕴含了不同子moduel的navGraph ,如下: <?xml version="1.0" encoding="utf-8"?><navigation xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/nav_module" app:startDestination="@+id/navi_home"> <include app:graph="@navigation/navi_home"/> <include app:graph="@navigation/navi_collection"/> <include app:graph="@navigation/navi_center"/></navigation>navi_home 、navi_collection 、navi_center是子moduel中的navGraph文件,这种做法要求其指定startDestination,而且只能跳转到startDestination ...

December 14, 2021 · 1 min · jiezi

关于android:Android入门教程-Audio-音频一

音频 PCM 数据的采集和播放,读写音频 wav 文件应用 AudioRecord 和 AudioTrack 实现音频 PCM 数据的采集和播放,并读写音频wav 文件 筹备工作Android 提供了 AudioRecord 和 MediaRecord。MediaRecord 可抉择录音的格局。 AudioRecord 失去 PCM 编码格局的数据。AudioRecord 可能设置模拟信号转化为数字信号的相干参数,包含采样率和量化深度,同时也包含通道数目等。PCM PCM 是在由模拟信号向数字信号转化的一种罕用的编码格局,称为脉冲编码调制,PCM 将模拟信号依照肯定的间距划分为多段,而后通过二进制去量化每一个间距的强度。 PCM 示意的是音频文件中随着工夫的流逝的一段音频的振幅。Android 在WAV 文件中反对 PCM 的音频数据。 WAV WAV,MP3 等比拟常见的音频格式,不同的编码格局对应不通过的原始音频。为了不便传输,通常会压缩原始音频。 为了分别出音频格式,每种格局有特定的头文件(header)。 WAV 以 RIFF 为规范。RIFF 是一种资源替换档案规范。RIFF 将文件存储在每一个标记块中。 根本形成单位是trunk,每个 trunk 由标记位,数据大小,数据存储,三个局部形成。 PCM 打包成 WAV PCM 是原始音频数据,WAV 是 windows 中常见的音频格式,只是在 pcm 数据中增加了一个文件头。 起始地址占用空间本地址数字的含意00H4byteRIFF,资源交换文件标记。04H4byte从下一个地址开始到文件尾的总字节数。高位字节在前面,这里就是001437ECH,换成十进制是1325036byte,算上这之前的8byte就正好1325044byte了。08H4byteWAVE,代表wav文件格式。0CH4byteFMT ,波形格局标记10H4byte00000010H,16PCM,我的了解是用16bit的数据表示一个量化后果。14H2byte为1时示意线性PCM编码,大于1时示意有压缩的编码。这里是0001H。16H2byte1为单声道,2为双声道,这里是0001H。18H4byte采样频率,这里是00002B11H,也就是11025Hz。1CH4byteByte率=采样频率*音频通道数*每次采样失去的样本位数/8,00005622H,也就是22050Byte/s=11025 * 1 * 16/220H2byte块对齐=通道数*每次采样失去的样本位数/8,0002H,也就是 2 == 1 * 16/822H2byte样本数据位数,0010H即16,一个量化样本占2byte。24H4bytedata,一个标记而已。28H4byteWav文件理论音频数据所占的大小,这里是001437C8H即1325000,再加上2CH就正好是1325044,整个文件的大小。2CH不定量化数据AudioRecord AudioRecord 可实现从音频输出设施记录声音的性能。失去PCM格局的音频。 读取音频的办法有 read(byte[], int, int), read(short[], int, int) 或 read(ByteBuffer, int)。 可依据存储形式和需要抉择应用这项办法。 ...

December 14, 2021 · 7 min · jiezi

关于android:Android-Camera-Framework层分析

Camera利用调用Framework Camera类API在Android Kitkat原生Camera2利用(packages/apps/Camera2/)的PhotoModule, VideoModule, WideAnglePanoramaModule类中用CameraUtil.open()办法来关上Camera。而后顺次调 用:CameraHolder的open()办法,AndroidCameraManagerImpl的cameraOpen()方 法,CameraHandler的handleMessage()【message为OPEN_CAMERA】,直到调用Framework Camera类(frameworks/base/core/java/android/hardware/Camera.java)的open()方 法。在这里,Camera2应用程序暂不做剖析,咱们着重看程序向下调用的服务申请过程。 mCameraDevice = CameraUtil.openCamera( mActivity, mCameraId, mHandler, mActivity.getCameraOpenErrorCallback()); // (1)public class CameraUtil { public static CameraManager.CameraProxy openCamera( Activity activity, final int cameraId, Handler handler, final CameraManager.CameraOpenErrorCallback cb) { try { throwIfCameraDisabled(activity); return CameraHolder.instance().open(handler, cameraId, cb); // (2) } catch (CameraDisabledException ex) { handler.post(new Runnable() { @Override public void run() { cb.onCameraDisabled(cameraId); } }); } return null; }}public class CameraHolder { public synchronized CameraProxy open( Handler handler, int cameraId, CameraManager.CameraOpenErrorCallback cb) { ………… if (mCameraDevice == null) { Log.v(TAG, "open camera " + cameraId); if (mMockCameraInfo == null) { mCameraDevice = CameraManagerFactory .getAndroidCameraManager().cameraOpen(handler, cameraId, cb); // (3) ………… } else { ………… } mCameraOpened = true; mHandler.removeMessages(RELEASE_CAMERA); ………… return mCameraDevice; }}class AndroidCameraManagerImpl implements CameraManager { public CameraManager.CameraProxy cameraOpen( Handler handler, int cameraId, CameraOpenErrorCallback callback) { mCameraHandler.obtainMessage(OPEN_CAMERA, cameraId, 0, CameraOpenErrorCallbackForward.getNewInstance( handler, callback)).sendToTarget(); // (4) ………… }} private class CameraHandler extends Handler { @Override public void handleMessage(final Message msg) { try { switch (msg.what) { case OPEN_CAMERA: mCamera = android.hardware.Camera.open(msg.arg1); // (5) ………… return; } } } }JNI层调用 ...

December 14, 2021 · 4 min · jiezi

关于android:更好地适配大屏幕设备-2021-Android-开发者峰会

作者 / 工程经理 Clara Bayarri 往年的 Android 开发者峰会 带来了许多 Android 大屏幕设施开发 的最新资讯,包含可折叠设施和平板电脑上的 Android 12L 性能更新 的一系列内容: 针对大屏幕设施优化的 Android 12 零碎性能、更好的开发者工具以及专为大屏幕设施提供的 Google Play 更新。接下来,咱们将为您介绍 Android 大屏幕设施开发的三项重要更新。 实用于大屏幕设施的 Android 12L 性能更新Android 12L 让 Android 12 在大屏幕设施上的体现更加杰出,告诉和锁屏等界面均已实现一系列优化。针对开发者而言还蕴含以下重要内容: 从新强调多任务处理,这意味着所有的利用当初都能够进入分屏模式,无论它们是否能够调整大小;针对兼容模式的更新改良;新的 Activity Embedding API,让您能够同时显示多个 Activity,从而更轻松地在现有利用中构建大屏幕设施优化布局。理解更多最新消息,您能够观看下方 "大屏幕设施和可折叠设施的新性能" 的介绍视频或查看咱们之前的推文《详解 Android 12L|更好地适配大屏幕设施》。 更轻松地构建大屏幕设施Android 判若两人的反对大屏幕设施,当初咱们公布了几个新工具来帮忙您扩大利用界面,以适应更大屏幕的设施类型。 针对大屏幕设备设计的新 Material Design 指南,蕴含生态系统中常见的 布局模式 的定义,有助于激发您的利用设计灵感;窗口大小类 (Window Size Classes) 是一种新型断点框架,其代表了生态系统中典型设施场景的大多数状况更新 SlidingPaneLayout 以反对导航;新的 Compose API 让开发自适应和响应式 UI 变得简略,包含对 导航栏 的反对;Android Studio 参考设施,一组新的设施配置文件,代表了生态系统中最宽泛的设施测试范畴;Android Studio 布局验证 (Layout Validation) 引入一个新的可视化的 lint 工具,用以检测大屏幕设施布局问题;全新的可调整大小模拟器,能够在参考设施间迅速切换。欢迎您观看 "为任何尺寸的屏幕构建 Android 界面" 和 "在可折叠设施和大屏幕设施上设计精美利用" 的技术分享视频,理解对于这些我的项目的更多信息。您还能够查看最新的 大屏幕设施指南 和 在 Compose 中构建自适应布局指南,理解更多相干信息。您也能够查看 "可折叠设施上视频利用的最佳实际" 和 "Android 开发者故事: 助力 Spotify 构建跨设施利用" 视频,理解如何让利用适配大屏幕设施。 ...

December 14, 2021 · 1 min · jiezi

关于android:Activity之间的通信

假如咱们有这样一个罕用的场景:有两个Activity,第一个Activity展现一段文本点击“编辑”按钮启动第二个Activity,并把这段文本当做参数传递到第二个Activity在第二个Activity编辑这个字符串编辑实现后点击保留将后果返回到第一个Activity第一个Activity展现批改后的字符串如下图: 这是一个非常简单和常见的场景,咱们个别通过 startActivityForResult 的形式传递参数,并在 onActivityResult 接管编辑后的后果,代码也很简略,如下: //第一个Activity启动编辑ActivitybtnEditByTradition.setOnClickListener { val content = tvContent.text.toString().trim() val intent = Intent(this, EditActivity::class.java).apply { putExtra(EditActivity.ARG_TAG_CONTENT, content) } startActivityForResult(intent, REQUEST_CODE_EDIT)} //EditActivity回传编辑后的后果 btnSave.setOnClickListener { val newContent = etContent.text.toString().trim() setResult(RESULT_OK, Intent().apply { putExtra(RESULT_TAG_NEW_CONTENT, newContent) }) finish()}//第一个Activity中承受编辑后的后果,并展现override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { when (requestCode) { REQUEST_CODE_EDIT -> { if (resultCode == RESULT_OK && data != null) { val newContent = data.getStringExtra(EditActivity.RESULT_TAG_NEW_CONTENT) tvContent.text = newContent } } else -> super.onActivityResult(requestCode, resultCode, data) }}那这种形式有什么毛病呢?代码扩散,可读性差封装不彻底,调用方须要到EditActivity能力晓得须要传递什么参数,类型是什么,key是什么调用方须要晓得EditActivity是如何返回的参数类型和key是什么能力正确解析约束性差,各种常量的定义(REQUEST\_CODE,PARAM\_KEY等),若项目管理不谨严,反复定义,导致前期重构和保护比拟麻烦那有没有一种形式能解决下面的毛病呢?咱们冀望的是:一个对外提供某些性能的Activity应该有足够的封装性,调用者像调用一般办法一样,一行代码即可实现调用办法的参数列表就是调用本服务须要传递的参数(参数数量,参数类型,是否必须)办法的返回参数就是本服务的返回后果提供服务的Activity像一个组件一样,能对外提供性能都是以一个个办法的模式体现通过Kotlin 协程和一个不可见的Fragment来实现。btnEditByCoroutine.setOnClickListener { GlobalScope.launch { val content = tvContent.text.toString().trim() // 调用EditActivity的 editContent 办法 // content为要编辑的内容 // editContent 即为编辑后的后果 val newContent = EditActivity.editContent(this@MainActivity, content) if (!newContent.isNullOrBlank()) { tvContent.text = newContent } }}通过下面的代码,咱们看到,通过一个办法即可实现调用,根本实现了上文提到的冀望。 那 editContent 办法外部是如何实现的呢?看如下代码: ...

December 14, 2021 · 2 min · jiezi

关于android:为什么有两年Android开发经验却抵不过一个实习生原因太现实

前言最近有一个敌人找到我,说他最近去阿里面试,没有通过。然而跟他一起面试的有一个实习生,被录取了。他说他学了两年的Android开发,有足够的教训,还做过一些我的项目,却抵不过一个没有教训的实习生,起初理解到起因是面试官问了他几个对于Android组件化的问题,刚好碰上他的弱点了。 听到他说的这些,我示意很感叹,当初安卓开发的前景和市场是处于向前倒退的趋势。大厂也对组件化这方面的问题比拟器重,他们更违心招聘有这方面技术的人才。为什么当初公司很重视组件化这个问题呢?举个例子来说,一个我的项目须要好几个业务代码,如果某一个业务代码出了问题,则须要在好几个当中去寻找,工程师须要理解各个业务的性能,防止代码的改变而影响其它的业务性能,势必无形中减少了我的项目保护的老本。如果让他们都绝对独立,咱们只须要保护好每个组件,须要用到该组件的性能时,一建援用集成就能够了。 近年来,为什么这么多团队要进行组件化实际呢?组件化到底能给咱们的工程、代码带来什么益处?咱们认为组件化可能带来两个最大的益处: 进步组件复用性可能有些人会感觉,进步复用性很简略,间接把须要复用的代码做成Android Module,打包AAR并上传代码仓库,那么这部分性能就能被不便地引入和应用。然而咱们感觉仅仅这样是不够的,上传仓库的AAR库是否不便被复用,须要组件化的规定来束缚,这样能力进步复用的便捷性。 升高组件间的耦合咱们须要通过组件化的规定把代码拆分成不同的模块,模块要做到高内聚、低耦合。模块间也不能间接调用,这须要组件化通信框架的反对。升高了组件间的耦合性能够带来两点间接的益处: 1.代码更便于保护;2.升高了模块的Bug率。所以说,学好组件化对一个开发工程师来说至关重要。我这里有一份高级Android组件化强化实战材料,心愿能帮到你们。 第一章 Android 组件化初识组件化和模块化的区别 组件化和插件化的区别 组件化开发的劣势 业务逻辑层 组件化开发要遇到的问题 从组件化实战来解决问题 Android 组件化根底 第二章 Android组件化初探组件化演示案例 概述 模块化和组件化 组件化Demo 组件application和library动静切换 WanAndroid APP 组件化我的项目实战(附demo) 简介 版本更新 效果图 次要性能 我的项目目录构造 次要开源框架 第三章 架构演变(大厂篇)组件化作为 Android 客户端技术的一个重要分支,近年来始终是业界积极探索和实际的方向。每个大厂外部的各个Android 开发团队也在尝试和实际不同的组件化计划,并且在组件化通信框架上也有很多高质量的产出。 从智行 Android 我的项目看组件化架构实际 组件化调整的起因和指标 组件化架构调整的整体规划 组件化架构调整中遇到的一些问题 组件化架构的实际成绩 失去 App Android彻底组件化demo公布 Android彻底组件化—代码和资源隔离 组件化:代码隔离也难不倒组件的按序初始化 微信 App 微信Android模块化架构重构实际 微信Android架构历史 为何再次重构微信 重塑模块化 取舍和抉择 代码之外,架构之内 蘑菇街 App 实现形式 组件生命周期治理 壳工程 遇到的问题 继续集成 周边设施 爱奇艺 App 对于组件化 ...

December 14, 2021 · 1 min · jiezi

关于android:高级工程师的不二之选Github常年霸榜的超强框架Retrofit

前言每个Android开发者在产品开发的过程中,都须要用到网络和服务器进行交互。而对于网络框架的应用和了解,往往能够看出一个开发者到底处于什么段位: 高级工程师:尽管也会应用OkHttp、Retrofit等框架,但根本都是机械的套用,对其源码、外围原理所知甚少,须要付出大量的工夫钻研源码。中级工程师:对于常见网络框架的外部原理有些理解,在我的项目开发过程中往往都能依据业务需要选用适合的框架。但遇到问题的时候还是常常须要寻求开源计划反对,通常这个时候他们会自行设计一个尽可能小的封装。高级工程师:个别会在我的项目中负责其架构选取的工作。他们对对http申请、线程池、缓存的常识了然于心,对网络框架的抉择规范,肯定是高性能,且简洁易用。所以基于OkHttp进行封装的Retrofit根本是他们的不二之选,且在反对converter扩大和rxjava,扩展性不好对他们高超的重构和封装技巧基本不是问题。而且对于Retrofit的核心思想熟络于心,能够很好地迁徙到其余的开发工作中。Retrofit为何成为高工最爱?作为最为宽泛应用的网络申请框架,OkHttp其实曾经十分弱小。然而在理论开发过程中,大家还是会遇到不少问题:无奈适配自动线程的切换、调用简单、网络申请接口配置繁琐、缓存生效……。而Retrofit的二次封装,能够很好地解决这些问题,为OkHttp锦上添花。 Retrofit是一个十分弱小的封装框架,能够配置不同HTTP client来实现网络申请,如OkHttp、httpclient等;能够定制申请办法的参数注解;能够同步或异步RxJava;轻松实现超级解耦;配置不同的反序列工具来解析数据,而且设计模式颇多,应用十分不便灵便: Retrofit没有扭转网络申请的实质,这部分仍旧由OkHttp实现。它最次要的特点在于设计模式十分丰盛,能够通过注解间接配置申请,能够适配不同的http客户端,而且通过不同的Json Converter 来序列化数据,同时对RxJava提供反对。所以Retrofit + OkHttp + RxJava是以后高工最钟意的一套框架。 但这套框架其实是有肯定门槛的,想要用好这套框架,对于Retrofit的外围原理肯定要非常相熟。 为什么举荐你学?当初BATJ等大厂的面试套路都是一样的:他们会让你谈谈Retrofit的具体应用,你有在本人的我的项目中应用过吗?而后扩大到和这个知识点相干的更深层次的知识点细节,会对Retrofit刨根问底: 用过哪些网络加载库?Retrofit外围实现原理?如果让你实现Retrofit的某些外围性能,你会思考怎么去实现?Retrofit的注解是怎么解析的 ?Retrofit网络申请层用的什么?Retrofit中应用了哪些设计模式?Retrofit在OkHttp上做了哪些封装?动静代理和动态代理的区别,是怎么实现的?Android开发Repository层如何拿到retrofit返回的数据?直到问的你答不上来为止,以此来探寻你的技术边际,这样就能更深刻地理解你的技术能力。其实,想要成为真正的高级架构师除了纯熟Retrofit外往往还须要把握其余框架常识。 如何学习Retrofit?其实很简略, 我这里有一份Android源码解析学习材料,心愿能帮忙大家更好地学习把握Retrofit的外围原理。 1.深刻解析 Retrofit 源码 2.与其余网络申请开源库比照 3.Retrofit 的实质流程 4.创立网络申请接口的实例 5.外观模式 因为篇幅较长,细节内容比拟多,临时只展现这些;有须要学习材料的敌人能够点击这里收费获取! 明天的文章就到这里,感谢您的浏览,喜爱的话不要忘了三连。大家的反对和认可,是我分享的最大能源。

December 14, 2021 · 1 min · jiezi