Android高级面试题

三、高级开发技术面试题

这里讲的是大公司需要用到的一些高端Android技术,这里专门整理了一个文档,希望大家都可以看看。这些题目有点技术含量,需要好点时间去研究一下的。

(一)图片

1、图片库对比

目前通用的图片库是Glide和Picasso

库大小和方法数量:

对比两个jar库的大小,Glide要比Picasso大很多,基本上是Picasso的3.5倍

Picasso的方法大概有849个,Glide的方法大概有2678个

使用方式:

Android高级面试题_第1张图片
Android高级面试题_第2张图片

缓存大小:

Picasso是下载图片然后缓存完整的大小到本地,比如图片的大小是1080p,之后如果我需要同一张图片,就会返回这张full size的,如果我需要resize,也就是对这个full size做resize。

Glide则完全不一样的做法。Glide会先下载图片,然后改变图片的大小,以适应ImageView的要求,然后缓存到本地。如果下载同一个图片,但是设定两个不同大小的imageView,那么Glide实际是缓存两份。

内存使用:

同样格式的图片,Glide内存使用比Picasso小。

加载图片的时间:

当下载图片时,加载的速度Picasso是要比Glide快的,因为Glide需要进行改变图片的大小,然后缓存;如果已经缓存在内存中,Glide加载速度比Picasso要快,因为Picasso内存中的图片需要resize。

其他方面:

Glide支持gif

Glide更加灵活。

https://www.jianshu.com/p/fc72001dc18d

2、图片库的源码分析

https://blog.csdn.net/guolin_blog/article/details/53759439

3、图片框架缓存实现

Glide将缓存分成了两个模块,一个是内存缓存,一个是硬盘缓存。

这两个缓存模块的作用各不相同,内存缓存的主要作用是防止应用重复将图片数据读取到内存中,而硬盘缓存的主要作用是防止应用重复从网络或其他地方重复下载和读取数据。

https://blog.csdn.net/guolin_blog/article/details/54895665

4、LRUCache原理

LRUCache的核心思想就是维护一个缓存对象列表,其中对象列表的排列方式是按照访问顺序实现的,即一直没有访问的对象放在队尾,即将被淘汰。而最近访问的对象将放在队头,最后被淘汰。

Android高级面试题_第3张图片

https://www.jianshu.com/p/b49a111147ee

5、图片加载原理

(1)、图片Drawable其实只是一个加载图片的工具,并不是一张图片;它可以加载xml文件,解析出我们的图,也可以从drawable文件夹中加载图片处理交给画布画。

(2)、主流的图片加载原理其实都用到了缓存:内存缓存、活动缓存、磁盘缓存等等,首先都是从缓存中获取到,如果没有再从网络下载数据到本地加载;最终的形式都是将文件解析成Bitmap加载到图片上。

6、自己去实现图片库,怎么做?

7、Glide源码解析

8、Glide使用什么缓存?

内存缓存和硬盘缓存

9、Glide内存缓存如何控制大小?

(二)网络和安全机制

1、网络框架对比和源码分析

优先使用Retrofit,前提是后台最好是支持Restful风格,如果不想使用或没有能力掌握,则推荐使用Volley,如果需要上传大量的数据,则不推荐使用volley,推荐使用okhttp。

Retrofit整个项目使用的动态代理和静态代理

2、自己去设计网络请求框架,怎么做?

网络请求框架的核心就是封装了网络请求+异步+数据处理

其中网络请求一般使用Android的网络请求原生方法(HttpClient或HttpURLConnection)

Android高级面试题_第4张图片

一般而言,我们需要考虑的方面有:

1、构建我们的请求Request:包含url,请求方法,请求参数,请求头,编码,请求体,编码格式,超时时间,代理端口,代理主机等。

2、由Dispatcher分发器并行分发我们的Request请求,这里的分发器实际是一个线程池。

3、准备开始连接服务器,连接http获取https服务器地址,https需要考虑自签名证书、双向SSL验证等安全问题。

4、Response得到服务器的回调,考虑输入流关闭的问题,大文件传输的问题,线程切换问题,缓存问题。

3、okhttp源码

https://www.jianshu.com/p/5b7ccc7e5bb7

4、网络请求缓存处理,okhttp如何处理网络缓存的

okHttp缓存流程分为读取缓存和存储缓存两个过程。

读取使用缓存的流程从HttpEngine的sendRequest发送请求开始。

(1)、首先,获取OkHttpClient的Cache缓存对象,就是之前创建OkHttpClient时设置的Cache。

(2)、然后传入Request请求到Cache的get方法去查找缓存响应数据Response.

(3)、构造一个缓存策略,传入Request请求和缓存响应Response,然后调用它的get方法去决策使用网络请求还是缓存响应。

(4)、策略判定以后,如果是使用缓存,它的cacheResponse不为空,networkRequest为空,如果使用请求,则相反。然后再将策略给出的两个值,继续处理。

(5)、如果使用请求,但是之前又找到了缓存响应,则要关闭缓存响应资源。

(6)、如果策略得出缓存响应为空,网络请求也为空,则返回请求不合理的响应。

(7)、如果请求为空,缓存不为空,也就是使用缓存的情况,则使用缓存响应来构造返回的响应数据。

(8)、最后只使用网络请求的情况,走网络请求的路线。

总结:先查找是否有可用的Cache,然后通过Cache找到对应的缓存,然后将请求和缓存交给缓存策略去判断使用请求还是使用缓存,得出结果后,自己再判断使用缓存还是使用请求,如果使用缓存,则用缓存构造响应直接返回,如果使用请求,那么开始网络请求流程。

OkHttp的存储缓存流程是从HttpEngine的readResponse发送请求开始的。

https://www.jianshu.com/p/00d281c226f6

5、从网络加载一个10M的图片,说下注意事项

需要注意开启子线程加载,需要注意内存是否会溢出。

6、TCP的3次握手和四次挥手

Android高级面试题_第5张图片

上图包括三个部分:建立连接,数据传输,断开连接

