2021 - Android面试总结

212 阅读15分钟

ffmpeg: 

www.cnblogs.com/souther-blo…

blog.csdn.net/helimin1234…

shimo.im/docs/XvW3Wp…

m.nowcoder.com/discuss/450…

m.nowcoder.com/discuss/449…

m.nowcoder.com/discuss/446…

mp.weixin.qq.com/s?__biz=MzI…

blog.csdn.net/dream161110…

blog.csdn.net/qwas12345qw…

www.cnblogs.com/chihaoyuIsn…

blog.csdn.net/stonewang_l…

《View 绘制流程之 DecorView 添加至窗口的过程》 www.jianshu.com/p/8ce6610d0…

《深入 Activity 三部曲(3)之 View 绘制流程》 www.jianshu.com/p/7e2a4eff2…

blog.csdn.net/javazejian/…

blog.csdn.net/u013651026/…

blog.csdn.net/CoderYue/ar…

blog.csdn.net/crazy_rain/…

blog.csdn.net/qq_17678217…

www.jianshu.com/p/146e5cec4…

www.jianshu.com/p/0f82b0650…

www.jianshu.com/p/4115bcf9f…

mp.weixin.qq.com/s?__biz=MzA…

mp.weixin.qq.com/s?__biz=MzA…

profile.zjurl.cn/rogue/ugc/p…

www.jianshu.com/p/176444063…

www.cnblogs.com/UncleWang00…

m.toutiaocdn.com/i6870373230…

www.jianshu.com/p/d53bf830f…

www.jianshu.com/p/157279e6e…

www.cnblogs.com/zhengbin/p/…

blog.csdn.net/u010648159/…

blog.csdn.net/augfun/arti…

www.jianshu.com/p/beaf4d595…

blog.csdn.net/chf11421521…

  • Activity的启动模式
  • Android IPC相关
  • Binder
  • ARouter原理
  • Retrofit原理
  • 如果设计一下Butterknife,会怎么做
  • volatile解决的问题,原理
  • sys和retreenlock的区别,用法,原理
  • jvm中会发生oom的区域
  • 怎么找两个单链表相交的节点
  • okhttp原理
  • gradle插件原理
  • 热修复原理
  • 性能优化相关(问了很多,基本所有的都涉及到了)
  • 算法:打印出2-100的质数(双重for循环就行)

www.jianshu.com/p/c2ab7131c…

www.cnblogs.com/jymblog/p/1…

blog.csdn.net/w2064004678…

事件分发/view的绘制流程/apk打包流程/apk安装流程/binder

www.cnblogs.com/jycboy/p/62…

blog.csdn.net/weixin_4433…

juejin.cn/post/684490…

blog.csdn.net/hesong1120/…

blog.csdn.net/u014133119/…

blog.csdn.net/xiao_nian/a…

www.cnblogs.com/fomin/p/101…

www.cnblogs.com/jymblog/p/1…

www.cnblogs.com/jymblog/p/1…

mp.weixin.qq.com/s?__biz=MzA…

mp.weixin.qq.com/s?__biz=MzA…

github.com/Tencent/mat…

github.com/274942954/A…

美团面试(难)

blog.csdn.net/qzqanzc/art…

www.cnblogs.com/qitian1/p/6…

www.jianshu.com/p/4f16421d5…

jianshu.com/p/953475cea991

启动activity的请求会有Instrumentation来处理,然后它通过Binder向AMS发请求,AMS内部维护这一个ActivityStack并负责栈内的activity的状态同步,AMS通过ActivityThread去同步activity的状态从而完成生命周期方法的调用

blog.csdn.net/lk2021991/a…

www.jianshu.com/p/7c4e6687e…

www.jianshu.com/u/066678cb2…

www.jianshu.com/p/59d98244f…

www.jianshu.com/p/29bf7a094…

www.jianshu.com/p/d11a6da8b…

www.jianshu.com/p/875cb4bd8…

