美文网首页Android 面试专辑半栈工程师AndroidWorld
Android 中级面试题汇总(201811更)

Android 中级面试题汇总(201811更)

作者: KT_11 | 来源:发表于2018-10-23 23:12 被阅读285次

    本文主要适用于中小厂、初中级面试,供1-3年的Android开发参考

    • 暂时仅有Android和少量Java,无算法、数据结构
    • 个人收集,题目和答案仅供参考,相关知识点不清楚可以自行搜索技术博客
    • 持续更新中
      创建时间:2018-10-23
      最近更新时间为:2018-11-7=>11-23

    目录

    (1 常问 2 偶尔问)

    1-1 Activity生命周期
    1-2 Service生命周期
    1-3 理解Activity、View、Window三者关系
    1-4 Activity四种LaunchMode启动模式及其使用场景
    1-5 Touch事件传递机制
    1-6 View的绘制流程
    1-7 Android中的动画有哪些
    1-8 谈谈你对binder机制的理解](楼主不熟)
    1-9 Android中进程间通信有哪些实现方式](楼主不熟)
    1-10 实现一个自定义view的基本流程
    1-11 ANR是什么?怎样避免和解决ANR?
    1-12 谈谈AIDL机制](楼主不熟)
    1-13 Android异步消息处理机制
    1-14 Android性能优化
    1-15 内存泄漏和内存溢出是什么?一般怎么处理内存泄漏?
    1-16 谈谈IntentService
    1-17 广播注册方式与区别
    1-18 如何进程保活?能否保证service不被杀死?
    1-19 怎么避免OOM?怎么避免图片加载导致的OOM?
    1-20 Android UI适配
    1-21 JAVA GC原理
    1-22 Fragment与Fragment、Activity通信的方式
    1-23 RecyclerView和ListView的区别
    1-24 图片框架为什么要用Glide?它和Universal-ImageLoader,Picasso,Fresco对比?
    1-25 网络框架为什么要用OKhttp? 它和Xutils, Volley, Retrofit对比?
    1-26 熟悉哪些设计模式?

    2-1 Activity在屏幕旋转时的生命周期
    2-2 怎样解决方法数65K的问题
    2-3 浅谈MVC、 MVP、 MVVM区别与联系(楼主不熟)
    2-4 什么是三级缓存?三级缓存的原理?
    2-5 热修复的原理?
    2-6 AsyncTask的内部实现、适用场景
    2-7 谈谈Context


    1 常问

    1-1 Activity生命周期

    • onCreate() 创建活动,做一些数据初始化操作
      onStart() 由不可见变为可见
      onResume() 可以与用户进行交互,位于栈顶
      onPause() 暂停,启动或恢复另一个活动时调用
      onStop() 停止,变为不可见
      onDestroy() 销毁
      onRestart() 由停止状态变为运行状态

    可参考 https://www.jianshu.com/p/f2a81c6b6c00


    1-2 Service生命周期

    • onCreate()
      首次创建服务时,系统将调用此方法。如果服务已在运行,则不会调用此方法,该方法只调用一次。
    • onStartCommand()
      当另一个组件通过调用startService()请求启动服务时,系统将调用此方法。
    • onDestroy()
      当服务不再使用且将被销毁时,系统将调用此方法。
    • onBind()
      当另一个组件通过调用bindService()与服务绑定时,系统将调用此方法。
    • onUnbind()
      当另一个组件通过调用unbindService()与服务解绑时,系统将调用此方法。
    • onRebind()
      当旧的组件与服务解绑后,另一个新的组件与服务绑定,onUnbind()返回true时,系统将调用此方法。

    Service生命周期分为三种情况,非绑定模式、绑定模式 、混合模式

    • 第一种
      用startService()启动服务、stopService()停止服务:
      startService()->onCreate() -> onStartCommand() ->stopService() ->onDestory
    • 第二种
      用bindService()绑定服务、unbindService()解绑服务:
      bindService()->onCreate() -> onBind() ->unbindService()-> onUnBind() -> onDestory
    • 第三种
      如果同时使用startService()和bindService(),则需要同时停止服务和解绑服务
      startService()->bindService()->onCreate() -> onStartCommnad() -> onBind() ->stopService() ->unbindService()-> onUnBind() -> onDestory

    此外要注意
    startService()开启Service后,调用者退出后Service仍然存在。
    bindService()开启Service后,调用者退出后Service也随即退出。


    1-3 理解Activity、View、Window三者关系

    • 比喻:Activity像一个工匠(控制单元),Window像窗户(承载模型),View像窗花(显示视图)LayoutInflater像剪刀,Xml配置像窗花图纸。
    • Activity构造的时候会初始化一个Window,准确的说是PhoneWindow
    • 这个PhoneWindow有一个ViewRoot,这个ViewRoot是一个View或者说ViewGroup,是最初始的根视图。
    • ViewRoot通过addView方法来一个个的添加View。比如TextView,Button等
    • 这些View的事件监听,是由WindowManagerService来接受消息,并且回调Activity函数。比如onClickListener,onKeyDown等。

    1-4 四种LaunchMode启动模式及其使用场景

    (1)standard
    默认模式,每次启动活动都重新创建一个新的实例
    (2)singleTop
    在配置文件activity中加入android:launchMode="singleTop"
    在启动活动时如果发现返回栈的栈顶已经是该活动,则直接使用它(并调用onNewIntent方法),否则会重新创建一个新的实例
    (3)singleTask
    每次启动该活动时,系统首先会在返回栈中检查是否存在该活动的实例,如果发现已经存在则直接使用该实例(并调用onNewIntent方法),并把这个活动之上所有活动统统出栈,如果没有发现则会创建一个新的实例
    (4)singleInstance
    该模式的活动每次会请求一个新的返回栈来管理这个活动
    主要适用于,当前程序和其他程序共享一个活动实例的时候才用到这个模式


    1-5 Touch事件传递机制

    • 在我们点击屏幕时,会有下列事件发生:
      Activity调用dispathTouchEvent()方法,把事件传递给Window;
      Window再将事件交给DecorView(DecorView是View的根布局);
      DecorView再传递给ViewGroup;
    • Activity ——> Window ——> DecorView ——> ViewGroup——> View
    • 事件分发的主要有三个关键方法
      dispatchTouchEvent() 分发
      onInterceptTouchEvent() 拦截 ,只有ViewGroup独有此方法
      onTouchEvent() 处理触摸事件
    • Activity首先调用dispathTouchEvent()进行分发,接着调用super向下传递
    • ViewGroup首先调用dispathTouchEvent()进行分发,接着会调用onInterceptTouchEvent()(拦截事件)。若拦截事件返回为true,表示拦截,事件不会向下层的ViewGroup或者View传递;false,表示不拦截,继续分发事件。默认是false,需要提醒一下,View是没有onInterceptTouchEvent()方法的
    • 事件在ViewGroup和ViewGroup、ViewGroup和View之间进行传递,最终到达View;
    • View调用dispathTouchEvent()方法,然后在OnTouchEvent()进行处理事件;OnTouchEvent() 返回true,表示消耗此事件,不再向下传递;返回false,表示不消耗事件,交回上层处理。

    上面只是简单的介绍流程
    很多细节如三种方法各自返回true或false接下来会怎么走,这涉及到的就比较多了
    如果可以的话,我宁愿画一张图,凭此图就可以说明所有可能发生的情况,也是分发机制的精髓所在
    可参考这篇文章,心里过一遍流程


    1-6 View的绘制流程

    • View的绘制流程:OnMeasure()——>OnLayout()——>OnDraw()
      各步骤的主要工作:
    • OnMeasure():测量View大小。从顶层父View到子View递归调用measure方法,measure方法又回调OnMeasure。
    • OnLayout():确定View位置,进行页面布局。从顶层父View向子View的递归调用view.layout方法的过程,即父View根据上一步measure子View所得到的布局大小和布局参数,将子View放在合适的位置上。
    • OnDraw():绘制View。ViewRoot创建一个Canvas对象,然后调用OnDraw()。六个步骤:①、绘制视图的背景;②、保存画布的图层(Layer);③、绘制View的内容;④、绘制View子视图,如果没有就不用;⑤、还原图层(Layer);⑥、绘制滚动条。

    1-7 Android中的动画有哪些

    • 逐帧动画(Frame Animation)
      加载一系列Drawable资源来创建动画,简单来说就是播放一系列的图片来实现动画效果,可以自定义每张图片的持续时间
    • 补间动画(Tween Animation)
      Tween可以对View对象实现一系列动画效果,比如平移,缩放,旋转,透明度等。但是它并不会改变View属性的值,只是改变了View的绘制的位置,比如,一个按钮在动画过后,不在原来的位置,但是触发点击事件的仍然是原来的坐标。
    • 属性动画(Property Animation)
      动画的对象除了传统的View对象,还可以是Object对象,动画结束后,Object对象的属性值被实实在在的改变了

    1-8 谈谈你对binder机制的理解

    • 在Android系统的Binder机制中,是有Client,Service,ServiceManager,Binder驱动程序组成的,其中Client,service,Service Manager运行在用户空间,Binder驱动程序是运行在内核空间的。而Binder就是把这4种组件粘合在一块的粘合剂,其中核心的组件就是Binder驱动程序,Service Manager提供辅助管理的功能,而Client和Service正是在Binder驱动程序和Service Manager提供的基础设施上实现C/S 之间的通信。其中Binder驱动程序提供设备文件/dev/binder与用户控件进行交互,Client、Service,Service Manager通过open和ioctl文件操作相应的方法与Binder驱动程序进行通信。而Client和Service之间的进程间通信是通过Binder驱动程序间接实现的。而Binder Manager是一个守护进程,用来管理Service,并向Client提供查询Service接口的能力。

    1-9 Android中进程间通信有哪些实现方式

    • Android 跨进程通信,像intent,contentProvider,广播,service都可以跨进程通信。
      intent:这种跨进程方式并不是访问内存的形式,它需要传递一个uri,比如说打电话。
      contentProvider:这种形式,是使用数据共享的形式进行数据共享。
      service:远程服务,aidl
      广播

    1-10 实现一个自定义view的基本流程

    • 1、自定义View的属性 编写attr.xml文件
      2、在layout布局文件中引用,同时引用命名空间
      3、在View的构造方法中获得我们自定义的属性 ,在自定义控件中进行读取(构造方法拿到attr.xml文件值)
      4、重写onMesure
      5、重写onDraw

    1-11 ANR是什么?怎样避免和解决ANR

    • Application Not Responding,即应用无响应
    • 出现的原因有三种:
      a)KeyDispatchTimeout(5 seconds)主要类型按键或触摸事件在特定时间内无响应
      b)BroadcastTimeout(10 seconds)BoradcastReceiver在特定的时间内无法处理
      c)ServiceTimeout(20 seconds)小概率类型Service在特定的时间内无法处理完成
    • 避免ANR最核心的一点就是在主线程减少耗时操作。通常需要从那个以下几个方案下手:
      a)使用子线程处理耗时IO操作
      b)降低子线程优先级,使用Thread或者HandlerThread时,调用Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)设置优先级,否则仍然会降低程序响应,因为默认Thread的优先级和主线程相同
      c)使用Handler处理子线程结果,而不是使用Thread.wait()或者Thread.sleep()来阻塞主线程
      d)Activity的onCreate和onResume回调中尽量避免耗时的代码
      e)BroadcastReceiver中onReceiver代码也要尽量减少耗时操作,建议使用intentService处理。intentService是一个异步的,会自动停止的服务,很好解决了传统的Service中处理完耗时操作忘记停止并销毁Service的问题

    1-12 谈谈AIDL机制

    • AIDL(Android Interface Definition Language), Android 接口定义语言,Android 提供的IPC(InterProcess Communication,进程间通信)的一种独特实现。
      使用AIDL只有在你允许来自不同应用的客户端夸进程通信访问你的service,并且想要在你的service中处理多线程的时候才时必要的。如果你不需要执行不同应用之间的IPC并发,你应该通过实现Binder建立你的接口,或者如果你想执行IPC,但是不需要处理多线程。那么使用Messenger实现你的接口
      a)建立.aidl文件
      b)实现这个接口
      c)暴露这个接口给客户端

    1-13 Android异步消息处理机制

    • 异步消息处理机制主要是用来解决子线程更新UI的问题
    • 主要有四个部分:
      1. Message (消息)
      在线程之间传递,可在内部携带少量信息,用于不同线程之间交换数据
      可以使用what、arg1、arg2字段携带整型数据
      obj字段携带Object对象
      2. Handler (处理者)
      主要用于发送和处理消息,sendMessage()用来发送消息,最终会回到handleMessage()进行处理
      3. MessageQueue (消息队列)
      主要存放所有通过Handler发送的消息,它们会一直存在于队列中等待被处理
      每个线程只有一个MessageQueue
      4. Looper (循环器)
      调用loop()方法后,会不断从MessageQueue 取出待处理的消息,然后传递到handleMessage进行处理
    • 流程:
      首先在主线程中创建一个Handler对象,并重写handleMessage()方法
      然后当子线程需要更新UI的时候,就创建一个Message对象,并通过Handler的sendMessage()方法把消息发送出去,然后这条消息会被添加到MessageQueue的队列中等待被处理
      而Looper会一直从MessageQueue中取出待处理的消息,最后分发回Handler的handleMessage()进行处理,此时处于主线程,可以更新UI

    1-14 Android性能优化


    1-15 内存泄漏和内存溢出是什么?一般怎么处理内存泄漏?

    (1)内存溢出(OOM)和内存泄露(对象无法被回收)的区别。
    (2)引起内存泄露的原因
    (3)内存泄露检测工具 ------>LeakCanary

    • 内存溢出 out of memory:是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。内存溢出通俗的讲就是内存不够用。
    • 内存泄露 memory leak:是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光
    • 内存泄露原因以及解决:
      一、Handler 引起的内存泄漏。
      解决:将Handler声明为静态内部类,就不会持有外部类SecondActivity的引用,其生命周期就和外部类无关,
      如果Handler里面需要context的话,可以通过弱引用方式引用外部类
      二、单例模式引起的内存泄漏。
      解决:Context是ApplicationContext,由于ApplicationContext的生命周期是和app一致的,不会导致内存泄漏
      三、非静态内部类创建静态实例引起的内存泄漏。
      解决:把内部类修改为静态的就可以避免内存泄漏了
      四、非静态匿名内部类引起的内存泄漏。
      解决:将匿名内部类设置为静态的。
      五、注册/反注册未成对使用引起的内存泄漏。
      注册广播接受器、EventBus等,记得解绑。
      六、资源对象没有关闭引起的内存泄漏。
      在这些资源不使用的时候,记得调用相应的类似close()、destroy()、recycler()、release()等方法释放。
      七、集合对象没有及时清理引起的内存泄漏。
      通常会把一些对象装入到集合中,当不使用的时候一定要记得及时清理集合,让相关对象不再被引用。

    1-16 谈谈IntentService

    • IntentService是继承于Service并处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统Service一样,同时,当任务执行完后,IntentService会自动停止,而不需要我们去手动控制。另外,可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。所有请求都在一个单线程中,不会阻塞应用程序的主线程(UI Thread),同一时间只处理一个请求
    • 优点:
    1. 我们省去了在Service中手动开线程的麻烦,
    2. 当操作完成时,我们不用手动停止Service

    1-17 广播注册方式与区别

    • Broadcast广播,注册方式主要有两种.
    • 第一种是静态注册,也可成为常驻型广播,这种广播需要在Androidmanifest.xml中进行注册,这中方式注册的广播,不受页面生命周期的影响,即使退出了页面,也可以收到广播这种广播一般用于想开机自启动啊等等,由于这种注册的方式的广播是常驻型广播,所以会占用CPU的资源。
    • 第二种是动态注册,而动态注册的话,是在代码中注册的,这种注册方式也叫非常驻型广播,收到生命周期的影响,退出页面后,就不会收到广播,我们通常运用在更新UI方面。这种注册方式优先级较高。最后需要解绑,否会会内存泄露
      广播是分为有序广播和无序广播。

    1-18 进程保活? 能否保证service不被杀死?

    进程保活
    先参考这篇 https://blog.csdn.net/Go_AheadY/article/details/79420027
    后面会再详细深入学习

    避免service被杀掉

    • 1.Service设置成START_STICKY
      kill 后会被重启(等待5秒左右),重传Intent,保持与重启前一样
    • 2.提升service进程优先级
      Android中的进程是托管的,当系统进程空间紧张的时候,会依照优先级自动进行进程的回收当service运行在低内存的环境时,将会kill掉一些存在的进程。因此进程的优先级将会很重要,可以在startForeground()使用startForeground()将service放到前台状态。这样在低内存时被kill的几率会低一些。
      【结论】如果在极度极度低内存的压力下,该service还是会被kill掉,并且不一定会restart()
    • 3.onDestroy方法里重启serviceservice +broadcast 方式
      就是当service走onDestory()的时候,发送一个自定义的广播,当收到广播的时候,重新启动service,也可以直接在onDestroy()里startService
      【结论】当使用类似口口管家等第三方应用或是在setting里-应用-强制停止时,APP进程可能就直接被干掉了,onDestroy方法都进不来,所以还是无法保证

    1-19 怎么避免内存溢出OOM?怎么避免图片加载导致的OOM?

    避免内存溢出OOM

    • 防止内存泄露
      避免OOM就是要剩余足够堆内存供应用使用,要想内存足够呢,首先就需要避免应用存在内存泄漏的情况,内存泄漏后,可使用的内存空间减少,自然就会更容易产生OOM。
    • 减小对象的内存占用
      1.使用更加轻量的数据结构,例如,我们可以考虑使用ArrayMap/SparseArray而不是HashMap等传统数据结构
      2.减小Bitmap对象的内存占用
    • 内存对象的重复利用
      1.复用系统自带的资源
      2.注意在ListView/GridView等出现大量重复子组件的视图里对ConvertView的复用
      3.Bitmap对象的复用
      4.代码中会需要使用到大量的字符串拼接的操作,这种时候有必要考虑使用StringBuilder来替代频繁的“+”

    图片加载导致的OOM怎么办?

    • 1.压缩图片
      在展示高分辨率图片的时候,最好先将图片进行压缩。压缩后的图片大小应该和用来展示它的控件大小相近,在一个很小的ImageView上显示一张超大的图片不会带来任何视觉上的好处,但却会占用我们相当多宝贵的内存,而且在性能上还可能会带来负面影响。
    • 2.使用图片缓存技术
      内存缓存技术对那些大量占用应用程序宝贵内存的图片提供了快速访问的方法。其中最核心的类是LruCache (此类在android-support-v4的包中提供) 。这个类非常适合用来缓存图片,它的主要算法原理是把最近使用的对象用强引用存储在 LinkedHashMap 中,并且把最近最少使用的对象在缓存值达到预设定值之前从内存中移除。
    • 3.及时回收bitmap内存
      虽然android系统有自己的gc机制,但是bitmap分为java和C两部分,这个bitmap对象是由java部分分配的,不用的时候系统就会自动回收了,但是那个对应的C可用的内存区域,虚拟机时不能直接回收的,这个只能调用底层的功能释放,所以需要调用recycle()方法来释放C部分内存。
    • 4.捕获异常
      因为bitmap是吃内存大户,为了避免应用在分配bitmap内存的时候出现OutOfMemory异常以后Crash掉,对异常进行捕获,如果发生了OOM后,应用不会崩溃,而是得到一个默认的bitmap图。

    1-20 Android UI适配

    • 字体使用sp,使用dp,多使用match_parent,wrap_content,weight
      图片资源,不同图片的的分辨率,放在相应的文件夹下可使用百分比代替。

    1-21 JAVA GC原理

    • 垃圾收集算法的核心思想是:对虚拟机可用内存空间,即堆空间中的对象进行识别,如果对象正在被引用,那么称其为存活对象
      ,反之,如果对象不再被引用,则为垃圾对象,可以回收其占据的空间,用于再分配。垃圾收集算法的选择和垃圾收集系统参数的合理调节直接影响着系统性能。

    1-22 Fragment与Fragment、Activity通信的方式

    • 1.直接在一个Fragment中调用另外一个Fragment中的方法
      2.使用接口回调
      3.使用广播
      4.Fragment直接调用Activity中的public方法

    1-23 RecyclerView和ListView的区别

    • RecyclerView可以完成ListView,GridView的效果,还可以完成瀑布流的效果。同时还可以设置列表的滚动方向(垂直或者水平);
      RecyclerView中view的复用不需要开发者自己写代码,系统已经帮封装完成了。
      RecyclerView可以进行局部刷新。
      RecyclerView提供了API来实现item的动画效果。
    • 在性能上:
      如果需要频繁的刷新数据,需要添加动画,则RecyclerView有较大的优势。
      如果只是作为列表展示,则两者区别并不是很大。

    1-24 图片框架为什么要用Glide?它和Universal-ImageLoader,Picasso,Fresco区别?

    • ImageLoader :
      优点:
      ① 支持下载进度监听;
      ② 可以在 View 滚动中暂停图片加载;
      ③ 默认实现多种内存缓存算法这几个图片缓存都可以配置缓存算法,不过 ImageLoader 默认实现了较多缓存算法,如 Size 最大先删除、使用最少先删除、最近最少使用、先进先删除、时间最长先删除等;
      ④ 支持本地缓存文件名规则定义;
      缺点:
      缺点在于不支持GIF图片加载, 缓存机制没有和http的缓存很好的结合, 完全是自己的一套缓存机制
    • Picasso:
      优点:
      ① 自带统计监控功能,支持图片缓存使用的监控,包括缓存命中率、已使用内存大小、节省的流量等。
      ② 支持优先级处理
      ③ 支持延迟到图片尺寸计算完成加载
      ④ 支持飞行模式、并发线程数根据网络类型而变,手机切换到飞行模式或网络类型变换时会自动调整线程池最大并发数。
      ⑤ “无”本地缓存。Picasso 自己没有实现本地缓存,而由okhttp 去实现,这样的好处是可以通过请求 Response Header 中的 Cache-Control 及 Expired 控制图片的过期时间。
      缺点:
      于不支持GIF,默认使用ARGB_8888格式缓存图片,缓存体积大。
    • Glide:
      优点:
      ① 图片缓存->媒体缓存 ,支持 Gif、WebP、缩略图。甚至是 Video。
      ② 支持优先级处理
      ③ 与 Activity/Fragment 生命周期一致,支持 trimMemory
      ④ 支持 okhttp、Volley。Glide 默认通过 UrlConnection 获取数据,可以配合 okhttp 或是 Volley 使用。实际 ImageLoader、Picasso 也都支持 okhttp、Volley。
      ⑤ 内存友好,内存缓存更小图片,图片默认使用默认 RGB565 而不是 ARGB888
      缺点:
      清晰度差,但可以设置
    • Fresco:
      优点:
      ① 图片存储在安卓系统的匿名共享内存, 而不是虚拟机的堆内存中,所以不会因为图片加载而导致oom, 同时也减少垃圾回收器频繁调用回收Bitmap导致的界面卡顿,性能更高.
      ② 渐进式加载JPEG图片, 支持图片从模糊到清晰加载
      ③ 图片可以以任意的中心点显示在ImageView, 而不仅仅是图片的中心.
      ④ JPEG图片改变大小也是在native进行的, 不是在虚拟机的堆内存, 同样减少OOM
      ⑤ 很好的支持GIF图片的显示
      缺点:
      框架较大, 影响Apk体积,使用较繁琐

    1-25 网络框架为什么要用OKhttp? 它和Xutils, Volley, Retrofit区别?

    • Xutils
      这个框架非常全面,可以进行网络请求,可以进行图片加载处理,可以数据储存,还可以对view进行注解,使用这个框架非常方便,但是缺点也是非常明显的,使用这个项目,会导致项目对这个框架依赖非常的严重,一旦这个框架出现问题,那么对项目来说影响非常大的

    • OKhttp
      Android开发中是可以直接使用现成的api进行网络请求的。就是使用HttpClient,HttpUrlConnection进行操作。okhttp针对Java和Android程序,封装的一个高性能的http请求库,支持同步,异步,而且okhttp又封装了线程池,封装了数据转换,封装了参数的使用,错误处理等。API使用起来更加的方便。但是我们在项目中使用的时候仍然需要自己在做一层封装,这样才能使用的更加的顺手。

    • Volley
      Volley是Google官方出的一套小而巧的异步请求库,该框架封装的扩展性很强,支持HttpClient、HttpUrlConnection, 甚至支持OkHttp,而且Volley里面也封装了ImageLoader,所以如果你愿意你甚至不需要使用图片加载框架,不过这块功能没有一些专门的图片加载框架强大,对于简单的需求可以使用,稍复杂点的需求还是需要用到专门的图片加载框架。Volley也有缺陷,比如不支持post大数据,所以不适合上传文件。不过Volley设计的初衷本身也就是为频繁的、数据量小的网络请求而生。

    • Retrofit
      Retrofit是Square公司出品的默认基于OkHttp封装的一套RESTful网络请求框架,RESTful是目前流行的一套api设计的风格, 并不是标准。Retrofit的封装可以说是很强大,里面涉及到一堆的设计模式,可以通过注解直接配置请求,可以使用不同的http客户端,虽然默认是用http ,可以使用不同Json Converter 来序列化数据,同时提供对RxJava的支持,使用Retrofit + OkHttp + RxJava + Dagger2 可以说是目前比较潮的一套框架,但是需要有比较高的门槛。

    • Volley VS OkHttp
      Volley的优势在于封装的更好,而使用OkHttp你需要有足够的能力再进行一次封装。而OkHttp的优势在于性能更高,因为 OkHttp基于NIO和Okio ,所以性能上要比 Volley更快。IO 和 NIO这两个都是Java中的概念,如果我从硬盘读取数据,第一种方式就是程序一直等,数据读完后才能继续操作这种是最简单的也叫阻塞式IO,还有一种是你读你的,程序接着往下执行,等数据处理完你再来通知我,然后再处理回调。而第二种就是 NIO 的方式,非阻塞式, 所以NIO当然要比IO的性能要好了,而 Okio是 Square 公司基于IO和NIO基础上做的一个更简单、高效处理数据流的一个库。理论上如果Volley和OkHttp对比的话,更倾向于使用 Volley,因为Volley内部同样支持使用OkHttp,这点OkHttp的性能优势就没了, 而且 Volley 本身封装的也更易用,扩展性更好些。

    • OkHttp VS Retrofit
      毫无疑问,Retrofit 默认是基于 OkHttp 而做的封装,这点来说没有可比性,肯定首选 Retrofit。

    • Volley VS Retrofit
      这两个库都做了不错的封装,但Retrofit解耦的更彻底,尤其Retrofit2.0出来,Jake对之前1.0设计不合理的地方做了大量重构, 职责更细分,而且Retrofit默认使用OkHttp,性能上也要比Volley占优势,再有如果你的项目如果采用了RxJava ,那更该使用 Retrofit 。所以这两个库相比,Retrofit更有优势,在能掌握两个框架的前提下该优先使用 Retrofit。但是Retrofit门槛要比Volley稍高些,要理解他的原理,各种用法,想彻底搞明白还是需要花些功夫的,如果你对它一知半解,那还是建议在商业项目使用Volley吧。


    1-26 熟悉哪些设计模式?

    • 按自己的实际情况回答,当然越多越好
    • 比如我就只熟悉 单例和建造者,加以描述,最好能写出来

    2 偶尔问

    2-1 Activity在屏幕旋转时的生命周期

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

    2-2 怎样解决方法数65K的问题

    • 使用Android Studio的 gradle 可以构建MutilDex

    2-3 浅谈MVC、 MVP、 MVVM区别与联系

    • (自由发挥,待补充)

    2-4 什么是三级缓存?三级缓存的原理?

    • 网络加载,不优先加载,速度慢,浪费流量
      本地缓存,次优先加载,速度快
      内存缓存,优先加载,速度最快
      首次加载Android App时,肯定要通过网络交互来获取图片,之后我们可以将图片保存至本地SD卡和内存中,之后运行APP时,优先访问内存中的图片缓存,若内存中没有,则加载本地SD卡中图片,最后选择访问网络

    2-5 热修复的原理 (如果简历中有提到过此技术)

    • 我们知道Java虚拟机 —— JVM 是加载类的class文件的,而Android虚拟机——Dalvik/ART VM 是加载类的dex文件,
      而他们加载类的时候都需要ClassLoader,ClassLoader有一个子类BaseDexClassLoader,而BaseDexClassLoader下有一个
      数组——DexPathList,是用来存放dex文件,当BaseDexClassLoader通过调用findClass方法时,实际上就是遍历数组,
      找到相应的dex文件,找到,则直接将它return。而热修复的解决方法就是将新的dex添加到该集合中,并且是在旧的dex的前面,
      所以就会优先被取出来并且return返回。

    2-6 AsyncTask的内部实现、适用场景

    • AsyncTask内部也是Handler机制来完成的,只不过Android提供了执行框架来提供线程池来执行相应地任务,因为线程池的大小问题,所以AsyncTask只应该用来执行耗时时间较短的任务,比如HTTP请求,大规模的下载和数据库的更改不适用于AsyncTask,因为会导致线程池堵塞,没有线程来执行其他的任务,导致的情形是会发生AsyncTask根本执行不了的问题。

    2-7 谈谈Context

    • Context是一个抽象基类。在翻译为上下文,也可以理解为环境,是提供一些程序的运行环境基础信息。Context下有两个子类,ContextWrapper是上下文功能的封装类,而ContextImpl则是上下文功能的实现类。而ContextWrapper又有三个直接的子类, ContextThemeWrapper、Service和Application。其中,ContextThemeWrapper是一个带主题的封装类,而它有一个直接子类就是Activity,所以Activity和Service以及Application的Context是不一样的,只有Activity需要主题,Service不需要主题。Context一共有三种类型,分别是Application、Activity和Service。这三个类虽然分别各种承担着不同的作用,但它们都属于Context的一种,而它们具体Context的功能则是由ContextImpl类去实现的,因此在绝大多数场景下,Activity、Service和Application这三种类型的Context都是可以通用的。不过有几种场景比较特殊,比如启动Activity,还有弹出Dialog。出于安全原因的考虑,Android是不允许Activity或Dialog凭空出现的,一个Activity的启动必须要建立在另一个Activity的基础之上,也就是以此形成的返回栈。而Dialog则必须在一个Activity上面弹出(除非是System Alert类型的Dialog),因此在这种场景下,我们只能使用Activity类型的Context,否则将会出错。
    • getApplicationContext()和getApplication()方法得到的对象都是同一个application对象,只是对象的类型不一样。
    • Context数量 = Activity数量 + Service数量 + 1 (1为Application)

    持续更新中......


    参考

    https://blog.csdn.net/zl_china/article/details/77439915
    https://www.jianshu.com/p/928dbf20d927
    https://blog.csdn.net/carter_yu/article/details/52517475
    https://yiweifen.com/html/news/WaiYu/74088.html
    https://www.jianshu.com/p/62a22dc70048
    https://www.jianshu.com/p/afc54b7e90cb
    https://blog.csdn.net/tomcat0916/article/details/81902189

    免税

    相关文章

      网友评论

        本文标题:Android 中级面试题汇总(201811更)

        本文链接:https://www.haomeiwen.com/subject/apzjzftx.html