26岁,在外包公司干了三年的Android开发,于2021年5月办理完成所有离场手续,办完那一天,我像是终于解脱了,终于放下,也终于释怀。
这三年的时间,算是给我人生上了一课。文字可能会比较多,但大部分的情况都和全国99%的软件行业外包情况完全匹配。希望能给你们一些参考。
第一次进入外包公司
开始面试的时候,找了两个月,一开始外包公司直拒,投递了 Factory Club,中控,医惠科技等等,可是都没有回音。11 月份已经没有多少工作机会了,迫切的需要一份工作,于是海投,我进入第一家外包公司。
由于我这是第一次进外包公司,所以连薪水都没有多要,最后自己通过公司进入了工行杭研中心,开始外包的坑之路~~(签合同的时候,还签了保密协议!!)
入职体验很不好
加入之后的第一个项目是银行外包金融App项目,因为要汇报每日的开发进度,所以我们是驻场开发。
入职后,根本没人带,前期就是先进行一系列考试,什么安全培训、职业技能测验培训,培训完会有对应的考试。
当然了这些都是占用我们下班时间进行的,体验极差的一点就是,工行项目组长每天都会拉我们外包工开晨会,时间基本都快半小时了,就一圈人站在一块向组长汇报昨天的工作进度,今天的工作开展。
第二次外包经历
经历了一次外包,后来我辞职后就没找外包了,通过了广电运通的面试。
面试时候就感觉不靠谱,因为面试地点是位于近江附近的望江国际里面的温州银行,面试前网上搜了广电运通的信息,说是国企,所以我就硬着头皮接下 offer 了,没想到面试 Android 结果做的 C++,而且也是驻场开发。
入职一月半就又离职了,这时候我的简历就很糟糕了,8 个月的外包经历又加上近期工作只有一个半月,然后我又进了外包。这次是华为外包。
入职
技术面试只有一轮,是华为员工进行的电话面试,大概半个多小时,都是 Android 基础又常见的面试题,但是热修复、内存泄漏、内存优化、插件化、组件化、okhttp竟然一个问题都没问。
隔天,某软国际 hr 通知我面试通过,还要接受 hrbp 的电话面试。顺利结束后,给我发了链接是牛客 Android 在线笔试(感觉这个顺序给弄反了),然后就是到滨江这边的和瑞科技园签合同,hr 和我说,我要先去华为办公一个月再回和瑞科技园办公,我签的是 FP 模式,不是驻场开发。
前一个礼拜都在进行信息安全、网络安全等培训,培训通过后说是才给办华为工卡。
作为过来人的体会,外包被歧视真的是一个社会问题。
大家说是一个地方工作,但是那种隐形的阶级感是在的,就是有很多正式员工很有优越感去使唤外派员工。
实际上就是这样,外包人员不可能接触到核心一点的东西,内部的很多文档,点进去可能都没有权限。加班只能调休没有加班费。
有时候仔细想想,外包和大厂在智商上的差距有那么大吗?
辞去第二份外包工作之后,花了大量的时间复习准备面试。杭州的一二线公司基本上都去面试过了,包括阿里,字节,快手,滴滴,有赞,涂鸦,哈啰(腾讯没有客户端的hc),其中也拿了几个不错的offer。这里就简单分享下部分面试题和准备工作吧:
备战大厂
战况:
- 滴滴:二面挂
- 快手:一面挂
- 阿里:三轮技术面 + 一轮HR 面
- 有赞:三轮技术面 + 一轮HR 面
- 哈啰出行:三轮技术面 + 一轮HR 面
- 涂鸦智能:三轮技术面 + 一轮HR 面
- 字节跳动:三轮技术面 + 一轮HR 面
关于面试前的准备工作,首先就是先把简历给优化了,毕竟简历算的上是大厂面试的墙门转了。
写一份不被扔垃圾桶的简历
-
简约清晰:技术人的简历可以简约一点,简约不等于简单,你的项目经历和技术深度可以很深,但是体现在简历上一定高度概括,简历上不适合长篇大论的写记叙文,议论文。
-
突出重点:一份简历如果全文都是做了系统,参与了功能,面试官要自己找重点,所以最好简历直接开门见山,我在项目中扮演什么角色,搞了什么大事情,拿到什么结果,最好是带数据作为支撑的,有个词叫可量化,如果就是访问量小但流程复杂度高,你可以总结怎么做模块化开发、流程灵活性配置、效率提升等等,写到JVM 内存调优你可以写新生代/老年代内存回收时间提升了 **ms等等,这都是参考,可以辅助一些图或表在简历中,直观来说一图二表三文字,当然前提是你图表确实有亮点。
-
细节:细节决定成败,有几个细节要关注:1.不要有错别字;2.前后逻辑一致,数据不要自相矛盾;3.简历不要压缩、不要群发、邮件带正文介绍自己;4.排版干净清爽
由于本人之前的职级有点低,所以这次的目标岗位是P6+ ~ P7岗(虽然最终还是只拿到了P6+的岗位)。如果有高P的大佬,那么下面的面试题看看就好,意义不大。
滴滴
一面:
- 简单介绍下项目中遇到的难题,怎么解决的?
- 大图加载的优化方案
- java注解元注解有哪些,有什么区别
- 简要讲解下APT技术
- ButterKnife为什么在子module要用R2文件,子module为什么不能使用switch-case来对view的id进行区别处理
- Activity.getWindow什么时候为空
- Handler 发送延迟消息,是否一定会在指定时间以后执行。异步消息怎么判断。消息列表是按什么顺序排列
- Looper在没有消息时,怎么处理,如何进行线程阻塞
二面:
- 简要介绍下项目中的亮点
- 主线程修改UI为什么会导致崩溃,怎么解决的
- 为什么Android要设计单线程操作UI
- 简单介绍下Activity启动流程
- Handler机制原理, Looper的阻塞机制
- 内存优化做过哪些,用过哪些工具
快手面试
一面:
- 如何计算bitmap大小,如何检测bitmap是否超过了1M,并打印
- 如何给在ImageView里面展示一个带边框的bitmap
- Handler机制
- ANR有哪些,怎么监控
- LRUCache原理
- 什么情况下会出现ConcurrentModifyException,为什么会出现,怎么解决
- 线程池使用过没,有哪些参数,什么作用
- HashMap原理
- SparseArray的原理
- SparseArray和HashMap的查找和插入时间复杂度是多少
- Android打包流程, 字节码插桩在哪个流程中实现
- 热更新有了解过么,tinker的原理是什么,有什么缺点。 有没有其他框架没有这个缺点的,怎么实现的
- Http 1.0,Http1.1 ,Http 2.0的区别 keep-alive和多路复用有啥区别
- 了解过HttpDNS么,什么作用
- 手写一个生产者和消费者模型
阿里面试
一面:
- 卡顿检测怎么做的,为什么要这么做,会有兼容问题么
- 如果降低crash率的,有做哪些处理
- 觉得哪些东西做的比较好,说一下
- jsBridge是怎么实现的,如果客户端向前端发送消息怎么发送。
- 在图片框架选型的时候怎么考虑的,Fresco,Piccaso,Glide之间的优缺点
- 自定义一个从底部滑出的抽屉,该怎么做,需要有哪些考虑的点
- 一个简单的RecyclerView,说一下手势Down,Move,Up的分发。如果TextView上面设置了点击事件,那么分发逻辑是怎么样的
- 项目是怎么进行架构设计的
- 项目是否采用模块化处理,怎么做的,怎么进行交互
- git-merge和git-rebase的区别
二面:
- 现在项目的整体设计是怎么样的
- 降低crash率做了哪些处理
- 怎么检测线上卡顿问题
- kotlin相比于java有哪些优势
- 什么时机可以认为页面加载完成
- 内存优化有做过哪些
- 讲下merge和include
- 讲下运营商DNS劫持,又是如何防止DNS劫持
- 怎么使用Fragment的, 是采用一个Activity多个Fragment的形式么
- 有没有使用过一些跨端技术
三面:
- 项目合并做了哪些事情
- 怎么检测线上卡顿
- 怎么检测线上内存泄漏
- 做了哪些性能优化
- 最近研究了哪些新技术,谈谈看法
- 何如学习提高自己的技术
- 说说看自己的优劣势
- 对于现在做的产品有什么看法和见解,怎么看待竞品
有赞面试
一面:
- 组件化的架构怎么设计的
- 组件之间怎么通信,除了EventBus还有其他哪些了解过
- EventBus是怎么工作的
- Router框架怎么设计的
- LiveData为什么具有生命周期感知能力,如何实现的
- APT怎么实现,如何生成代码文件
- MVP与MVVM的区别
- MVP为什么会存在内存泄漏的可能,怎么解决
- 线程池的创建有哪些参数,有什么作用
- 有用过kotlin么?object关键主要应用在哪里? let和run的区别
- GC有哪些算法,现代虚拟机基本采用什么算法,为什么这么做
- Activity的启动流程
- 在APP进程还没创建的时候,会做哪些额外操作,app进程是谁创建的
- View是如何显示出来的
- 如何把像素点显示到屏幕上
- Glide三级缓存策略有了解过么
- Glide为什么会感知生命周期
- 做过哪些性能优化
- 最近写的这篇博客写的什么,遇到了什么问题,怎么解决
二面:
- 讲讲项目的组成
- retrofit2原理
- 用过rxjava2哪些操作符,zip什么作用。
- 热修复的原理
- APT技术怎么实现,如何理解AOP,有过哪些应用场景
- MVC,MVP,MVVM的区别
- 讲一下LiveData+ViewModel怎么实现生命周期, 屏幕旋转时,会保存数据么
- 有没有碰到过LiveData接收多次消息的问题,LiveData的postValue和setValue有什么区别,平时怎么使用
- glide怎么实现生命周期的监听
- 组件化的方案,如何提高编译效率
- 组件通信用的什么
- 有没有写过印象深刻的框架
- 平时周末会遇到线上事故么,怎么处理
- 平时开发过程怎么沟通协调,在里面作为什么角色存在。
三面:
- 讲一下你觉得成长最大的一个项目,为什么
- 组件化考虑的因素有哪些,为什么这么考虑,为什么使用AAR包就会提高编译效率
- 说一个你觉得做的比较好的点。
- 有没有跨端经验
- 有没有推动过项目的一些方案的制作和实施。讲一下怎么做的
哈啰出行
一面:
- 讲述一下自己做的最有亮点的项目
- view的绘制流程
- View的事件分发流程
- ViewPager内部嵌套同向RecyclerView,RecyclerView滑动与ViewPager滑动冲突解决方案
- 详细说下Handler机制
- Handler会存在哪些问题,怎么解决
- 设计模式用过哪些,简要讲述下最熟悉的几个设计模式,怎么设计,为什么这么设计
- APT怎么实现的,元注解什么作用。 IOC怎么实现
二面:
- 讲述一下自己项目亮点
- 讲一下路由框架的架构设计,路由还可以实现哪些功能
- 容灾方案怎么实现,怎么做降级处理,怎么做AbTest
- App Link有了解过没
- Handler的机制,如果取不到消息接下来怎么做。
- APP启动做过哪些优化,如果启动优化的负责人,你会怎么做
- Activity的冷启动流程
- Application由谁创建,Activity由谁创建。ContentProvider的onCreate发生在什么时候
- 热更新的原理,插件化的原理
三面:
- 讲述项目经历
- 讲一下自己觉得做得最好的地方
- 有做过哪些性能优化
- 让你负责埋点功能,你怎么设计实现
- leakcanary实现原理
- flutter有了解过么
- 讲当前部门的主要业务
字节跳动
一面:
- git cherry-pick 操作commit id一样么
- git merge和rebase的作用
- Fragment 如何传参的,有没有使用构造函数传参
- SurfaceView和View绘制上面的差别,可以设置层级么。 mediaOverlay什么作用
- 插件化和组件化的差别, 插件化的加载过程
- 长图加载解决方案 DecodeRegion的底层原理
- 算法:A方法返回0和1的概率是p和1-p, 设计一个算法让0和1返回的概率各是1/2
- opengl 顶点着色器, 片段着色器
- classLoader通过什么判断class是否已经加载到内存中
- 内存优化怎么做的
- 滑动冲突怎么解决 nestchild和nestparent如何实现手势分发
二面:
- OpenGLES 怎么使用
- 线程启动方式
- HandlerThread了解过么
- Synchronized原理,notify wait底层是怎么做的, 了解过锁的膨胀么
- CAS操作如何保证两个线程数据安全
- Dialog和Activity属于同一个window么,为什么
- 用过哪些设计模式
- 讲讲设计原则,项目里使用情况
- 讲讲现在项目里的网络库, OKHttp有哪些优势(相比较于以前的HttpClient和HttpUrlConnection)
- EventBus 内部使用什么样的数据结构保存,EventBus的优缺点
- Bitmap内存怎么计算 假设一个100*100的图片放入xxhdpi的文件夹,在720的手机上面显示,Config是ARGB8888。 内存大小多少
- 讲讲为什么使用MVVM,MVP为什么会出现内存泄漏, MVVM为什么不会出现内存泄漏
- VSync信号 什么作用 同步多次执行addView,removeView等UI操作为什么不会多次进行View的绘制
- 算法:如果将一串路径反转 例如 /a/b/././c/..d/e -> /e/d/c/b/a
三面:
- 自动登出如何处理的
- 登录之后页面,数据刷新怎么处理
- TCP和UDP的区别, 讲下视频通话中哪些用到了UDP,哪些用到了TCP
- Java的Thread是JVM创建的还是系统的
- Thread可以设置大小么
- JVM的内存回收算法
- View的onMeasure测量逻辑
- 解决过的难题
- 讲下mvvm的设计,与mvp相比优势是什么,如果用mvp如何防止内存泄露
- 100个人编号为1100,山洞有100盏灯,编号为1100。 人依次过山洞,当人经过【灯编号可以整除人编号】的路灯时,按下开关。假设刚开始灯都是灭的,那么100个人出去以后,有多少盏灯是亮着的。
- 给定两个职员,找出最近的公共上级 (树的最近公共祖先节点
总结
我一般都是建议不要去外包,不是我对外包有多大仇恨,也不是有意甩锅外包公司,人家也是企业,也是靠实力看市场来赚钱。曾经也在外包干过三年的我,三年一点成长没有(没精力,天天加班,也没空间提升,因为大家都是干着流水线式码农的工作),不是忙项目就是忙出差,真的废了的一踏糊涂。
眼下正值很多毕业生找工作的季节,对于初入社会的职场人来讲,第一份工作特别重要,它一定程度上决定了后面几年的路是怎么样的,是完美入场,还是完美入坑,区别还是很大的。
面试大厂无论如何,你回答的层面最好足够深,从源码层级说起来。有时候面试官的对问题的看法和你的看法有分歧,此时就需要你是否可以从源码的层面上对这些问题有自己的解释。
面试的时候只需要沉着冷静的思考,从源码的角度对面试官抛出来问题进行分析,就能比较轻松的解决。
技能储备冲击大厂
Android学习是一条漫长的道路,我们要学习的东西不仅仅只有表面的 技术,还要深入底层,弄明白下面的 原理,只有这样,我们才能够提高自己的竞争力,在当今这个竞争激烈的世界里立足。
如果你觉得自己学习效率低,缺乏正确的指导,可以参考下下面分享我多年工作以来收集整理的学习路线(详细扫描下面二维码获取详细版本),给大家做个参考:
接下来是每个模块我整理出来的文档学习资料,帮助大家更细致化的学习。
《Android汇总复习资料—Java》
《Android汇总复习资料—Android》
《Android汇总复习资料—Android扩展》
《Android汇总复习资料—Kotlin》
《Android汇总复习资料—Flutter》
《Android汇总复习资料—算法》
除了上面的学习路线,还可以额外的配合以下方式学习,效果翻倍~
①看视频进行系统学习
前几年的Crud经历,让我明白自己真的算是菜鸡中的战斗机,也正因为Crud,导致自己技术比较零散,也不够深入不够系统,所以重新进行学习是很有必要的。我差的是系统知识,差的结构框架和思路,所以通过视频来学习,效果更好,也更全面。关于视频学习,个人可以推荐去B站进行学习,B站上有很多学习视频,唯一的缺点就是免费的容易过时。
另外,我自己也珍藏了好几套视频,有需要的我也可以分享给你。
②读源码,看实战笔记,学习大神思路
“编程语言是程序员的表达的方式,而架构是程序员对世界的认知”。所以,程序员要想快速认知并学习架构,读源码是必不可少的。阅读源码,是解决问题 + 理解事物,更重要的:看到源码背后的想法;程序员说:读万行源码,行万种实践。
主要内含微信 MMKV 源码、AsyncTask 源码、Volley 源码、Retrofit源码、OkHttp 源码等等。
③面试前夕,刷题冲刺
面试的前一周时间内,就可以开始刷题冲刺了。请记住,刷题的时候,技术的优先,算法的看些基本的,比如排序等即可,而智力题,除非是校招,否则一般不怎么会问。
关于面试刷题,我个人也准备了一套系统的面试题,帮助你举一反三:
④2020大厂面试高频知识点
- 图片
- 网络和安全机制
- 数据库
- 插件化、模块化、组件化、热修复、增量更新、Gradle
- 架构设计和设计模式
- 性能优化
- Android Framework
- Android优秀三方库源码