blog.csdn.net/mq285699271…

  •   1:你是如何理解Android操作系统的。
  •   2:是否熟悉framework层,如果熟悉,那就对framework做个简介。
  •   3:是否熟悉多线程,如果熟悉,介绍下线程。
  •   4:对象锁和类锁是否会互相影响,会举例子让你判断锁的使用是否恰当,并说出原因。
  •   5:是否熟悉Lopper架构,如果熟悉说下其原理,如果你自己实现,你会怎么实现。这里主要考察阻塞消息队列原理,和其变形。
  •   6:自定义控件原理,及消息分发流程。
  •   7:binder工作原理。
  •   8:ActivityThread,Ams,Wms的工作原理。
  •   9:如果工作中需要修改framework,你如何寻找切入点。

blog.csdn.net/zhujohnle/a…

blog.csdn.net/qq_31339141…

www.jianshu.com/p/a1d208e1e… www.jianshu.com/p/a0806d5f1… www.jianshu.com/p/9e042b33e… www.jianshu.com/p/6ca1f7a06…

www.cnblogs.com/wytiger/p/6…

www.jianshu.com/p/70a1c13b9…

m.toutiao.com/i6917532969…

  • 1、intercept 和 netIntercept的区别
  • 2、调用其他应用是否是一个栈
  • 3、自定义view/handleThread
  • 4、okhttp加载request流程
  • 5、如何保证looper的唯一性
  • 6、handler在编译器中为什么会报错
  • 7、handler如何防止内存泄漏
  •     静态内部类不持有外部类的引用
  •     弱引用
  •     页面销毁移除消息
  • 8、接口和抽象类的区别
  • 9、锁sync 对静态方法加锁和对普通方法加锁的区别
  • 10、一个数组构造两个栈
  • 11、如何保证下载的文件完整性
  • 12、java集合   hashMap某些参数含义 集合中的size含义 Android的某些集合
  • 13、线程安全 sync和votile 单例 枚举 
  • 14、网络 retrfit 如何进行网络环境切换
  • 15、view绘制流程
  • 16、自己画个圆角控件 glide 圆角怎么设置的 内存管理原理 
  • 17、Android 启动模式 生命周期 跳转页面生命周期切换
  • 18、api和implement、如何进行组件开发调试
  • 19、view的post
  • 20、事件传递,如何解决事件冲突
  • 21、recycleview 滑动不复用怎么设置
  • 22、点击事件是如何让传递给phoneWindow的

二面:(过)

  • 24、线程间通讯
  • 25、aar内存泄漏-排查
  • 26、RN和原生交互方式
  • 27、manifest文件合并策略:blog.csdn.net/u013803839/…
  • 28、工程优化
  • 29、java多态
  • 30、trace文件
  • 31、tcp:www.cnblogs.com/bj-mr-li/p/…
  • 32、handler延时消息不准怎么办
  • 33、RN能不能直接进行权限申请
  • 34、性能优化

美团面试(难)(挂)

小红书一面(过)

小红书二面

  • apk打包流程
  • .java、.class和.dex文件区别

跟谁学一面

  • 1、Fragment为什么需要无参构造方法 Fragment和Activity交互setArgment()方法

因为Activity横竖屏切换的时候,会重新构造Fragment,默认调用的就是Fragment的无参构造方法。如果通过 setArguments来传递参数的话,Activity在构造Fragment时会通过反射无参构造实例化一个新的Fragment,并且给mArgments初始化为原先的值。如果参数是通过构造方法传递的,在重新构造Fragment实例之后,数据就丢失了。

  • 2、application的context能不能启动activity blog.csdn.net/cyuyanshuju…
  • 3、什么情况下会导致栈溢出
  • 如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常。 
  • 如果虚拟机在动态扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常
  • 4、图解HTTPS建立过程 www.jianshu.com/p/2ac9297e0…
  • 5、AsyncTask 异步任务 但是任务默认是不并发 串行执行
  • 6、okhttp 框架 zhuanlan.zhihu.com/p/114623692
  • 7、HTTP和HTTPS协议,看一篇就够了 blog.csdn.net/xiaoming100…
  • 8、recycleview中刷新 
  •   adapter.notifyItemChanged(int position,R.id.**);
  •   adapter.notifyItemChanged(int position);

