Android史上最全面试题(持续更新ing)

前言

博主Android开发三年了!不论是大公司(百度、美团、网易),还是小公司的面试都经历过。这篇面试题是我积累了好几年的心血,之前都是在有道云笔记、印象笔记中,通过自己一次次的面试,每次都会把面试官问的问题自己回来记录好,做好总结。直到现在,我选择发出来,是因为我觉得我已经积累的差不多了,这些面试题差不多能应对一场面试了。

聊聊面试这件事。面试,我认为不光是考察技术(当然技术是必不可少的),有时候天时地利人和到了,你技术可能一般,也就通过面试了,面试官看你看对眼了的话,再加上今天面试官可能表白成功,你可能就是走了狗屎运了[偷笑]。当然,我只是举个例子而已,只是想阐述面试考的不止是技术,也是有运气成分的。所以,如果你面试很多次都没有offer的话,不要灰心,不要气馁,总有个坑会要你这根萝卜的,这就好比是相亲,相了好多次,都没有看上你的话,不要灰心,不要气馁,总有个瞎了狗眼的会看上你。

我把面试的问题分为java基础、Android知识点、数据结构与算法、项目相关的问题四部分。

java基础这部分很重要,这个看你基本功,去大公司面试比较注重基础,所以这部分会问的比较多,jvm问的挺多,线程池这块也是重点,还有,大公司面试还会问你并发这块的知识点,比如锁机制,一些volatile、synchronized关键字用来做什么的,内部实现原理等问题。

Android知识点,这块自然不用多说,肯定是面试的重灾区。去大公司面试都都喜欢问你源码、内部实现,这样的问题。所以,handler,asynctask这样常用的API内部原理必须会,面试官还经常问你看过哪些开源框架的源码,所以你得熟悉几个开源框架的内部实现,比如volley、retrofit、OkHttp、butterknife、glide。Android还是要做多项目积累经验。

数据结构与算法这部分是我的弱项,多扯两句,这部分是去大公司面试的必问问题,博主去美团、百度面试都让算法给刷掉了,所以这块很重要,要想进大公司算法是绕不过去的,虽然Android一般用不到太多、太复杂的算法。我在面试题中,关于算法这块我也写了几个,比如排序,二分查找,面试小公司,可能会让你写个什么冒泡排序,快排,二分查找,但是进大公司面试,面试官根本不问这些最普通的面试问题,他们都会自己给你出一个题,让你写出最优算法,平时多看看《剑指offer》、刷LeetCode。算法也是我的弱项,我就不在这里侃了。数据结构,也是很重要的!常用的数据结构(ArrayList、LinkedList、HashMap)内部实现都得知道,能跟面试官侃侃而谈,还有延伸的一些数据结构你也得有所了解,比如问到HashMap都知道他不是线程安全的,那线程安全的ConcurrentHashMap,你知道内部的机制,他是怎么来保证线程安全的前提下,最大的提高读写效率的呢?还有Android特有的数据结构SparseArray等一些原理。了解数据结构内部实现其实挺好的,对编码有帮助。

项目相关的问题,这部分基本都是在二面、三面上吧(终于过了一年了),这块你就跟面试官聊聊你做的项目,用到了什么技术,怎么来解决问题啥的,这个针对自己项目来说就行,就不多说了。

面试要点写完了,来一句感受:面试搬大象,干活拧螺丝!

今天临时想到的基本都是这些,最后奉献上我积累几年的面试题[无私],祝愿各位都能拿到不错的offer。

Java

1. jvm垃圾回收机制

  • JVM详解之Java垃圾回收机制详解和调优

  • JVM GC 那些事(一)- JVM 运行时内存划分

  • Java 堆内存

  • Java中的堆和栈的区别

2. hashCode()和equals()

Java hashCode() 和 equals()的若干问题解答

3. java内存管理

Java进阶10 内存管理与垃圾回收

java内存优化
  • 释放连接
  • 优化逻辑,释放不必要的对象 尽量使用局部变量
  • 减少循环逻辑里的对象的创建
  • 基本类型代替对象类型
  • 使用stringBuffer和stringBuilder替代多次String对象
  • 单线程尽量使用hashmap和ArrayList
  • 提前分配stringBuffer,数组,array,vector等容量
  • 合适的场所使用单例
  • 尽量不要随意使用静态变量
  • 处理内存泄露

