插件化面试题Android进阶之路

有人说这是初级Android工程师的面经?吓到我了!

2019-11-28  本文已影响0人  Z_萧晓

本篇文章来自作者潇风寒月,文章主要介绍了他面试Android开发工程师整个过程中整理的知识体系,相信会对大家有所帮助!By the way,作者说这是初始Android工程师的面经,我认为可不是,这难度已经把我吓到了。。

Java基础

什么是乐观锁?

乐观锁:假设每次去拿数据都认为别人不会修改,所以不会上锁。但是在更新的时候会判断一下此期间别人有没有去更新这个数据。一般用在读比较多,写比较少的情况。

悲观锁:假设每次都是最坏情况,每次去拿数据时别人都会修改,所以每次拿数据的时候都会上锁,这样别人想拿这个数据就会被阻塞直到它拿到锁,多写少读时使用。

volatile关键字

  1. 保证可见性,不保证原子性
  2. 禁止指令重排序
  3. 不缓存,每次都是从主存中取

hashmap 原理,红黑树是什么?

红黑树

jvm内存分配

String,StringBuffer,StringBuilder 区别

String,StringBuffer,StringBuilder最终底层存储与操作的都是char数组。但是String里面的char数组是final的,而StringBuffer,StringBuilder不是,也就是说,String是不可变的,想要新的字符串只能重新生成String。而StringBuffer和StringBuilder只需要修改底层的char数组就行。相对来说,开销要小很多。

String的大多数方法都是重新new一个新String对象返回,频繁重新生成容易生成很多垃圾。StringBuffer是线程安全的,StringBuilder是线程不安全的,因为StringBuffer的方法是加了synchronized锁起来了的,而StringBuilder没有。增删比较多时用StringBuffer或StringBuilder(注意单线程与多线程)。实际情况按需而取吧,既然已经知道了里面的原理。

安卓基础

安卓各版本大变化(Android 6.0到10.0),兼容适配

Android 5.0

Android 6.0

Android 7.0

Android 8.0

Android 9.0

Android 10

热修复原理

原理

  1. 安卓在加载class时会通过双亲委托机制去加载一个类,先让父类去加载,如果找不到再让子类去加载某个类。

  2. 通过查看ClassLoader源码发现findClass方法是由每个子类自己实现的,比如BootClassLoader或者BaseDexClassLoader。而PathClassLoader是继承自BaseDexClassLoader的,它的findClass也是在BaseDexClassLoader里面实现的。

  3. BaseDexClassLoader的findClass里面使用了另一个对象DexPathList去查找对应的class,这是安卓里面特有的实现。在DexPathList对象里面有一个属性dexElements,dexElements是用于存放加载好了的dex数组的,查找class是从这个dexElements数组里面去找的。

  4. dexElements里面存放的是Element对象,findClass最终会交给Element去实现,Element又会交给Element里面的一个属性DexFile去实现。我看了下,最终是用native实现的。

  5. 回到上面的第3步中的DexPathList对象从dexElements数组里面查找class,从数组的前面往后找,找到了就返回结果,不再继续查找。

  6. 所以当我们把修复好bug了的class,搞成dex,然后通过反射等技术放到dexElements的最前面,这样系统在通过PathClassLoader找到class时,就能先找到我们放置的修复好bug的class,然后就不会再往后找了,相当于实现了热修复。这样有bug的class就不会被用了。应了一句古话,近水楼台先得月。

  7. 第6点中的反射,流程是:获取到PathClassLoader,然后反射获取到父类中的DexPathList对象,然后再反射到DexPathList对象中的dexElements数组。然后将补丁(dex)转为Element对象,插入到dexElements数组的前面(先复制出来,再合并,再通过反射放回去)。

一句话总结。将修复好的类放在dexElements的最前面,这样在加载类的时候就会被优先加载到而达到修复的目的。

MVC,MVP,MVVM

首先需要知道的是为什么要进行技术框架的设计?肯定是为了低耦合,提高开发效率是吧。所以不要为了设计而设计。

MVC