跟谁学二面:项目

soul

1、通过gradle生成apk的过程 blog.csdn.net/KyleWo/arti… 2、Android 高清加载巨图方案 拒绝压缩图片 blog.csdn.net/lmj62356579…

蚂蚁一面:只问项目

蚂蚁二面

  • 1、装饰者模式和继承的区别
  • 2、shareperfence和cotentprovider是否是线程安全的 都不是安全的
  • 3、service /数组链表/stringBuilder和stringBuffer
  • 4、ThreadLocal blog.csdn.net/qq_26988127…

滴滴一面

静态代理的优缺点

优点

静态代理对客户(测试类)隐藏了被代理类接口(目标类接口)的具体实现类,在一定程度上实现了解耦合,同时提高了安全性!

缺点

  1. 静态代理类需要实现目标类(被代理类)的接口,并实现其方法,造成了代码的大量冗余。
  2. 静态代理只能对某个固定接口的实现类进行代理服务,其灵活性不强。故一般大项目不会选择静态代理。

动态代理的优缺点

优点

  1. 动态代理实现了只需要将被代理对象作为参数传入代理类就可以获取代理类对象,从而实现类代理,具有较强的灵活性。
  2. 动态代理的服务内容不需要像静态代理一样写在每个代码块中,只需要写在invoke()方法中即可,降低了代码的冗余度。

缺点

动态代理类仍然需要实现接口。

java 装饰者模式与继承的区别

装饰者模式目标

把许多要实现的功能,加载在子类上,类的继承,显得很臃肿,装饰着模式是在不改变原有类文件和使用继承的情况下,通过创建一个包装对象动态地扩展一个对象的功能,相比生成子类更为灵活 装饰者模式角色 * 抽象组件角色 给出一个抽象接口 * 具体组件角色 定义一个将要增加附加功能的类,相当于父类 * 抽象装饰者角色 持有一个组件对象的实例,并且实现抽象组件接口 * 具体装饰者角色 负责给组件对象添加附加的功能,相当于子类

装饰者模式和继承的区别

继承实现的增强类:

  • 优点:代码结构清晰,而且实现简单
  • 缺点:对于每一个的需要增强的类都要创建具体的子类来帮助其增强,这样会导致继承体系过于庞大。

装饰模式实现的增强类:

  • 优点:内部可以通过多态技术对多个需要增强的类进行增强 
  • 缺点:需要内部通过多态技术维护需要增强的类的实例。进而使得代码稍微复杂。

接口和抽象类的区别

相同点

  1. 都不能被实例化 
  2. 接口的实现类或抽象类的子类都只有实现了接口或抽象类中的方法后才能实例化。

不同点

  1. 接口只有定义,不能有方法的实现,java 1.8中可以定义default方法体,而抽象类可以有定义与实现,方法可在抽象类中实现。
  2. 实现接口的关键字为implements,继承抽象类的关键字为extends。一个类可以实现多个接口,但一个类只能继承一个抽象类。所以,使用接口可以间接地实现多重继承。
  3. 接口强调特定功能的实现,而抽象类强调所属关系。
  4. 接口成员变量默认为public static final,必须赋初值,不能被修改;其所有的成员方法都是public、abstract的。抽象类中成员变量默认default,可在子类中被重新定义,也可被重新赋值;抽象方法被abstract修饰,不能被private、static、synchronized和native等修饰,必须以分号结尾,不带花括号。

synchronized和volatile区别

  1. volatile本质是告诉JVM当前变量在寄存器中的值是不确定的,需要从主存中读取,synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
  2. volatile仅能用在变量级别,而synchronized可以使用在变量、方法、类级别。 4. volatile仅能实现变量的修改可见性和有序性,不能保证原子性;而synchronized则可以保证变量的修改可见性、有序性和原子性。
  3. volatile不会造成线程阻塞,synchronized可能会造成线程阻塞。
  4. volatile标记的变量不会被编译器优化,synchronized标记的变量可以被编译器优化。