4.线程池

线程池,这一篇或许就够了

5. 进程和线程的关系

6. Thread和Runnable的区别

java线程(上)Thread和Runnable的区别

7. 死锁

java 死锁及解决
【Java并发编程】之九:死锁(含代码)

8. 单例

JAVA设计模式之单例模式

9. 强引用 软引用 弱引用 虚引用

Java 7之基础 - 强引用、弱引用、软引用、虚引用

10. http

Android之Http通信——1.初识Http协议
Android Http请求头与响应头的学习

11. 接口和抽象类的区别

  • 接口中所有的方法隐含的都是抽象的。而抽象类则可以同时包含抽象和非抽象的方法。
  • 类可以实现很多个接口,但是只能继承一个抽象类
  • 类如果要实现一个接口,它必须要实现接口声明的所有方法。但是,类可以不实现抽象类声明的所有方法,当然,在这种情况下,类也必须得声明成是抽象的。
  • 抽象类可以在不提供接口方法实现的情况下实现接口。
  • Java接口中声明的变量默认都是final的。抽象类可以包含非final的变量。
  • Java接口中的成员函数默认是public的。抽象类的成员函数可以是private,protected或者是public。
  • 接口是绝对抽象的,不可以被实例化。抽象类也不可以被实例化,但是,如果它包含main方法的话是可以被调用的。

12.字符串

Java中的字符串常量池
Java细节:字符串的拼接

13. java并发

  • volatile的原理
    Java并发编程:volatile关键字解析
  • synchronized的原理
    Java并发编程:Synchronized及其实现原理
  • java.util.concurrent包详解
    Java - concurrent包详解
  • lock的实现原理

Android

Android基础知识

1. Android生命周期

  • 重新认识Android Activity的生命周期
  • Android多个Activity切换时其生命周期中的方法执行顺序

2. Android启动模式

  • 深入讲解Android中Activity launchMode
  • Android中Activity四种启动模式和taskAffinity属性详解

3. Service

Android Service完全解析,关于服务你所需知道的一切

Service两种启动方式的区别

Android 服务两种启动方式的区别

如何让一个Service一直保持存活?

IntentService的特点
  • 它创建了一个独立的工作线程来处理所有的通过onStartCommand()传递给服务的intents。
  • 创建了一个工作队列,来逐个发送intent给onHandleIntent()。
  • 不需要主动调用stopSelft()来结束服务。因为,在所有的intent被处理完后,系统会自动关闭服务。
  • 默认实现的onBind()返回null
  • 默认实现的onStartCommand()的目的是将intent插入到工作队列中

4. 自定义view

Android LayoutInflater原理分析,带你一步步深入了解View
Android View 四个构造函数详解

5.DiskLruCache LruCache

Android DiskLruCache完全解析,硬盘缓存的最佳方案

6.Touch事件传递机制

Android Touch事件传递机制通俗讲解

  1. Touch事件分发中只有两个主角:ViewGroup和View。ViewGroup包含onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent三个相关事件。View包含dispatchTouchEvent、onTouchEvent两个相关事件。其中ViewGroup又继承于View。
  2. ViewGroup和View组成了一个树状结构,根节点为Activity内部包含的一个ViwGroup。
  3. 触摸事件由Action_Down、Action_Move、Aciton_UP组成,其中一次完整的触摸事件中,Down和Up都只有一个,Move有若干个,可以为0个。
  4. 当Acitivty接收到Touch事件时,将遍历子View进行Down事件的分发。ViewGroup的遍历可以看成是递归的。分发的目的是为了找到真正要处理本次完整触摸事件的View,这个View会在onTouchEvent结果返回true。
  5. 当某个子View返回true时,会中止Down事件的分发,同时在ViewGroup中记录该子View。接下去的Move和Up事件将由该子View直接进行处理。由于子View是保存在ViewGroup中的,多层ViewGroup的节点结构时,上级ViewGroup保存的会是真实处理事件的View所在的ViewGroup对象:如ViewGroup0-ViewGroup1-TextView的结构中,TextView返回了true,它将被保存在ViewGroup1中,而ViewGroup1也会返回true,被保存在ViewGroup0中。当Move和UP事件来时,会先从ViewGroup0传递至ViewGroup1,再由ViewGroup1传递至TextView。
  6. 当ViewGroup中所有子View都不捕获Down事件时,将触发ViewGroup自身的onTouch事件。触发的方式是调用super.dispatchTouchEvent函数,即父类View的dispatchTouchEvent方法。在所有子View都不处理的情况下,触发Acitivity的onTouchEvent方法。
  7. onInterceptTouchEvent有两个作用:1.拦截Down事件的分发。2.中止Up和Move事件向目标View传递,使得目标View所在的ViewGroup捕获Up和Move事件。