在Android中View和Controller一般就是被Activity充当了,当逻辑非常多,操作非常复杂时,Activity代码量非常庞大,不易维护。

MVP

我个人角度,现在(2019年10月29日20:02:49)大多是使用这种方式,既不复杂也解耦合了。

MVVM

为了更加分离M,V层,所以有了MVVM。

组件化的好处

  1. 任意修改都需要编译整个工程,效率低下。
  2. 解耦,有利于多人团队协作开发
  3. 功能复用

app启动流程

  1. Launcher startActivity
  2. AMS startActivity
  3. Zygote fork进程
  4. Activity main()
  5. ActivityThread 进程loop循环
  6. 开启Activity,开始生命周期回调…

Activity启动流程

  1. Activity startActivityForResult
  2. Instrumentation execStartActivity
  3. AMS startActivity
  4. ApplicationThread scheduleLaunchActivity
  5. ActivityThread.H handleMessage -> performLaunchActivity
  6. Activity attach
  7. Instrumentation callActivityOnCreate

app体积优化

可以使用lint工具,检测出没有用的文件。同时可以开启资源压缩,自动删除无用的资源。尽量多使用可绘制对象,某些图像不需要静态图像资源,框架可以在运行时动态绘制图像。尽量自己写Drawable,能不用UI切图就不用,占用空间小。

重用资源,比如一个三角按钮,点击前三角朝上代表收起的意思,点击后三角朝下,代表展开,一般情况下,我们会用两张图来切换,我们其实完全可以用旋转的形式去改变。比如同一图像的着色不同,我们可以用android:tint和tintMode属性,低版本可以使用ColorFilter。

压缩PNG和JPEG文件,可以减少PNG文件的大小,而不会丢失图像质量。使用WebP文件格式,可以使用WebP文件格式,而不是使用PNG或JPEG文件。可以使用AS将现有的BMP、JPG、PNG或静态GIF图像转换成WebP格式。使用矢量图形.svg;代码混淆,使用proGuard代码混淆器工具,它包括压缩,优化,混淆等功能。这个大家太熟悉。插件化,将功能模块放服务器上,按需下载,可以减少安装包大小。

app启动优化

利用提前展示出来的Window,快速展示出来一个节目,给用户快速反馈的体验。障眼法,治标不治本。

避免在启动时做密集沉重的初始化(Heavy app initialization)。某些SDK初始化放在异步去加载(比如友盟,bugly这样的业务非必要可以异步加载),比如地图,推送等,非第一时间需要的可以在主线程做延时启动(比如闪屏页),当程序已经启动起来之后,再进行初始化。对于网络,图片请求框架就必须在主线程中初始化了。启动时,避免I/O操作,反序列化,网络操作,布局嵌套等耗时操作。

app布局优化

app内存优化

频繁使用字符串拼接用StringBuilder或者StringBuffer;ArrayMap、SparseArray替换HashMap;避免内存泄漏。

内存泄漏有哪些

app线程优化

线程池避免存在大量的Thread,重用线程池内部的线程,从而避免了线程的创建和销毁带来的性能开销,同时能有效控制线程池的最大并发数,避免大量线程因互相抢占系统资源而导致阻塞线现象发生。

分类

优点

注意点

Android换肤如何实现,原理

重新设置LayoutInflater的Factory2,从而拦截创建View的过程,然后搞成自己的控件,想怎么换肤就怎么换肤。

fresco原理,glide原理,两者区别,哪个更省内存

这块暂时不懂,加入todo。

Handler原理,Android 消息机制

之前写过一篇文章,死磕Android_Handler机制你需要知道的一切,里面介绍得很详细,顺便说了一下为什么loop不会阻塞主线程问题。

Handler机制的关键在于对于ThreadLocal原理的理解,线程私有数据。利用ThreadLocal机制将Looper存放到线程内部,perfect !

Android 系统架构

应用层,应用框架层,系统运行库层,硬件抽象层和Linux内核层。

常用布局有哪些

Android数据存储有几种方式

View,SurfaceView

jni调用流程