volatile不能保证原子性的原因

线程A修改了变量还没结束时,线程B可以看到已修改的值,而且可以修改这个变量,而不用等A结束,是因为volatile变量没上锁。

谈谈synchronized与ReentrantLock的区别?:zhuanlan.zhihu.com/p/126085068

Dalvik和Art的区别

即Android Runtime,Android 4.4发布了一个ART运行时,准备用来替换掉之前一直使用的Dalvik虚拟机。
ART 的机制与 Dalvik 不同。在Dalvik下,应用每次运行的时候,字节码都需要通过即时编译器(just in time ,JIT)转换为机器码,这会拖慢应用的运行效率,而在ART 环境中,应用在第一次安装的时候,字节码就会预先编译成机器码,使其成为真正的本地应用。这个过程叫做预编译(AOT,Ahead-Of-Time)。这样的话,应用的启动(首次)和执行都会变得更加快速。

Dalvik与Art的区别

  1. Dalvik每次都要编译再运行,Art只会首次启动编译
  2. Art占用空间比Dalvik大(原生代码占用的存储空间更大),就是用“空间换时间”
  3. Art减少编译,减少了CPU使用频率,使用明显改善电池续航
  4. Art应用启动更快、运行更快、体验更流畅、触感反馈更及时 www.cnblogs.com/chenxibobo/…

Dalvik和JVM的区别?

  1. Dalvik VM和JVM 的第一个区别是 Dalvik VM是基于寄存器的架构(reg based),而JVM是栈机(stack based)。reg based VM的好处是可以做到更好的提前优化(ahead-of-time optimization)。另外reg based的VM执行起来更快,但是代价是更大的代码长度。
  2. Dalvik 经过优化,允许在有限的内存中同时运行多个虚拟机的实例,并且每一个Dalvik 应用作为一个独立的Linux 进程执行。独立的进程可以防止在虚拟机崩溃的时候所有程序都被关闭。 3. Dalvik执行.dex格式的字节码,而JVM执行.class格式的字节码;dex字节码和标准Java的字节码(Class)在结构上的一个区别是dex字节码将多个文件整合成一个,这样,除了减少整体的文件尺寸,I/O操作,也提高了类的查找速度。 原来每个类文件中的常量池现在由DEX文件中一个常量池来管理。
  3. Dalvik虚拟机有自己的 bytecode, 并非使用 Java bytecode.
  4. DVM的特点在于使用了Zygote, ,它是虚拟机实例的孵化器。它在系统启动的时候就会产生,它会完成虚拟机的初始化,库的加载,预制类库和初始化的操作。如果系统需要一个新的虚拟机实例,它会迅速复制自身,以最快的速度提供给系统。对于一些只读的系统库,所有虚拟机实例都和Zygote共享一块内存区域。

int w = View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED);
int h = View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED);
textView.measure(w, h);
int width =textView.getMeasuredWidth();
int height =textView.getMeasuredHeight();

requestLayout 和 invalidate

requestLayout 和 invalidate 都会触发整个绘制流程。但是在 measure 和 layout 过程中,只会对 flag 设置为 FORCE_LAYOUT 的情况进行重新测量和布局,而 draw 只会重绘 flag 为 dirty 的区域。 requestLayout 是用来设置 FORCE_LAYOUT 标志,invalidate 用来设置 dirty 标志。所以 requestLayout 只会触发 measure 和 layout,invalidate 只会触发 draw; 1、不管大小变不变化,调用invalidate 只会执行onDraw绘制,调用了之后就会强制执行onDraw(),不管视图是否发生了变化。 2、调用requestLayout 会触发onMeasure重新测量,并调用布局onLayout重新布局,但不会调用onDraw,总结就是,控件布局没有变化时,执行invalidate就可以;如果控件布局位置变化了,但显示不变,例如平移,只需调用requestLayout 就可以;如果位置变化了,显示也不一样了,那就要同时调用,调用顺序一般是requestLayout ,然后invalidate