dispatchTouchEvent源码分析总结
  1. 触摸控件(View)首先执行dispatchTouchEvent方法。
    在dispatchTouchEvent方法中先执行onTouch方法,后执行onClick方法(onClick方法在onTouchEvent中执行,下面会分析)。
  2. 如果控件(View)的onTouch返回false或者mOnTouchListener为null(控件没有设置setOnTouchListener方法)或者控件不是enable的情况下会调运onTouchEvent,dispatchTouchEvent返回值与onTouchEvent返回一样。
  3. 如果控件不是enable的设置了onTouch方法也不会执行,只能通过重写控件的onTouchEvent方法处理(上面已经处理分析了),dispatchTouchEvent返回值与onTouchEvent返回一样。
  4. 如果控件(View)是enable且onTouch返回true情况下,dispatchTouchEvent直接返回true,不会调用onTouchEvent方法。

7.动画

Android属性动画完全解析,初识属性动画的基本用法

8.View的绘制流程

从ViewRoot的performTraversals()方法开始依次调用perfromMeasure、performLayout和performDraw这三个方法。这三个方法分别完成顶级View的measure、layout和draw三大流程,其中perfromMeasure会调用measure,measure又会调用onMeasure,在onMeasure方法中则会对所有子元素进行measure,这个时候measure流程就从父容器传递到子元素中了,这样就完成了一次measure过程,接着子元素会重复父容器的measure,如此反复就完成了整个View树的遍历.

同理,performLayout和performDraw也分别完成perfromMeasure类似的流程。通过这三大流程,分别遍历整棵View树,就实现了Measure,Layout,Draw这一过程,View就绘制出来了。

9.Android性能优化

  • 布局优化:尽量减少布局文件的层级,删除布局中无用的控件和层级。 提供按需加载的功能
  • 绘制优化:onDraw()方法中不要创建新的局部对象,不要做耗时的任务 GPU过度绘制 HierarchyView来检测 开发者选项 显示开发者过度绘制选项
  • 内存泄露优化:context、handler、bitmap、单例模式、内部类、静态变量、资源对象没有关闭
  • 响应速度优化和ANR日志分析:避免在主线程中做耗时操作,系统会在/data/anr目录下创建一个文件traces.txt
  • 避免创建过多的对象
  • 不要过多使用枚举,枚举占用的内存空间要比整型大
  • 常量请使用static final 来修饰
  • 使用一些Android特有的数据结构,比如SparseArray和Pair等,他们都具有更好的性能
  • 适当使用软引用和弱引用
  • 采用内存缓存和磁盘缓存
  • 尽量采用静态内部类,这样可以避免潜在的由于内部类而导致的内存泄露
  • Android的性能优化
  • Android应用开发性能优化完全分析

10.MVP模式

浅谈 MVP in Android

11.横竖屏切换,Android生命周期的变化

  • 不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次
  • 设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次
  • 设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法

11.WebView

WebView性能、体验分析与优化
Android中Java和JavaScript交互

12. Android中出现65536的限制的原因以及解决办法

Android dex 65536 的原因 以及解决办法

13. Android Lint的工作机制原理

Android Lint工作原理剖析

14. Android中的Dalvik VM ART JVM 的区别

Android 中的Dalvik和ART是什么,有啥区别?
Dalvik 虚拟机和 Sun JVM 在架构和执行方面有什么本质区别?

15.Android内存泄露问题

避免Android中Context引起的内存泄露
译文:Android中糟糕的AsyncTask
Android中Handler引起的内存泄露
Android内存泄漏总结