我之前也写过简单的demo,JNI Java与C的相互调用与基本操作。

组件之间相互引用,如何解决

Android 数字签名

校验用户身份,校验数据的完整性。

fragment用在哪里,与Activity的区别

View绘制原理

主要是分析measure,layout,draw的过程,之前写过一篇比较完整的,如下。死磕Android_View工作原理你需要知道的一切:

https://blog.csdn.net/xfhy_/article/details/90270630

Retrofit和OkHttp原理,拦截器

点击事件传递机制,事件分为哪几种

事件传递大体过程:Activity--> Window-->DecorView --> View树从上往下,传递过程中谁想拦截就拦截自己处理。MotionEvent是Android中的点击事件。主要事件类型:

需要关注的几个方法。

上面3个方法可以用以下伪代码来表示其关系:

public boolean dispatchTouchEvent(MotionEvent ev) {
    boolean consume = false;//事件是否被消费
    if (onInterceptTouchEvent(ev)) {//调用onInterceptTouchEvent判断是否拦截事件
        consume = onTouchEvent(ev);//如果拦截则调用自身的onTouchEvent方法
    } else {
        consume = child.dispatchTouchEvent(ev);//不拦截调用子View的dispatchTouchEvent方法
    }
    return consume;//返回值表示事件是否被消费,true事件终止,false调用父View的onTouchEvent方法
}

anr如何产生,Service触发anr是多长时间(20秒),如何解决anr?如何解决那种莫名其妙的anr?

我觉得anr就是在主线程做了耗时操作,比如io、读写文件、数据库操作等等。anr发生之后一般会有日志,在/data/anr/traces.txt里面。可以参考我的这篇文章拿anr日志,Android 未root查看ANR异常:

https://blog.csdn.net/xfhy_/article/details/80223190

Dialog和Activity是同一个Window?

不是同一个。

Window,Activity,Dectorview之间的关系

Activity里面实例化了一个Window,Window里面有一个DecorView(根布局)。看一下这篇文章,Android Window机制探索:

https://blog.csdn.net/qian520ao/article/details/78555397

ConstraintLayout和RelativeLayout在绘制方面有何差别?

todo。

onClick事件和onTouchListener在哪里回调?

如果一个View需要处理事件,它设置了OnTouchListener,那么OnTouchListener的onTouch方法会被回调。如果onTouch返回false,则onTouchEvent会被调用,反之不会。在onTouchEvent方法中,事件为Action.UP的时候会回调OnClickListener的onClick方法,可见OnClickListener的优先级很低。

LinearLayout是如何测量(measure)的?如果有weight又是如何测量的?

先做一次测量,做完之后有空间剩余,有weight的View再测量一下,分一下剩余的空间。

屏幕适配

先前有鸿洋的AndroidAutoLayout,根据宽高进行控件缩放,非常经典,很多项目可能都还在使用,但是已经停止更新了。然后就是有名的今日头条方案,出来还是有点时间了。原理其实就是更改density。

屏幕的宽度=设计稿宽度 * density。

然后有AndroidAutoSize库,将今日头条方案融合进去还完善了很多问题,易用,完美。

其他

Java四种引用

项目中遇到的最困难的事情是什么?如何解决的?

每个人遇到的情况不同,这个提前思考一下自己做过的项目最有挑战的地方。

Kotlin优势

缺点就是有时候代码阅读性可能会降低。

Kotlin 协程是什么?

就是一个线程框架,提供了一套操作线程的api。

二叉树,广度优先遍历,深度优先遍历

推荐小灰的漫画算法。还有其他的一些,随便聊聊:

最后

有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。

对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!

文章中每一个部分都包含一系列BAT面试的面试点,这些点构建了一个完整的知识体系。后面,我会细化里面的知识,如果 大家觉得有问题,请联系我~

这里附上上述的技术知识点相关的几十套腾讯、头条、阿里、美团等公司19年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

相信它会给大家带来很多收获:

上述高清技术脑图以及配套的架构技术PDF可以简信我免费获取

当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。

上一篇 下一篇

猜你喜欢

热点阅读