第一次握手:客户端发送syn包(seq = x)到服务器,并进入SYN_SENT状态,等待服务器确认;第二次握手:服务器收到syn包,必须确认客户的SYN(ack = x+1),同时自己也发送一个SYN包(seq = y),即SYN+ACK包,此时服务器进入SYN_RECV状态;第三次握手:客户端收到服务器的SYN+ACK包,向服务器确认包ACK(ack = y+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

四次挥手

第一次挥手:主动关闭方发送一个FIN,用来关闭主动方到被动方的数据传输,也就是主动关闭方告诉被动关闭方:我已经不会再给你发送数据了(当然,在FIN之前发送出去的数据,如果没有收到对应的ack确认报文,主动关闭方依然会重发这些数据),但此时主动关闭方还可以接收数据。

第二次挥手:被动关闭方收到FIN包后,发送一个ACK给对方,确认序号为收到序号加1(与SYN相同,一个FIN占用一个序号)。

第三次挥手:被动关闭方发送一个FIN,用来关闭被动关闭方到主动关闭方的数据传输,也就是告诉主动关闭方,我的数据也发送完了,不会再给你发送数据了。

第四次挥手:主动关闭方收到FIN后,发送一个ACK给被动关闭方,确认序号为收到的序号+1,致此完成四次挥手。

7、TCP与UDP的区别

(1)、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接。

(2)、TCP提供可靠服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付。

(3)、TCP面向字节流,实际上是TCP把数据看成了一连串无结构的字节流;UDP面向报文的,UDP没有拥塞控制,因此,网络出现拥塞不会使源主机的发送效率降低(对实时应用很有用,如IP电环,实时视频会议等)

(4)、每一条TCP连接只能是点对点的;UDP支持一对一,一对多,多对一和多对多交互通信。

(5)、TCP首部开销20字节;UDP的首部开销小,只有8个字节;

(6)、TCP的逻辑通信信道是全双工的可靠信道;UDP则是不可控信道。

8、TCP与UDP的应用

当对网络通信质量有要求时,比如:整个数据要准确无误的传递给对方,这往往需要可靠的传输协议

如:浏览器使用的HTTP,FlashFXP使用ftp,QQ文件传输等

对当前网络通信质量要求不高的时候,要求网络通讯速度尽量的快,这就使用UDP,如:QQ语音,QQ视频,TFTP

9、HTTP协议

Http协议是超文本传输协议。

http请求分成三个部分,分别是请求行,消息报头,请求正文

10、HTTP1.0与2.0的区别

HTTP1.0:浏览器每次请求都需要与服务器建立一个TCP连接,服务器处理完成后立即断开TCP连接(无连接),服务器不跟踪每个客户端也不记录过去的请求(无状态)

HTTP2.0:HTTP2.0引入了二进制数据帧和流的概念,其中帧对数据进行顺序标识,这样浏览器在收到数据之后,就可以按照序列对数据进行合并,而不会出现合并后数据错乱的情况。同样因为有了序列,服务器就可以并行的传输数据,这就是流所做的事情。

11、HTTP报文结构

一个HTTP的请求报文由四个部分组成:请求行,请求头部,空行,请求数据。

HTTP响应报文也分为三个部分:响应行,响应头,响应体。

https://blog.csdn.net/shouwang666666/article/details/70232053

12、HTTP与HTTPS的区别以及如何实现安全性

两者的区别:

(1)、HTTP是明文传输,传输内容容易被篡改或者被窃取;HTTPS是密文传输,https相当于包装了SSL\TLS协议的HTTP。

(2)、https在网络请求效率上会低于http,因为采用了不同的请求协议以及更复杂的安全验证操作。

(3)、https需要申请CA证书,用于验证公钥这个证书收费,HTTP不用。

主要通过非对称加密+对称加密+CA证书来保证请求安全的。

13、如何验证证书的合法性?

(1)、验证证书是否在有效期内。

(2)、验证证书是否被吊销了。

(3)、验证证书真实性,是否是由上级CA签发的。

https://www.jianshu.com/p/f4a37da10c53

14、https中哪里用了对称加密,哪里用了非对称加密,对加密算法(如RSA)等是否有了解?

https协议中加密使用了SSL协议,SSL的加密既用了对称加密也用了非对称加密,对称加密速度快,平时传输用对称加密,非对称加密传密码比较安全,所以对称加密的密码是用非对称加密来传的,这种加密的关键是用非对称加密的方式用密文传输对称加密用的密码。

RSA非对称加密

RSA算法举例:

1,任取两个质数,比如p=3,q=11

2,计算n=p*q,也就是n=33

3,计算A=(p-1)*(q-1),也就是A=20

4,在1到A之间随便选个数e,要求e和A互质,比如选e=3(随便选的,和p=3没有关系)

5,计算d,要求e*d mod(A)=1,也就是3*d对20取模等于1,d可以等于7,可以等于17,还可以等于其他很多值,这里选d=7

6,于是得到了e和d,e和d关于A互为模反元素,那么,公钥就是(n,e)也就是(33,3),私钥就是(n,d)也就是(33,7)

7,公钥(33,3)由服务器发给浏览器,私钥(33,7)由服务器自己留下。假如浏览器要发送的内容是18,用m表示,即m=18,那么m的e次方对n取模,即18的3次方对33取模,得到结果c=24,也就是浏览器发送的加密内容是24

8,服务器收到24的加密内容后,用c的d次方对n取模,即24的7次方对33取模,得到m=18,也就是浏览器本来要发送的内容。

15、client如何确定自己发送的消息被server收到?

当Client收到服务器返回的二次握手的信息,包含Client发送的SYN+服务器确认的SYN

16、谈谈你对WebSocket的理解

WebSocket是应用层html5出的一种协议,相比较http而言优势是支持长连接,WebSocket只需要一次HTTP握手,整个通信过程是建立在一次连接/状态中,也就避免了HTTP的非状态性,服务端会一直知道你的信息,直到关闭请求;同时WebSocket协议解决了服务器与客户端全双工通信的问题。

信息只能单向传送为单工;信息能双向传送,但不能同时双向传送称为半双工;信息能够同时双向传送称为双工。

17、WebSocket与socket的区别

Android高级面试题_第6张图片

Socket处于抽象层,是Http底层协议;而WebSocket是类似于http应用层协议,WebSocket是应用层html5出的协议。

Http协议有个缺陷:通信只能从客户端发起,做不到服务器主动向客户端推送信息。

WebSocket最大的特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。

18、谈谈你对安卓签名的理解。

Android签名是为了保证应用发布者是本人,大致有几种:以前Eclipse用keyStore进行签名;现在Android Studio开发app采用JKS签名;Android系统签名采用的是pem/pk8.

每个Android App都会有自己的签名,如果我们没有指定签名,编译时会默认用SDK目录下的debug签名文件。

常见的签名jks在Android studio中有两种方式给app签名,一种是build时generate signed apk;一种是在build文件中配置签名信息。

Android高级面试题_第7张图片
Android高级面试题_第8张图片

19、请解释安卓为啥要加签名机制?

(1)、应用程序升级,验证app的唯一性,包名和签名都一致才能升级。

(2)、应用程序模块化,可以模块化部署多个应用到一个进程,只要他们的签名都一样。

(3)、代码或者数据共享,同一个签名有相同的权限,可以共享数据和代码。

20、视频加密传输

为何要加密传输,因为盗链和盗播的存在,让版权价值大打折扣。用户通过一次付费行为,就可以拿到付费视频的播放URL,将播放的URL进行二次分发,这种行为叫做盗链;用户将视频直接下载到本地,然后进行二次上传分发,这种行为叫做盗播。

常用的视频加密技术有:

(1)、分片加密

基于苹果公司的HLS协议,服务器需要切片出TS文件并进行AES加密,生成m3u8索引文件,然后客户端下载到本地给播放器播放。

(2)、文件前中后加密

这三段文件加密都涉及到文件的读取,尤其是对大文件的读取,我们使用java的RandomAccessFile(随机访问文件)这个类来进行文件的加密解密。

21、App 是如何沙箱化,为什么要这么做?

Android是一个多用户系统,每个应用是一个独立的用户。系统为每个应用分配一个唯一的用户标识(UID),并为应用中所有的文件设置该用户才能访问的权限。每个进程中有一个独立的VM。每个应用在自己的进程中运行,应用组件需要执行时,系统创建该进程,当系统内存不足时,系统会销毁该进程。

在很多情况下,源自同一开发者或同一开发机构的应用程序,相互间存在信任关系。Android系统提供一种所谓的共享UID(SharedUserID)机制,使具备信任关系的应用程序可以运行在同一进程空间。

沙箱是为app提供隔离环境的一种安全机制,严格控制执行的程序所访问的资源,以确保系统的安全,让app在独立的进程中执行任务,让其不能访问外部进程的资源,这样一个应用出问题了,其他的应用进程能够保障不被影响。

22、权限管理系统(底层的权限是如何进行 grant 的)?

应用程序在应用层的AndroidManifest.xml中所申请的权限将会在Android系统启动时,经过解析后,逐步映射到内核层的组ID和用户ID,最终由内核层setgid()和setuid()函数设置后才能执行;在进行权限申请时,6.0以上需要动态代码申请,6.0以下直接在AndroidManifest.xml中注册即可。

(三)数据库

1、sqlite升级,增加字段的语句

(1)、将表A重命名,重命名为A_temp。

(2)、创建新表A。

(3)、将表A_temp中的数据插入到新表A中。

(4)、删除表A_temp。

2、数据库框架对比和源码分析

greenDao是一种Android数据库ORM框架,与OrmLite、ActiveOrm、LitePal等数据库相比,单位时间内可以插入、更新和查询更多数据,而且提供了大量的灵活通用的接口。

https://blog.csdn.net/u012702547/article/details/52226163

3、数据库的优化

数据库性能上:

(1)、批量事务插入,提升数据插入的性能。

(2)、单条sql由于多条sql

(3)、读和写操作是互斥的,写操作过程中可以休眠让读操作进行。

(4)、使用索引。

(5)、使用联合索引

(6)、勿使用过多索引

(7)、增加查询条件

(8)、提前将字段的index映射好。

数据库设计上:

(1)、通过冗余换取查询速度

(2)、减少数据来提升查询速度。

(3)、避免大数据多表的联合查询。

4、数据库数据迁移问题

(1)、将表A重命名,重命名为A_temp。

(2)、创建新表A。

(3)、将表A_temp中的数据插入到新表A中。

(4)、删除表A_temp。

(四)算法

1、排序算法有哪些?

(1)、冒泡排序:

Android高级面试题_第9张图片

从第一个数开始,相邻元素两两对比,小的数放前面。(每循环一次,最后一个数都会被确定下来,为每轮的最大数)

(2)、选择排序:

Android高级面试题_第10张图片

从第一个数开始,循环一圈找最小的数交换位置。(每循环一圈,第一个数都会被确定下来,为每轮最小的值)

(3)、插入排序:

Android高级面试题_第11张图片

从第二个数开始,跟前一个数比较,若比前一个数小,则交换位置,接着跟前一个数比较,直到比前一个数大为止。(从第一张开始整理扑克牌,小的往前插)(可能会出现一个数从最后比较到最前面,比较费时)

(4)、希尔排序:

    希尔排序属于插入类排序,是将整个有序序列分割成若干个小的子序列分别进行插入排序。

    排序过程:先取一个正整数d1

    优点:当n值很大时,数据项每一趟排序需要移动的个数很少,但数据项的距离很长;当n值减小时,每一趟需要移动的数据增多,此时已经接近于它们排序后的最终位置。

    希尔分析:

        希尔排序是按照不同步长对元素进行插入排序,当刚开始元素很无序的时候,步长最大,所以插入排序的元素个数很少,速度很快;当元素基本有序了,步长很小,插入排序对于有序的序列效率很高。所以,希尔排序的时间复杂度会比o(n^2)好一些。

(5)、归并排序:

Android高级面试题_第12张图片

 归并排序有两种实现方法:自上而下的递归;自下而上的迭代。下面讲递归法:

    将原数组用二分法一直分到两个数为一组,然后通过比较将较小的数放到前面(通过一个中间数组排序);然后一层层向上排序。

    (就是两个数比较进行排序,然后两组(四个数)进行比较排序,然后两组(八个数)进行比较排序…)

(6)、快速排序:

Android高级面试题_第13张图片

快速排序思想:先找到一个基准点(一般指数组的中部),然后数组被该基准点分为两部分,依次与该基准点数据比较,如果比它小,放左边;反之,放右边。 左右分别用一个空数组去存储比较后的数据。最后递归执行上述操作,直到数组长度<=1。

    特点:快速,常用。缺点是需要另外声明两个数组,浪费了内存空间资源。

2、最快的排序算法是哪个?

快速排序时最快的排序算法。

3、手写一个冒泡排序

Android高级面试题_第14张图片

4、手写快速排序代码

Android高级面试题_第15张图片

5、快速排序的过程、时间复杂度、空间复杂度

快速排序原理:

(1)、定义一个基准元素base(我这里定义最左边的元素定位基准元素)

(2)、定义两个变量i和j

(3)、j先从右向左遍历,找到第一个比base小的数就停止。

(4)、i从左往右遍历,找到第一个比base大的数就停止。

(5)、如果i和j不相等,交换i和j指向的元素。

(6)、直到i和j指向同一元素,将这个元素与基准元素交换

(7)、递归求解

图解:

Android高级面试题_第16张图片
Android高级面试题_第17张图片

6、手写堆排序

Android高级面试题_第18张图片
Android高级面试题_第19张图片

7、堆排序过程、时间复杂度及空间复杂度

将待排序的序列构造成一个大顶堆。此时,这个序列最大值就是堆顶的根节点。将其与数组末尾元素进行交换,此时末尾元素就是最大值,然后将剩余的n-1个序列重新构造成一个堆,这样就可以得到n-1个元素的次大值。如此反复执行,便能得到一个有序序列了。

堆排序的时间复杂度是O(n log n)

空间复杂度为O(1)

8、写出你所知道的排序算法及时空复杂度,稳定性

Android高级面试题_第20张图片

9、二叉树给出根节点和目标节点,找出从根节点到目标节点的路径

Android高级面试题_第21张图片

10、给阿里2万多名员工按年龄排序应该选择哪个算法?

快速排序

Android高级面试题_第22张图片

https://blog.csdn.net/lsm18829224913/article/details/80304750

11、GC算法(各种算法的优缺点以及应用场景)

(1)、标记清除

优点:实现简单;与保守式GC算法兼容;

缺点:碎片化;分配速度;与写时复制技术不兼容

(2)、复制算法

优点:优秀的吞吐量;可实现告诉分配;不会发生碎片化;与缓存兼容

缺点:堆使用效率低下;不兼容保守式GC算法;递归调用函数

(3)、标记整理

优点:可有效利用堆

缺点:压缩花费计算成本

(4)、增量算法

优点:缩短了最大暂停时间;降低了吞吐量。

https://www.jianshu.com/p/9e7ec35c45f5

12、蚁群算法与蒙特卡洛算法

https://blog.csdn.net/longxinghaofeng/article/details/77740480

https://blog.csdn.net/bi_mang/article/details/52416258

13、子串包含问题(KMP 算法)写代码实现

Android高级面试题_第23张图片
Android高级面试题_第24张图片
Android高级面试题_第25张图片

在匹配阶段,若是模式串和文本串相同,那就继续匹配下一位,若是不相同,就去找next数组记录的位置,继续匹配,这也就是KMP算法和普通暴力算法的主要区别,暴力是从头开始匹配,而KMP是通过next数组,发现前面可以跳过大量重复计算的东西。

next数组计算方法:

next数组的计算主要和模式串相关,与文本串没有关系,因为,模式串前后公共最长子序列。这样才会让我们跳过大量的重复计算,next数组的主要实现方法有很多,就是要找到前后最长公共子序列的长度,比如:

ababa:

模式串的各个子串:前缀:后缀:最大公共元素长度:

a 0

ab a b 0

aba a ab a ba 1

abab a ab aba b ab bab 2

ababa a ab aba abab a ba aba baba 3

如上图next数组的元素就是0,0,1,2,3

kmp算法的核心就是就算next数组。

14、一个无序,不重复数组,输出N个元素,使得N个元素的和相加为M,给出时间复杂度、空间复杂度。手写算法

15、万亿级别的两个URL文件A和B,如何求出A和B的差集C(提示:Bit映射->hash分组->多文件读写效率->磁盘寻址以及应用层面对寻址的优化)

16、百度POI中如何试下查找最近的商家功能(提示:坐标镜像+R树)。

17、两个不重复的数组集合中,求共同的元素。

retainAll取交集

18、两个不重复的数组集合中,这两个集合都是海量数据,内存中放不下,怎么求共同的元素?

采取分而治之的方法

先遍历数组A,对每个元素求取hash(元素)%1000,然后根据所取到的值将元素分别存储在1000个数组中。

遍历数组B,采取和A相同的方式,将元素分别存储在1000个数组中,这样处理后,所有可能相同的元素都在对应的小数组中(a0VSb0,a1VSb1...a999VSb999),不对应的小数组不可能有相同的元素,然后只要求出1000对小数组中相同的元素即可。

19、一个文件中有100万个整数,由空格分开,在程序中判断用户输入的整数是否在此文件中。说出最优的方法

使用位图方法,申请足够的内存,一个bit位代表一个unsigned int值。读入100万数据,设置响应的bit位,读入要查询的数,查看响应bit位是否为1,为1表示存在,为0表示不存在。

https://www.cnblogs.com/hongdada/p/8267032.html

20、一张Bitmap所占内存以及内存占用的计算

一张图片(Bitmap)占用的内存=图片长度*图片宽度*单位像素占用的字节数。(图片长度和图片宽度的单位是像素)。

21、2000万个整数,找出第五十大的数字?

采用最小堆。首先读入前50个数字,来创建大小为50的最小堆,建堆的时间复杂度O(50log50),然后遍历后续数字,并与堆顶(最小)的数字进行比较,如果比最小的数小,则继续读取后续数字,如果比最小值大,则替换对顶元素,并重新调整堆为最小堆,重复这个过程直到2000万个整数遍历完成。此时,采用中序遍历的方式输出所有的50个数字,就是前50大的数字,第一个即为第50大的数字。

22、烧一根不均匀的绳,从头烧到尾总共需要1个小时。现在有若干条材质相同的绳子,问如何用烧绳的方法来计时一个小时十五分钟呢?

先用两根绳子,一根绳子一头点火,另一根绳子两头点火,当第二根绳子燃烧完毕的时候(即半个小时),点燃第一根绳子的另一头,当第一根绳子燃烧完毕的时候,此时正好45分钟,然后再点燃第三根绳子的两头,等第三根绳子烧完,则正好是一个小时十五分钟。

23、求1000以内的水仙花数以及40亿以内的水仙花数

Android高级面试题_第26张图片

24、5枚硬币,2正3反如何划分为两堆然后通过翻转让两堆中正面向上的硬8币和反面向上的硬币个数相同

25、时针走一圈,时针分针重合几次

11次。

26、N*N的方格纸,里面有多少个正方形

n^2 +(n-1)^2 +……+1 = (n+1)(2n+1)n/6个

27、x个苹果,一天只能吃一个、两个、或者三个,问吃完有多少种吃法?

Android高级面试题_第27张图片

(五)插件化、模块化、组件化、热修复、增量更新、Gradle

1、对热修复和插件化的理解

插件化和热修复不是同一概念,插件化顾名思义就是把需要实现的模块或是功能当做一个独立的提取出来,减少宿主的规模,当需要使用到响应的功能时,再去加载相应的模块。

热修复则往往是从修复bug的角度出发,强调的是不需要二次安装应用的前提下修复已知的bug。

2、插件化原理分析

插桩代理

https://blog.csdn.net/rayht/article/details/79795985

3、模块化实现(好处,原因)

(1)、结构清晰,各个模块的代码实现分离,不会搅在一起。在代码review或者二次开发的时候一目了然,不会满世界去找代码。

(2)、协同开发的时候更灵活,不用再等同组的其他同事的模块开发完成后才能运行app,自己负责的模块稍加修改就可以当做主App直接跑起来。

(3)、便于维护。每个模块的代码、布局文件、资源文件可以随时从项目中通过gradle配置去掉。

4、热修复,插件化

Android插件化----指将一个程序划分成不同的部分,比如一般App的皮肤样式就可以看成一个插件。

Android组件化-----这个概念和上边相差不是那么明显,组件和插件最大的区别在于:组件是指通用和复用性较高的构建,比如图片缓存就可以看成一个组件被多个App调用。

热修复----从bug角度出发,强调的是在不需要二次安装应用的前提下修复已知的bug。

5、项目组件化的理解

除了有commonLib和app模块外,还包括按功能划分的各个业务组件模块,之前的包变成现在的组件模块,增加了层次感;每个模块可以单独编译,加快了编译速度,也为提供单元模块测试提供了支持;多人开发只负责自己开发的模块,直接避免了版本管理的冲突。

(1)、设置模块间的依赖,且使得业务模块可单独编译--通过配置gradle即可解决。

(2)、业务模块之间的跳转以及通信--使用阿里开源的ARouter即可解决。

https://www.jianshu.com/p/8b6e6a50e21e

6、描述清点击 Android Studio 的 build 按钮后发生了什么

Android Studio点击build后就会编译整个项目,并将apk安装到手机上,这个过程就是android工程编译打包的过程。

(1)、打包资源文件,生成R.java文件。

输入:Resource文件(即工程的res文件)

    Assets文件(即工程的assets文件夹)

    AndroidManifest.xml文件

    Android基础类库(Android.jar文件)

输出:R.java文件

          打包好的资源。

工具:aapt工具

(2)、处理AIDL文件(没有可以省略),生成对应的.java文件

输入:源码文件、aidl文件、freamwork.aidl文件

输出:对应的.java文件

工具:aidl工具

(3)、编译java文件,生成对应的.class文件。

输入:源码文件(包括第一步生成的R.java和第二步生成的aidl.java文件)

          库文件(.jar文件)

输出:对应的.class文件

工具:javac工具

(4)、把.class文件转化为Davilk VM支持的.dex文件

输入:第三步生成的.class文件(包括AIDL、R.java、源代码生成的.class文件)

    库文件(.jar文件)

输出:对应的.dex文件

工具:javac工具

(5)、打包生成未签名的.apk文件

输入:打包后的资源文件(包括本地和第三方库里的)

  打包后的.dex文件

    libs文件(包括.so文件,如果涉及到C/C++开发的话)

输出:未签名的.apk文件

工具:apkbuilder工具

(6)、对未签名的.apk文件进行签名

输入:未签名的.apk文件

输出:签名的.apk文件

工具:jarsigner工具

(7)、对签名后的.apk文件进行对齐处理

输入:签名的.apk文件

输出:对齐后的.apk文件

工具:zipalign工具

反编译过程:

(1)、将apk解压

(2)、找到classes.dex文件,用dex2jar工具,将dex转变为.jar文件,命令d2j-dex2jar classes.dex

(3)、用jd-gui工具,将jar文件转换成java文件

(4)、用apktool这个工具用于最大幅度的还原apk中9-patch图片、布局、字符串等等一系列的资源。命令apktool d Demo.apk。

(六)架构设计和设计模式

1、谈谈你对Android设计模式的理解

Android的设计模式一般有MVC,MVP,MVVM三种

2、MVC MVP MVVM原理和区别

MVC是指Modle,View和Controller,将界面,业务逻辑和控制器分开,是一种低耦合的设计方式,适用于简单的应用开发。

这种设计模式最简单,但问题有三:

(1)、View和Model相互可见,耦合度高。

(2)、如果程序复杂,那么Activity这个Controller将十分繁琐复杂,不容易维护。

(3)、Activity角色模糊,View或Model。

MVP:P是指Presenter,即实现者,功能与Controller类似。Presenter实质为Interface类的运用,用于降低M、V、C间的耦合度,主旨是为Activity或Fragment瘦身。

MVP模式容易维护,可拆卸,可扩展,耦合性叫MVC较小,结构清晰。

MVP的缺点,在于开发开销相对较大。与MVC相比,需要维护更多的接口。

MVVM:MVVM由三部分组成,M,V,VM,分别代表Modle,View,ViewModle。谈论MVVM的前提是需要了解DataBinding,即Modle与View的进行绑定,包括单向绑定(Modle影响View),双向绑定(Modle与View相互影响)。

MVVM的侧重点在于数据与UI的联动,自动更新,而非降低耦合度。对于耦合度的问题,其实还是需要结合MVP模式来解决。

3、你所知道的设计模式有哪些?

Android高级面试题_第28张图片

4、项目中常用的设计模式

(1)、模板方法模式

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,如jdbcTemplate

(2)、代理模式

spring的Proxy模式在AOP中有体现

(3)、观察者模式

定义对象的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新

(4)、适配器模式

MethodBeforeAdviceAdapter类。

(5)、策略模式

使用了java的继承和多态

(6)、单例模式

解决了一个全局使用的类频繁的创建与销毁。

(7)、工厂模式

分为三种:简单工厂,工厂方法,抽象工厂。

5、手写生产者/消费者模式

生产者消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据。

实现生产者消费者模式有三点:

(1)、一般使用队列作为缓冲区,给生产者和消费者解耦,平衡了生产者和消费者的处理能力。

(2)、构建生产者,队列满使得生产者线程阻塞。

(3)、构建消费者,队列空使得消费者线程阻塞。

Android高级面试题_第29张图片
Android高级面试题_第30张图片
Android高级面试题_第31张图片

BlockingQueue是一个阻塞队列,它的存取可以保证只有一个线程在进行,所以根据逻辑,生产者在内存满的时候进行等待,并唤醒消费者队列,反过来消费者在饥饿状态下,等待并唤醒生产者生产。

6、写出观察者模式的代码

Android高级面试题_第32张图片
Android高级面试题_第33张图片
Android高级面试题_第34张图片

从上边的例子可以看出,定义了四个订阅者,一个发布者,当发布者更新一个消息时,四个订阅者都收到消息,根据发布者更新的信息执行对应的更新操作。

7、适配器模式,装饰者模式,外观模式的异同?

装饰器模式:能动态的新增或组合对象的行为。

适配器模式:是对其他对象接口的一种转换行为,将原接口转换为目标接口,达到适配的效果。

外观模式:外观对象提供对子系统各元件功能的简化为共同层次的调用接口,它主要起简化作用。

装饰者是“新增行为”,适配器模式是“转换行为”,外观者模式是“简化行为”。

8、用到的一些开源框架,介绍一个看过源码的,内部实现过程。

EventBus是一款在Android开发中使用的发布/订阅事件总线框架,基于观察者模式,将事件的接收者和发送者分开,简化了组件之间的通信,使用简单、效率高,体积小。

Android高级面试题_第35张图片

技术要点:java反射,ThreadLocal&Queue,单例模式,建造者模式

EventBus以反射开始--注册,以反射结束--事件的消费。

https://blog.csdn.net/json_it/article/details/79948484

9、谈谈对RxJava的理解

RxJava说到底,本质可以压缩为异步一个词。它就是一个异步操作的库,其他定于都是基于这之上的。

RxJava的异步实现是通过一种扩展的观察者模式来实现的。

10、RxJava的功能与原理实现

RxJava原理就是创建一个Observable对象来干活,然后使用各种操作符建立起来的链式操作,就如同流水线一样,把你想要处理的数据一步一步加工成你想要的成品,然后发射给Subscriber处理。

11、RxJava的作用,与平时使用的异步操作来比的优缺点

异步操作有Handler、AsyncTask等,但使用Rxjava,就算再多的异步操作,代码逻辑越来越复杂,RxJava依然可以保持清晰的逻辑。

https://www.jianshu.com/p/57b5c6567791

12、说说EventBus作用,实现方式,代替EventBus的方式

EventBus作用:简化各组件间的通信,让我们书写代码更简单,能有效的分离事件发送方和事件接收方(也就是解耦合),能避免复杂和容易出错的依赖性和生命周期的问题。

RxJava可以替代EventBus,也可以使用Handler或AsyncTask

13、从0设计一款App整体架构,如何去做?

(1)、构建方式:Gradle或Maven

(2)、网络框架:包括网络请求,图片异步加载,图片缓存,网络缓存,力求简单易用。

(3)、适配资源。

(4)、设计模式:MVC、MVP、MVVM

14、说一款你认为当前比较火的应用并设计(比如:直播APP,P2P金融,小视频等)

15、谈谈对java状态机理解

状态机包含一个状态集合,定义当状态机处于某一个状态的时候它所能接受的事件以及可执行的行为,执行完后,状态机所处的状态。

https://www.jianshu.com/p/d48e0d565618

16、Fragment如果在Adapter中使用应该如何解耦?

接口回调,广播

17、Binder机制及底层实现

IPC原理:

Android高级面试题_第36张图片

每个Android进程,只能运行在自己进程所拥有的虚拟地址空间。对应一个4GB的虚拟地址空间,其中3GB是用户空间,1GB是内核空间,当然内核空间的大小可以通过参数配置进行调整。对于用户空间,不同进程之间彼此是不共享的,而内核空间确实可共享的。Client进程向Server进程通信,恰恰是利用了进程间可共享内核空间来完成底层通信工作的,Client端与Server端进程往往采用ioctl等方法跟内核空间的驱动进行交互。

Binder原理:

Binder通信采用C/S架构,从组件视角来说,包含Client、Server、ServiceManager以及binder驱动,其中ServerManager用于管理系统中的各种服务。

Android高级面试题_第37张图片

Binder通信的四个角色:

Client进程:使用服务的进程。

Server进程:提供服务的进程。

ServiceManager进程:ServiceManager的作用是将字符串形式的Binder名字转化成Client中对该Binder的引用,使得Client能够通过Binder名字获得对Server中Binder实体的引用。

Binder驱动:驱动负责进程之间Binder通信的建立,Binder在进程之间的传递,Binder引用计数管理,数据包在进程间的传递交互等一系列底层支持。

https://www.jianshu.com/p/4920c7781afe?from=jiantop.com

18、对于应用更新这块是如何做的?(解答:灰度,强制更新,分区域更新)?

19、实现一个Json解析器(可以通过正则提高速度)

https://www.cnblogs.com/mahuan2/p/8034392.html

20、统计启动时长,标准

启动类型

(1)、冷启动:application没有被创建,需要先创建进程,然后启动MainActivity。由于这个过程需要fork一个新进程,所以耗时。

(2)、热启动:同上面对照,已经启动过application,并驻留在系统内存内,只是需要唤醒该进程,并启动MainActivity。

启动时长统计:

adb统计:adb shell am start -w pageage/activityname 通过这条命令启动,可以获得启动时间。

(七)性能优化

1、如何对Android 应用进行性能分析以及优化?

Android高级面试题_第38张图片

https://www.jianshu.com/p/da2a4bfcba68

2、ddms 和 traceView

TraceView是AndroidSDK自带的工具,用于Android应用程序及Framework层的代码进行性能分析。

TraceView是一个图形化工具,最终它会产生一个图表,用于对性能分析进行说明。

TraceView原理:TraceView通过修改code,在需要调试的起始位置加入调试函数,程序运行之后会在SD的根目录下产生*.trace文件来保存运行时数据,然后把*.trace文件拷贝到PC机上,通过traceview命令对*.trace文件进行分析。

DDMS:

(1)、查看进程的堆栈使用情况。

(2)、跟踪对象的内存分配

(3)、操作仿真器或设备的文件系统。

(4)、检查线程信息。

(5)、方法分析。

(6)、使用的网络流量工具

(7)、使用LogCat

(8)、模拟电话业务和位置

(9)、模拟来电或SMS文本信息

(10)、设置手机地理位置。

https://blog.csdn.net/liu515714312/article/details/20034813

3、性能优化如何分析systrace?

Systrace原理:在系统一些关键链路(比如System Service,虚拟机,Binder驱动)插入一些信息(这里称为Label),通过Label的开始和结束来确定某个核心过程的执行时间,然后把这些Label信息收集起来得到系统关键路径的运行时间信息,进而得到整个系统的运行性能信息。

https://www.jianshu.com/p/fa6cfad8ccc2

4、用IDE如何分析内存泄漏?

(1)、把java应用程序使用的heap dump下来。

(2)、使用java heap分析工具,找出内存占用超出预期的嫌疑对象。

(3)、必要时,需要分析嫌疑对象和其他对象的引用关系。

(4)、查看程序的源代码,找出嫌疑对象数量过多的原因。

https://blog.csdn.net/u010944680/article/details/51721532

5、Java多线程引发的性能问题,怎么解决?

创建线程的方式:继承Thread类;实现Runnable接口

两种方式的主要区别在于多线程访问同一资源的情况下,用Runnable创建的线程可以处理同一资源,而Thread类创建的线程则各自独立处理,各自拥有自己的资源。

多线程引发的问题:

(1)、线程的创建和销毁都需要时间,当有大量的线程创建和销毁时,那么这些时间的消耗则比较明显,将导致性能上的缺失。

(2)、大量的线程创建、执行和销毁是非常耗CPU和内存的,这样直接影响系统的吞吐量,导致性能急剧下降,如果内存资源占用的比较多,还很可能造成OOM。

(3)、大量的线程的创建和销毁很容易导致GC频繁的执行,从而发生内存抖动现象,而发生内存抖动,对移动端来讲,最大的影响就是造成页面卡顿。

解决办法:

重用已有的线程,从而减少线程的创建和销毁,这就需要使用线程池,线程池的基本作用就是进行线程的复用。

6、启动页白屏及黑屏解决?

原因:

在启动Activity时,执行setContentView(R.layout.activity_splash)出现白屏。

onCreate----setContentView这个并不是发生在窗体绘制的第一步,系统会在执行这个步骤前,先绘制窗体,这时候布局资源还没有加载,于是就使用默认背景色。

这种亮色系造成白色闪屏。

这种暗色系主题,造成黑色闪屏。

解决方案:

(1)、把启动图bd_splash设置为窗体背景,避免刚刚启动App时出现黑/白屏。

(2)、设置为背景bd_splash显示时,后台负责加载资源,同时去下载广告,广告图下载成功或超时时,显示SplashActivity的真实样子。

(3)、随后进入MainActivity

7、启动太慢怎么解决?

应用启动速度取决于application中做了什么事情,比如继承了很多sdk,并且sdk的init操作都需要在主线程中实现,那自然就慢了。在非必要的情况下,可以把加载延后,或丢给子线程。

8、怎么保证应用启动不卡顿?

同上边是一个道理,也可以做一个闪屏页当缓冲时间。

9、App启动崩溃异常捕捉

https://www.jianshu.com/p/fb28a5322d8a

10、自定义View注意事项

减少不必要的invalidate()方法。

(1)、降低刷新频率

(2)、使用硬件加速

(3)、初始化时创建对象;不要在onDraw方法内创建绘制对象,一般都在构造函数里初始化对象。

(4)、状态存储和恢复:如果内存不足时,而恰好我们的Activity置于后台,不行被重启,或者用户旋转屏幕造成Activity重启,我们的View也应该尽量的去保存自己的属性。

11、现在下载速度很慢,试从网络协议的角度分析原因,并优化(提示:网络的5层都可以涉及)。

12、Https请求慢的解决办法(提示:DNS,携带数据,直接访问IP)

Http耗时 = TCP握手

HTTPS耗时 = TCP握手 + SSL握手

13、如何保持应用的稳定性

需要借助内存分析工具防止内存泄漏。

14、RecyclerView和ListView的性能对比

https://www.jianshu.com/p/171b20389634

15、ListView的优化

convertView的使用,主要优化加载布局问题。

内部类ViewHolder的使用。

16、RecycleView优化

给item设置点击事件和长按事件。

给item中的控件设置点击事件和长按事件。

17、View渲染

https://blog.csdn.net/csdn1125550225/article/details/80401365

18、Bitmap如何处理大图,如一张30M的大图,如何预防OOM

需要将这张大图进行压缩。

使用图片缓存。

https://blog.csdn.net/guolin_blog/article/details/9316683

19、java中的四种引用的区别以及使用场景

强引用:如果一个对象具有强引用,那么垃圾回收器绝不会回收它。

软引用:如果一个对象具有软引用,则内存空间足够,垃圾回收器不会回收它,如果内存空间不足了,就会回收这些对象。

弱引用:弱引用与软引用的区别在于,只具有弱引用的对象拥有更短暂的生命周期。

虚引用:如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。

总结:弱引用和软引用都可以用来保存对象的实例引用,这两个类与垃圾回收有关。

弱引用其中保存的对象实例可以被GC回收掉。这个类通常用于在某处保存对象的引用,而又不干扰该对象被GC回收,通常用于Debug、内存监视工具等程序中。

强引用保存的对象实例,除非JVM即将OutOfMemory,否则就不会被GC回收。

20、强引用置为null,会不会被回收?

会,GC执行时,就会被回收掉,前提是没有被引用的对象。

Android高级面试题_第39张图片

https://blog.csdn.net/qq_33048603/article/details/52727991

(八)NDK、jni、Binder、AIDL、进程通信有关

1、请介绍一下NDK

Native Development Kit,是Android的开发工具包。

作用:快速开发C/C++的动态库,并自动将so和应用一起打包成apk。

即可通过NDK在Android中使用JNI与本地代码(C/C++)交互。

2、什么是NDK库?

Native Development Kit,是Android的开发工具包。

版本一般使用:android-ndk-r14b-darwin-x86_64 或16版本的。

3、jni用过吗?

用过

4、如何在jni中注册native函数,有几种注册方式?

静态方法:这种方法比较常见,大致流程如下:

(1)、先创建java类,声明Native方法,编译成.class文件

(2)、使用javah命令生成C/C++的头文件。

(3)、创建.h的源文件,实现对应的native方法。

动态注册:

JNI中有一个叫JNINativeMethod的结构体来保存这个对应的关系,实现动态注册就需要这个结构体。

https://blog.csdn.net/wwj_748/article/details/52347341

5、Java如何调用c、c++语言?

直接调用java中的native方法即可。

6、jni如何调用java层代码?

C调用java中的方法使用的是反射

(1)、获取字节码文件(jclass(FindClass)(JNIEnv,const char*);)

(2)、通过字节码对象找到方法对象(jmethodID(GetMethodID)(JNIEnv,jclass,const char,const char);)

(3)、通过字节码文件创建一个object对象(该方法可选,方法中已经传递了一个object,如果需要调用的方法与本地方法不在同一个文件夹则需要创建新的object(jobject(AllocObject)(JNIEvn,jclass);),如果需要反射调用的java方法与本地方法不在同一个类中,需要创建该方法,但是如果是这样,并且需要更新UI操作,这个时候就会报空指针异常,因为这个时候调用的方法只是一个方法,没有Activity声明周期)。

(4)、通过对象调用方法,可以调用空参数方法,也可以调用有参数的方法,并将参数通过调用的方法传入(void(CallVoidMethod)(JNIEvn,jobject,jmethodID,...))。

7、进程间通信的方式?

(1)、AIDL:功能强大,支持进程间一对多的实时并发通信,并可实现RPC(远程过程调用)

(2)、Messenger:支持一对多的串行实时通信,AIDL的简化版本。

(3)、Bundle:四大组件的进程通信方式,只能传输Bundle支持的数据类型。

(4)、ContentProvider:强大的数据源访问支持,主要支持CRUD操作,一对多进程间数据共享。

(5)、Broadcast Receiver:广播,但只能单向通信,接收者只能被动接受信息。

(6)、文件共享:在非高并发的情况下共享简单的数据。

(7)、Socket:通过网络传输数据。

8、Binder机制

IPC原理:

Android高级面试题_第40张图片

每个Android进程,只能运行在自己进程所拥有的虚拟地址空间。对应一个4GB的虚拟地址空间,其中3GB是用户空间,1GB是内核空间,当然内核空间的大小可以通过参数配置进行调整。对于用户空间,不同进程之间彼此是不共享的,而内核空间确实可共享的。Client进程向Server进程通信,恰恰是利用了进程间可共享内核空间来完成底层通信工作的,Client端与Server端进程往往采用ioctl等方法跟内核空间的驱动进行交互。

Binder原理:

Binder通信采用C/S架构,从组件视角来说,包含Client、Server、ServiceManager以及binder驱动,其中ServerManager用于管理系统中的各种服务。

Android高级面试题_第41张图片

Binder通信的四个角色:

Client进程:使用服务的进程。

Server进程:提供服务的进程。

ServiceManager进程:ServiceManager的作用是将字符串形式的Binder名字转化成Client中对该Binder的引用,使得Client能够通过Binder名字获得对Server中Binder实体的引用。

Binder驱动:驱动负责进程之间Binder通信的建立,Binder在进程之间的传递,Binder引用计数管理,数据包在进程间的传递交互等一系列底层支持。

https://www.jianshu.com/p/4920c7781afe?from=jiantop.com

9、简述IPC?

IPC是Interface Process Connection的缩写,含义为进程间通信或跨进程通信,指两个进程间进行数据交换的过程。

10、什么是AIDL?

AIDL是Android中IPC的方式的一种。AIDL的作用是让你可以在自己的APP里绑定一个其他的APP的Service,这样你的APP可以与其他APP交互。

11、AIDL解决了什么问题?

只有当你允许来自不同的客户端访问你的服务并且需要处理多线程问题时才必须用AIDL。

12、AIDL如何使用?

服务端:

(1)、定义一个*.aidl的文件

(2)、实现AIDL文件生成的java接口

(3)、定义一个自己的Service,在实现Service时,为了其他应用可以通过bindService来和我们的Service进行交互,我们都要实现Service中的onBind()方法,并且返回一个继承了Binder的内部类。

(4)、同一应用中的Activity为该Service赋值,使用Service

客户端:

(1)、客户端要想使用该服务,需要知道服务在aidl文件中提供了什么服务,所以需要将服务端的aidl文件拷贝到客户端,且包名和文件名需要与服务端一致。

(2)、通过bindService方法与Service交互,该方法中有一个ServiceConnection类型的参数,主要代码便是在该接口中实现。

(3)、在ServiceConnection实现类中onServiceConnected方法中通过*.asInterface(service)获取一个aidl接口的实例。

https://www.cnblogs.com/yoyohong/p/5660406.html

13、Android 上的 Inter-Process-Communication 跨进程通信时如何工作的?

Client进程向Server进程通信,恰恰是利用了进程间可共享内核空间来完成底层通信工作的,Client端与Server端进程往往采用ioctl等方法跟内核空间的驱动进行交互。

14、多进程场景遇见过么?

遇见过

15、Android进程分类?

前台进程:需要用户当前正在进行的操作

可视进程:做用户当前意识到的工作。

服务进程:含有以startService方法启动的Service

缓存/后台进程:系统如有内存需要,可随意杀死。

16、进程和 Application 的生命周期?

进程的生命周期,优先级从高到底

(1)、前台进程,比如Activity的Resume状态。

(2)、可见进程,比如主Activity上弹出一个对话框,该Activity的进程状态就为可见进程。

(3)、服务进程,比如正在运行的Service的状态。

(4)、后台进程,比如Activity,按Home键之后的状态。

(5)、空进程,该进程状态主要用来缓存进程,保存一些进程的数据,方便下次启动的时候,直接从缓存读取数据。

Application的生命周期:

(1)、onCreate在创建应用程序时调用。可以重写这个方法来实现实例化应用程序单态,以及创建和实例化任何程序状态变量和共享资源。

(2)、onLowMemory当系统处于资源匮乏的时候,具有良好行为的应用程序可以释放额外的内存。这个方法一般只会在后台进程已经终止,但是前台应用程序仍然缺少内存时调用。可以重写这个处理程序来清空缓存或释放不必要的资源。

(3)、onTrimMemory作为onLowMemory的一个特定于应用程序的替代选择,在Android4.0时引入。当运行时决定当前应用程序应该尝试减少其内存开销时调用,它包含一个level参数,用于提供请求的上下文。

(4)、onConfigurationChanged与Activity不同,在配置改变时,应用程序对象不会被终止和重启。如果应用程序使用的值依赖于特定的配置,则重写这个方法来重新加载这些值,或在应用程序级别处理配置改变。

17、进程调度

(1)、优先级调度

(2)、组优先级调度

(3)、调度策略

(4)、进程adj调度

http://www.51testing.com/html/96/n-3723996-2.html

18、谈谈对进程共享和线程安全的认识

可以通过uid实现进程共享。

线程安全:如果代码所在的进程中有多个线程在同时运行,而这些线程有可能同时运行这段代码。如果每次运行结果和单线程运行结果是一样的,而且其他变量的值也和预期的是一样的,就是线程安全的。

19、谈谈对多进程开发的理解以及多进程应用场景

在开发中,我们通常会使用修改清单文件的android:process来达到多进程的目的。如果android:process的value值以冒号开头的话,那么该进程就是私有进程,如果以其他字符开头,则是公有进程,这样拥有相同ShareUID的不同应用可以跑在同一进程中。

多进程应用场景:做音乐播放器(在新的进程中,启动前台Service,播放音乐);多模块应用。

20、什么是协程?

协程提供了一种新的异步执行方式。

(九)framework层、ROM定制、Ubuntu、Linux之类的问题

1、java虚拟机的特性

2、谈谈对jvm的理解

JVM是java的核心和基础,在java编译器和os平台之间的虚拟处理器。

JVM的执行过程:

(1)、加载.class文件

(2)、管理并分配内存。

(3)、执行垃圾收集。

Android高级面试题_第42张图片

3、JVM内存区域,开线程影响哪块内存

每当有线程创建的时候,JVM就需要为其在内存中分配虚拟机栈和本地方法栈来记录调用方法的内容,分配程序计数器记录指令执行的位置,这样的内存消耗就是创建线程的内存代价。

4、对Dalvik、ART虚拟机有什么了解?

JVM执行的是.class文件

DVM执行的是由.class文件转化来的dex文件

DVM可执行文件更小,JVM基于栈,DVM基于寄存器

ART虚拟机执行的是本地机器码

5、Art和Dalvik对比

DVM运行的是dex文件,ART运行的是本地机器码

ART在应用第一次安装的时候字节码就会预编译成机器码,使其成为真正的本地应用。这个过程叫做预编译。这样应用的启动(首次)和执行都会更快

dex不能直接被ART虚拟机执行,Google已经放弃了DVM,可以直接研究ART。

6、虚拟机原理,如何自己设计一个虚拟机(内存管理,类加载,双亲委派)

7、谈谈你对双亲委派模型理解

Android高级面试题_第43张图片

上图中类加载器之间的这种层次关系,称为类加载器的双亲委派模型。双亲委派模型要求除了顶层的启动类加载器,其余的类加载器都应该有自己的父类加载器。这里类加载器之间的父子关系一般不会以继承关系来实现,而是使用组合关系来复用父加载器的代码。

双亲委托模型的工作过程是:如果一个类加载器收到了类加载器的请求,它首先不会自己尝试加载这个类,而是把这个请求委托给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最后都应该传送到顶层的启动类加载器中,只有当父类加载器反馈自己无法完成这个加载请求(它的搜索范围内没有找到所需的类时),子类才会尝试自己去加载。

8、JVM内存模型,内存区域

Android高级面试题_第44张图片

9、类加载机制

类从被加载到虚拟机的内存开始,到卸载出内存为止,整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载七大阶段。

10、谈谈对ClassLoader(类加载器)的理解

程序启动的时候,并不会一次性加载程序所要用的所有的class文件,而是根据程序需要,通过java的类加载机制(ClassLoader)来动态的加载某个class文件到内存当中去,从而只有class文件被加载到内存之后,才能被其他的class所引用。所以ClassLoader就是动态的加载class文件到内存中的。

11、谈谈对动态加载(OSGI)的理解

12、内存对象的循环引用及避免

两个实例对象相互引用就会造成循环引用。

13、内存回收机制、GC回收策略、GC原理时机以及GC对象

对象回收使用引用计数法和可达性算法

GC回收策略:

新生代可用GC策略:

标记--清除算法

复制算法

标记--整理算法

分代收集算法

GC原理时机:为新对象分配内存时,Eden区没有足够空间时会发生MinorGC。

老年代没有足够空间时,会进行Full GC

14、垃圾回收机制与调用System.gc()区别

System.gc()显示的通知jvm进行一次垃圾回收,但垃圾回收机制具体在什么时间运行是无法预知的。

15、Ubuntu编译安卓系统

https://www.cnblogs.com/chenfeifen/p/9864517.html

16、系统启动流程是什么?(提示:Zygote进程 –> SystemServer进程 –> 各种系统服务 –> 应用进程)

Android高级面试题_第45张图片

17、大体说清一个应用程序安装到手机上时发生了什么

18、简述Activity启动全部过程

https://www.jianshu.com/p/10effba8eed6

19、App启动流程,从点击桌面开始

Android高级面试题_第46张图片

20、逻辑地址与物理地址,为什么使用逻辑地址?

逻辑地址:在具有地址变换功能的计算机中,访问指令给出的操作数。

物理地址:用于内存芯片级单元寻址,与CPU连接的地址总线相对应。

任何一个独立运行的程序,都需要系统分配单独的内存空间,大多数情况下这个工作是由系统完成的,方便程序访问变量,程序不需要关心变量的物理地址。现代操作系统都提供了一种内存管理的抽象,即虚拟内存。进程使用虚拟内存的逻辑地址范文,操作系统协助转换成真正的物理地址。

21、Android为每个应用程序分配的内存大小是多少?

默认是16M

22、Android中进程内存的分配,能不能自己分配定额内存?

23、进程保活的方式

黑色保活:不同app进程,用广播相互唤醒(包括利用系统提供的广播进行唤醒)。

白色保活:启动前台Service

灰色保活:利用系统漏洞启动前台Service

https://www.jianshu.com/p/63aafe3c12af

24、如何保证一个后台服务不被杀死?(相同问题:如何保证service在后台不被kill?)比较省电的方式是什么?

(1)、提升进程的优先级,降低进程被杀死的概率。

(2)、在进程被杀死后,进行拉活

https://blog.csdn.net/u011622280/article/details/52311344

25、App中唤醒其他进程的实现方式

(1)、通过Intent唤醒

(2)、通过Uri换起app

(3)、直接通过包名唤起app

https://blog.csdn.net/jimtrency/article/details/78720611

附;性能调优+前沿技术+NDK技术大纲

你可能感兴趣的:(Android高级面试题)