16. RecyclerView和ListView的区别

  • RecyclerView的ViewHolder规范化
  • RecyclerView可以实现线性布局效果,网格布局效果,瀑布流布局效果
  • ListView具有setEmptyView() addHeaderView() addFooterView()
    Android 优雅的为RecyclerView添加HeaderView和FooterView
  • RecyclerView支持局部刷新
  • listview实现局部刷新 https://juejin.im/entry/581bdee6570c35006094a30e
  • RecyclerView轻松实现item动画效果
  • RecyclerView没有setOnItemClickListener() setOnItemLongClickListener() 而是实现了RecyclerView.OnItemTouchListener()
    android开发游记:RecyclerView无法添加onItemClickListener最佳的高效解决方案
  • RecyclerView自定义分割线

17.compileSdkVersion, minSdkVersion 和 targetSdkVersion区别

如何选择 compileSdkVersion, minSdkVersion 和 targetSdkVersion

18. RelativeLayout和LinearLayout性能分析

Android中RelativeLayout和LinearLayout性能分析

  • RelativeLayout会让子View调用2次onMeasure,LinearLayout 在有weight时,也会调用子View2次onMeasure
  • RelativeLayout的子View如果高度和RelativeLayout不同,则会引发效率问题,当子View很复杂时,这个问题会更加严重。如果可以,尽量使用padding代替margin。
  • 在不影响层级深度的情况下,使用LinearLayout和FrameLayout而不是RelativeLayout。
  • 为什么Google给开发者默认新建了个RelativeLayout,而自己却在DecorView中用了个LinearLayout。因为DecorView的层级深度是已知而且固定的,上面一个标题栏,下面一个内容栏。采用RelativeLayout并不会降低层级深度,所以此时在根节点上用LinearLayout是效率最高的。而之所以给开发者默认新建了个RelativeLayout是希望开发者能采用尽量少的View层级来表达布局以实现性能最优,因为复杂的View嵌套对性能的影响会更大一些。

19. 图片处理

Android高效加载大图、多图解决方案,有效避免程序OOM

20. 屏幕适配问题

21. 多进程的知识

Android API源码和第三方框架源码

1. AsyncTask

Android AsyncTask 源码解析

  1. 设置当前AsyncTask的状态为RUNNING,上面的switch也可以看出,每个异步任务在完成前只能执行一次。
  2. 执行了onPreExecute(),当前依然在UI线程,所以我们可以在其中做一些准备工作。
  3. 将我们传入的参数赋值给了mWorker.mParams ,mWorker为一个Callable的子类,且在内部的call()方法中,调用了doInBackground(mParams),然后得到的返回值作为postResult的参数进行执行;postResult中通过sHandler发送消息,最终sHandler的handleMessage中完成onPostExecute的调用。
  4. exec.execute(mFuture),mFuture为真正的执行任务的单元,将mWorker进行封装,然后由sDefaultExecutor交给线程池进行执行。

如果现在大家去面试,被问到AsyncTask的缺陷,可以分为两个部分说,在3.0以前,最大支持128个线程的并发,10个任务的等待。在3.0以后,无论有多少任务,都会在其内部单线程执行;

2. Handler

Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系

  1. 首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象;因为Looper.prepare()在一个线程中只能调用一次,所以MessageQueue在一个线程中只会存在一个。
  2. Looper.loop()会让当前线程进入一个无限循环,不端从MessageQueue的实例中读取消息,然后回msg.target.dispatchMessage(msg)方法。
  3. Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。
  4. Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。
  5. 在构造Handler实例时,我们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法。

好了,总结完成,大家可能还会问,那么在Activity中,我们并没有显示的调用Looper.prepare()和Looper.loop()方法,为啥Handler可以成功创建呢,这是因为在Activity的启动代码中,已经在当前UI线程调用了Looper.prepare()和Looper.loop()方法。

3.Retrofit

Android:手把手带你深入剖析 Retrofit 2.0 源码

Retrofit分析-漂亮的解耦套路

4. Glide

Android图片加载框架最全解析,Glide的基本用法

5.OkHttp

拆轮子系列:拆 OkHttp

6.HandlerThread

Android HandlerThread 源码分析

7. IntentService

Android IntentService完全解析 当Service遇到Handler

8. leakcanary

LeakCanary 工作原理浅析

