热门搜索 :
考研考公
您的当前位置:首页正文

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垃圾回收机制

2. hashCode()和equals()

3. java内存管理

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

4.线程池

5. 进程和线程的关系

6. Thread和Runnable的区别

7. 死锁

8. 单例

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

10. http

11. 接口和抽象类的区别

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

12.字符串

13. java并发

  • volatile的原理
  • synchronized的原理
  • java.util.concurrent包详解
  • lock的实现原理

Android

Android基础知识

1. Android生命周期

2. Android启动模式

3. Service

Service两种启动方式的区别

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

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

4. 自定义view

5.DiskLruCache LruCache

6.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.动画

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性能优化

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

10.MVP模式

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

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

11.WebView

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

13. Android Lint的工作机制原理

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

15.Android内存泄露问题

16. RecyclerView和ListView的区别

  • RecyclerView的ViewHolder规范化
  • RecyclerView可以实现线性布局效果,网格布局效果,瀑布流布局效果
  • ListView具有setEmptyView() addHeaderView() addFooterView()
  • RecyclerView支持局部刷新
  • listview实现局部刷新
  • RecyclerView轻松实现item动画效果
  • RecyclerView没有setOnItemClickListener() setOnItemLongClickListener() 而是实现了RecyclerView.OnItemTouchListener()
  • RecyclerView自定义分割线

minSdkVersion 和 targetSdkVersion区别

18. 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. 图片处理

20. 屏幕适配问题

21. 多进程的知识

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

1. 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

  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

4. Glide

5.OkHttp

6.HandlerThread

7. IntentService

8. 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

3. LinkedList

4. ArrayList

5.ConcurrentHashMap

6.List Map Set的区别

7. 快速排序

8. 二分查找

9.数组去重

其他问题

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. 解决的办法是将对称加密的密钥使用非对称加密的公钥进行加密,然后发送出去,接收方使用私钥进行解密得到对称加密的密钥,然后双方可以使用对称加密来进行沟通。

面经

Top