EventBus

EventBus是一款针对Android优化的发布/订阅(publish/subscribe)事件总线。主要功能是替代Intent,Handler,BroadCast在Fragment,Activity,Service,线程之间传递消息。简化了应用程序内各组件间、组件与后台线程间的通信。优点是开销小,代码更优雅,以及将发送者和接收者解耦。比如请求网络,等网络返回时通过Handler或Broadcast通知UI,两个Fragment之间需要通过Listener通信,这些需求都可以通过EventBus实现。

JVM中GC Root对象有哪些?

  1. 虚拟机栈中引用的对象;(栈中包括局部变量表和操作数栈,局部变量表中的变量可能为引用类型(reference),他们引用的对象即可作为GC Root)
  2. 方法区中类静态属性引用的对象;(类中使用的static声明的引用类型字段)
  3. 方法区中常量引用的对象;(类中使用final声明的引用类型字段)
  4. 本地方法栈中的引用的对象;(程序中native本地方法引用的对象)

JDK动态代理的实现原理:

  1. 拿到被代理对象的引用,然后获取他的接口
  2. JDK代理重新生成一个类,同时实现我们给的代理对象所实现的接口
  3. 把被代理对象的引用拿到了
  4. 重新动态生成一个class字节码
  5. 然后编译 就是实现java.lang.reflect.InvocationHandler接口,并使用java.lang.reflect.Proxy.newProxyInstance()方法生成代理对象 www.jianshu.com/p/895600700…

www.jianshu.com/p/366f418af…

www.jianshu.com/p/fbfec7678…

mp.weixin.qq.com/s/IIh2g1i6Y…

www.jianshu.com/p/36bb7cc23…

www.jianshu.com/p/7ee756b1f…

www.zhihu.com/question/23…

mp.weixin.qq.com/s?__biz=MzA…

mp.weixin.qq.com/s?__biz=MzA…

www.cnblogs.com/guoyaohua/p…

        int res = 0;
        for(int num : nums) {
            int i = 0, j = res;
            while(i < j) {
                int m = (i + j) / 2;
                if(tails[m] < num) i = m + 1;
                else j = m;
            }
            tails[i] = num;
            if(res == j) res++;
        }
        return res;

mp.weixin.qq.com/s?__biz=MzA…

zhuanlan.zhihu.com/p/114623692

blog.csdn.net/weixin_3982…

blog.csdn.net/weixin_3996…

www.jianshu.com/p/ca01b8559…

Leakcanary

查看Leakcanary官方的github仓库,最重要的便是对Leakcanary是如何起作用的(即原理)这一问题进行了阐述,把它翻译成了易于理解的文字,主要分为如下7个步骤:

RefWatcher.watch()创建了一个KeyedWeakReference用于去观察对象。

然后,在后台线程中,它会检测引用是否被清除了,并且是否没有触发GC。

如果引用仍然没有被清除,那么它将会把堆栈信息保存在文件系统中的.hprof文件里。

HeapAnalyzerService被开启在一个独立的进程中,并且HeapAnalyzer使用了HAHA开源库解析了指定时刻的堆栈快照文件heap dump。

从heap dump中,HeapAnalyzer根据一个独特的引用key找到了KeyedWeakReference,并且定位了泄露的引用。

HeapAnalyzer为了确定是否有泄露,计算了到GC Roots的最短强引用路径,然后建立了导致泄露的链式引用。

这个结果被传回到app进程中的DisplayLeakService,然后一个泄露通知便展现出来了。

官方的原理简单来解释就是这样的:在一个Activity执行完onDestroy()之后,将它放入WeakReference中,然后将这个WeakReference类型的Activity对象与ReferenceQueque关联。这时再从ReferenceQueque中查看是否有没有该对象,如果没有,执行gc,再次查看,还是没有的话则判断发生内存泄露了。最后用HAHA这个开源库去分析dump之后的heap内存。

blog.csdn.net/songzi1228/…