9. Volley

  1. 当一个RequestQueue被成功申请后会开启一个CacheDispatcher和4个默认的NetworkDispatcher。
  2. CacheDispatcher缓存调度器最为第一层缓冲,开始工作后阻塞的从缓存序列mCacheQueue中取得请求;对于已经取消的请求,标记为跳过并结束这个请求;新的或者过期的请求,直接放入mNetworkQueue中由N个NetworkDispatcher进行处理;已获得缓存信息(网络应答)却没有过期的请求,由Request的parseNetworkResponse进行解析,从而确定此应答是否成功。然后将请求和应答交由Delivery分发者进行处理,如果需要更新缓存那么该请求还会被放入mNetworkQueue中。
  3. 将请求Request add到RequestQueue后对于不需要缓存的请求(需要额外设置,默认是需要缓存)直接丢入mNetworkQueue交给N个NetworkDispatcher处理;对于需要缓存的,新的请求加到mCacheQueue中给CacheDispatcher处理;需要缓存,但是缓存列表中已经存在了相同URL的请求,放在mWaitingQueue中做暂时处理,等待之前请求完毕后,再重新添加到mCacheQueue中。
  4. 网络请求调度器NetworkDispatcher作为网络请求真实发生的地方,对消息交给BasicNetwork进行处理,同样的,请求和结果都交由Delivery分发者进行处理。
  5. Delivery分发者实际上已经是对网络请求处理的最后一层了,在Delivery对请求处理之前,Request已经对网络应答进行过解析,此时应答成功与否已经设定;而后Delivery根据请求所获得的应答情况做不同处理;若应答成功,则触发deliverResponse方法,最终会触发开发者为Request设定的Listener;若应答失败,则触发deliverError方法,最终会触发开发者为Request设定的ErrorListener;处理完后,一个Request的生命周期就结束了,Delivery会调用Request的finish操作,将其从mRequestQueue中移除,与此同时,如果等待列表中存在相同URL的请求,则会将剩余的层级请求全部丢入mCacheQueue交由CacheDispatcher进行处理。

数据结构与算法

1. 算法实现统计出Activity中的view树的深度

2. HashMap

Java集合---HashMap源码剖析

3. LinkedList

Java集合---LinkedList源码解析

4. ArrayList

Java集合---ArrayList的实现原理

5.ConcurrentHashMap

Java并发编程:并发容器之ConcurrentHashMap(转载)

6.List Map Set的区别

浅谈Java中的Set、List、Map的区别

7. 快速排序

图解快速排序

8. 二分查找

二分查找算法(递归与非递归两种方式)

9.数组去重

Java实现数组去重、排序操作

其他问题

1. 工作中遇到一次最大困难时什么 你最后是怎么解决的 如果让你再来一次你是否能够解决的更好

2. 职业规划

3. HTTP和HTTPS的区别

  • HTTP协议使用默认80端口,HTTPS协议使用443端口
  • HTTPS协议需要到CA申请证书,一般免费的证书较少,需要交费
  • HTTP信息是明文传输,HTTPS使用具有安全性的SSL加密传输信息

4. http1和http2的区别

  • http2可以同时发多个请求
  • http2会压缩,体积小
  • http2服务器会推送

3. 加密算法有哪些?对称加密和非对称加密的区别?

MD5,SHA1,Base64,RSA,AES,DES

非对称密钥加密的使用过程:
  1. A要向B发送信息,A和B都要产生一对用于加密和解密的公钥和私钥。
  2. A的私钥保密,A的公钥告诉B;B的私钥保密,B的公钥告诉A。
  3. A要给B发送信息时,A用B的公钥加密信息,因为A知道B的公钥。
  4. A将这个消息发给B(已经用B的公钥加密消息)。
  5. B收到这个消息后,B用自己的私钥解密A的消息,其他所有收到这个报文的人都无法解密,因为只有B才有B的私钥。
  6. 反过来,B向A发送消息也是一样。
对称加密和非对称加密的区别
  1. 对称加密加密与解密使用的是同样的密钥,所以速度快,但由于需要将密钥在网络传输,所以安全性不高。
  2. 非对称加密使用了一对密钥,公钥与私钥,所以安全性高,但加密与解密速度慢。
  3. 解决的办法是将对称加密的密钥使用非对称加密的公钥进行加密,然后发送出去,接收方使用私钥进行解密得到对称加密的密钥,然后双方可以使用对称加密来进行沟通。

面经

一年Android工作经验,一举拿下百度、网易、美团、小米、快手等Offer面经

2017年4月x团面试总结[新]

你可能感兴趣的:(Android史上最全面试题(持续更新ing))