Android大厂面试题锦集附答案(BAT TMD JD 小米)

1.android事件分发机制,请详细说下整个流程

2.android view绘制机制和加载过程,请详细说下整个流程

1.ViewRootImpl会调用performTraversals(),其内部会调用performMeasure()、performLayout、performDraw()。
2.performMeasure()会调用最外层的ViewGroup的measure()→onMeasure(),ViewGroup的onMeasure()是抽象方法,但其提供了measureChildren(),这之中会遍历子View而后循环调用measureChild()这之中会用getChildMeasureSpec()+父View的MeasureSpec+子View的LayoutParam一块儿获取本View的MeasureSpec,而后调用子View的measure()到View的onMeasure()→setMeasureDimension(getDefaultSize(),getDefaultSize()),getDefaultSize()默认返回measureSpec的测量数值,因此继承View进行自定义的wrap_content须要重写。
3.performLayout()会调用最外层的ViewGroup的layout(l,t,r,b),本View在其中使用setFrame()设置本View的四个顶点位置。在onLayout(抽象方法)中肯定子View的位置,如LinearLayout会遍历子View,循环调用setChildFrame()→子View.layout()。
4.performDraw()会调用最外层ViewGroup的draw():其中会前后调用background.draw()(绘制背景)、onDraw()(绘制本身)、dispatchDraw()(绘制子View)、onDrawScrollBars()(绘制装饰)。
5.MeasureSpec由2位SpecMode(UNSPECIFIED、EXACTLY(对应精确值和match_parent)、AT_MOST(对应warp_content))和30位SpecSize组成一个int,DecorView的MeasureSpec由窗口大小和其LayoutParams决定,其余View由父View的MeasureSpec和本View的LayoutParams决定。ViewGroup中有getChildMeasureSpec()来获取子View的MeasureSpec。
6.三种方式获取measure()后的宽高:java

  • 1.Activity#onWindowFocusChange()中调用获取linux

  • 2.view.post(Runnable)将获取的代码投递到消息队列的尾部。android

  • 3.ViewTreeObservable.c++

3.android四大组件的加载过程,请详细介绍下

1.android四大组件的加载过程:这是我总结的一篇博客web

4.Activity的启动模式

1.standard:默认标准模式,每启动一个都会建立一个实例,
2.singleTop:栈顶复用,若是在栈顶就调用onNewIntent复用,从onResume()开始
3.singleTask:栈内复用,本栈内只要用该类型Activity就会将其顶部的activity出栈
4.singleInstance:单例模式,除了3中特性,系统会单独给该Activity建立一个栈,面试

5.A、B、C、D分别是四种Activity的启动模式,那么A->B->C->D->A->B->C->D分别启动,最后的activity栈是怎么样的

1.这个题目须要深刻了解activity的启动模式
2.最后的答案是:两个栈,前台栈是只有D,后台栈从底至上是A、B、C正则表达式

6.Activity缓存方法

1.配置改变致使Activity被杀死,横屏变竖屏:在onStop以前会调用onSaveInstanceState()保存数据在重建Activity以后,会在onStart()以后调用onRestoreInstanceState(),并把保存下来的Bundle传给onCreate()和它会默认重建Activity当前的视图,咱们能够在onCreate()中,回复本身的数据。
2.内存不足杀掉Activity,优先级分别是:前台可见,可见非前台,后台。算法

7.Service的生命周期,两种启动方法,有什么区别

1.context.startService() ->onCreate()- >onStart()->Service running→(若是调用context.stopService() )->onDestroy() ->Service shut down数据库

  • 1.若是Service尚未运行,则调用onCreate()而后调用onStart();设计模式

  • 2.若是Service已经运行,则只调用onStart(),因此一个Service的onStart方法可能会重复调用屡次。

  • 3.调用stopService的时候直接onDestroy,

  • 4.若是是调用者本身直接退出而没有调用stopService的话,Service会一直在后台运行。该Service的调用者再启动起来后能够经过stopService关闭Service。
    2.context.bindService()->onCreate()->onBind()->Service running→onUnbind() -> onDestroy() ->Service stop

  • 1.onBind将返回给客户端一个IBind接口实例,IBind容许客户端回调服务的方法,好比获得Service运行的状态或其余操做。

  • 2.这个时候会把调用者和Service绑定在一块儿,Context退出了,Service就会调用onUnbind->onDestroy相应退出。

  • 3.因此调用bindService的生命周期为:onCreate → onBind(只一次,不可屡次绑定) → onUnbind → onDestory。

8.怎么保证service不被杀死

1.提高service优先级
2.提高service进程优先级
3.onDestroy方法里重启service

9.静态的Broadcast 和动态的有什么区别

1.动态的比静态的安全
2.静态在app启动的时候就初始化了 动态使用代码初始化
3.静态须要配置 动态不须要
4.生存期,静态广播的生存期能够比动态广播的长不少
5.优先级动态广播的优先级比静态广播高

10.Intent能够传递哪些数据类型

1.Serializable
2.charsequence: 主要用来传递String,char等
3.parcelable
4.Bundle

11.Json有什么优劣势、解析的原理

1.JSON的速度要远远快于XML
2.JSON相对于XML来说,数据的体积小
3.JSON对数据的描述性比XML较差
4.解析的基本原理是:词法分析

12.一个语言的编译过程

1.词法分析:将一串文本按规则分割成最小的结构,关键字、标识符、运算符、界符和常量等。通常实现方法是自动机和正则表达式
2.语法分析:将一系列单词组合成语法树。通常实现方法有自顶向下和自底向上
3.语义分析:对结构上正确的源程序进行上下文有关性质的审查
4.目标代码生成
5.代码优化:优化生成的目标代码,

13.动画有哪几类,各有什么特色

1.动画的基本原理:其实就是利用插值器和估值器,来计算出各个时刻View的属性,而后经过改变View的属性来,实现View的动画效果。
2.View动画:只是影像变化,view的实际位置还在原来的地方。
3.帧动画是在xml中定义好一系列图片以后,使用AnimationDrawable来播放的动画。
4.View的属性动画:

  • 1.插值器:做用是根据时间的流逝的百分比来计算属性改变的百分比

  • 2.估值器:在1的基础上由这个东西来计算出属性到底变化了多少数值的类

14.Handler、Looper消息队列模型,各部分的做用

1.MessageQueue:读取会自动删除消息,单链表维护,在插入和删除上有优点。在其next()中会无限循环,不断判断是否有消息,有就返回这条消息并移除。
2.Looper:Looper建立的时候会建立一个MessageQueue,调用loop()方法的时候消息循环开始,loop()也是一个死循环,会不断调用messageQueue的next(),当有消息就处理,不然阻塞在messageQueue的next()中。当Looper的quit()被调用的时候会调用messageQueue的quit(),此时next()会返回null,而后loop()方法也跟着退出。
3.Handler:在主线程构造一个Handler,而后在其余线程调用sendMessage(),此时主线程的MessageQueue中会插入一条message,而后被Looper使用。
4.系统的主线程在ActivityThread的main()为入口开启主线程,其中定义了内部类Activity.H定义了一系列消息类型,包含四大组件的启动中止。
5.MessageQueue和Looper是一对一关系,Handler和Looper是多对一

15.怎样退出终止App

1.本身设置一个Activity的栈,而后一个个finish()

16.Android IPC:Binder原理

1.在Activity和Service进行通信的时候,用到了Binder。

  • 1.当属于同个进程咱们能够继承Binder而后在Activity中对Service进行操做

  • 2.当不属于同个进程,那么要用到AIDL让系统给咱们建立一个Binder,而后在Activity中对远端的Service进行操做。

2.系统给咱们生成的Binder:

  • 1.Stub类中有:接口方法的id,有该Binder的标识,有asInterface(IBinder)(让咱们在Activity中获取实现了Binder的接口,接口的实如今Service里,同进程时候返回Stub不然返回Proxy),有onTransact()这个方法是在不一样进程的时候让Proxy在Activity进行远端调用实现Activity操做Service

  • 2.Proxy类是代理,在Activity端,其中有:IBinder mRemote(这就是远端的Binder),两个接口的实现方法不过是代理最终仍是要在远端的onTransact()中进行实际操做。


  • 3.哪一端的Binder是副本,该端就能够被另外一端进行操做,由于Binder本体在定义的时候能够操做本端的东西。因此能够在Activity端传入本端的Binder,让Service端对其进行操做称为Listener,能够用RemoteCallbackList这个容器来装Listener,防止Listener由于经历过序列化而产生的问题。
    4.当Activity端向远端进行调用的时候,当前线程会挂起,当方法处理完毕才会唤醒。
    5.若是一个AIDL就用一个Service太奢侈,因此可使用Binder池的方式,创建一个AIDL其中的方法是返回IBinder,而后根据方法中传入的参数返回具体的AIDL。
    6.IPC的方式有:Bundle(在Intent启动的时候传入,不过是一次性的),文件共享(对于SharedPreference是特例,由于其在内存中会有缓存),使用Messenger(其底层用的也是AIDL,同理要操做哪端,就在哪端定义Messenger),AIDL,ContentProvider(在本进程中继承实现一个ContentProvider,在增删改查方法中调用本进程的SQLite,在其余进程中查询),Socket

17.描述一次跨进程通信

1.client、proxy、serviceManager、BinderDriver、impl、service
2.client发起一个请求service信息的Binder请求到BinderDriver中,serviceManager发现BinderDiriver中有本身的请求 而后将clinet请求的service的数据返回给client这样完成了一次Binder通信
3.clinet获取的service信息就是该service的proxy,此时调用proxy的方法,proxy将请求发送到BinderDriver中,此时service的 Binder线程池循环发现有本身的请求,而后用impl就处理这个请求最后返回,这样完成了第二次Binder通信
4.中间client可挂起,也能够不挂起,有一个关键字oneway能够解决这个

18.android重要术语解释

1.ActivityManagerServices,简称AMS,服务端对象,负责系统中全部Activity的生命周期
2.ActivityThread,App的真正入口。当开启App以后,会调用main()开始运行,开启消息循环队列,这就是传说中的UI线程或者叫主线程。与ActivityManagerServices配合,一块儿完成Activity的管理工做
3.ApplicationThread,用来实现ActivityManagerService与ActivityThread之间的交互。在ActivityManagerService须要管理相关Application中的Activity的生命周期时,经过ApplicationThread的代理对象与ActivityThread通信。
4.ApplicationThreadProxy,是ApplicationThread在服务器端的代理,负责和客户端的ApplicationThread通信。AMS就是经过该代理与ActivityThread进行通讯的。
5.Instrumentation,每个应用程序只有一个Instrumentation对象,每一个Activity内都有一个对该对象的引用。Instrumentation能够理解为应用进程的管家,ActivityThread要建立或暂停某个Activity时,都须要经过Instrumentation来进行具体的操做。
6.ActivityStack,Activity在AMS的栈管理,用来记录已经启动的Activity的前后关系,状态信息等。经过ActivityStack决定是否须要启动新的进程。
7.ActivityRecord,ActivityStack的管理对象,每一个Activity在AMS对应一个ActivityRecord,来记录Activity的状态以及其余的管理信息。其实就是服务器端的Activity对象的映像。
8.TaskRecord,AMS抽象出来的一个“任务”的概念,是记录ActivityRecord的栈,一个“Task”包含若干个ActivityRecord。AMS用TaskRecord确保Activity启动和退出的顺序。若是你清楚Activity的4种launchMode,那么对这个概念应该不陌生。

19.理解Window和WindowManager

1.Window用于显示View和接收各类事件,Window有三种类型:应用Window(每一个Activity对应一个Window)、子Window(不能单独存在,附属于特定Window)、系统window(Toast和状态栏)
2.Window分层级,应用Window在1-9九、子Window在1000-199九、系统Window在2000-2999.WindowManager提供了增删改View三个功能。
3.Window是个抽象概念:每个Window对应着一个View和ViewRootImpl,Window经过ViewRootImpl来和View创建联系,View是Window存在的实体,只能经过WindowManager来访问Window。
4.WindowManager的实现是WindowManagerImpl其再委托给WindowManagerGlobal来对Window进行操做,其中有四个List分别储存对应的View、ViewRootImpl、WindowManger.LayoutParams和正在被删除的View
5.Window的实体是存在于远端的WindowMangerService中,因此增删改Window在本端是修改上面的几个List而后经过ViewRootImpl重绘View,经过WindowSession(每一个应用一个)在远端修改Window。
6.Activity建立Window:Activity会在attach()中建立Window并设置其回调(onAttachedToWindow()、dispatchTouchEvent()),Activity的Window是由Policy类建立PhoneWindow实现的。而后经过Activity#setContentView()调用PhoneWindow的setContentView。

20.Bitmap的处理

1.当使用ImageView的时候,可能图片的像素大于ImageView,此时就能够经过BitmapFactory.Option来对图片进行压缩,inSampleSize表示缩小2^(inSampleSize-1)倍。
2.BitMap的缓存:

  • 1.使用LruCache进行内存缓存。

  • 2.使用DiskLruCache进行硬盘缓存。

  • 3.实现一个ImageLoader的流程:同步异步加载、图片压缩、内存硬盘缓存、网络拉取

    • 1.同步加载只建立一个线程而后按照顺序进行图片加载

    • 2.异步加载使用线程池,让存在的加载任务都处于不一样线程

    • 3.为了避免开启过多的异步任务,只在列表静止的时候开启图片加载

21.如何实现一个网络框架(参考Volley)

1.缓存队列,以url为key缓存内容能够参考Bitmap的处理方式,这里单独开启一个线程。
2.网络请求队列,使用线程池进行请求。
3.提供各类不一样类型的返回值的解析如String,Json,图片等等。

22.ClassLoader的基础知识

1.双亲委托:一个ClassLoader类负责加载这个类所涉及的全部类,在加载的时候会判断该类是否已经被加载过,而后会递归去他父ClassLoader中找。
2.能够动态加载Jar经过URLClassLoader
3.ClassLoader 隔离问题 JVM识别一个类是由:ClassLoader id+PackageName+ClassName。
4.加载不一样Jar包中的公共类:

  • 1.让父ClassLoader加载公共的Jar,子ClassLoader加载包含公共Jar的Jar,此时子ClassLoader在加载公共Jar的时候会先去父ClassLoader中找。(只适用Java)

  • 2.重写加载包含公共Jar的Jar的ClassLoader,在loadClass中找到已经加载过公共Jar的ClassLoader,也就是把父ClassLoader替换掉。(只适用Java)

  • 3.在生成包含公共Jar的Jar时候把公共Jar去掉。

23.插件化框架描述:dynamicLoadApk为例子

1.能够经过DexClassLoader来对apk中的dex包进行加载访问
2.如何加载资源是个很大的问题,由于宿主程序中并无apk中的资源,因此调用R资源会报错,因此这里使用了Activity中的实现ContextImpl的getAssets()和getResources()再加上反射来实现。
3.因为系统启动Activity有不少初始化动做要作,而咱们手动反射很难完成,因此能够采用接口机制,将Activity的大部分生命周期提取成接口,而后经过代理Activity去调用插件Activity的生命周期。同时若是像增长一个新生命周期方法的时候,只须要在接口中和代理中声明一下就行。
4.缺点:

  • 1.慎用this,由于在apk中使用this并不表明宿主中的activity,固然若是this只是表示本身的接口仍是能够的。除此以外可使用that代替this。

  • 2.不支持Service和静态注册的Broadcast

  • 3.不支持LaunchMode和Apk中Activity的隐式调用。

24.热修复:Andfix为例子

1.大体原理:apkpatch将两个apk作一次对比,而后找出不一样的部分。能够看到生成的apatch了文件,后缀改为zip再解压开,里面有一个dex文件。经过jadx查看一下源码,里面就是被修复的代码所在的类文件,这些更改过的类都加上了一个_CF的后缀,而且变更的方法都被加上了一个叫@MethodReplace的annotation,经过clazz和method指定了须要替换的方法。而后客户端sdk获得补丁文件后就会根据annotation来寻找须要替换的方法。最后由JNI层完成方法的替换。
2.没法添加新类和新的字段、补丁文件很容易被反编译、加固平台可能会使热补丁功能失效

25.线程同步的问题,经常使用的线程同步

1.sycn:保证了原子性、可见性、有序性
2.锁:保证了原子性、可见性、有序性

  • 1.自旋锁:可使线程在没有取得锁的时候,不被挂起,而转去执行一个空循环。

    • 1.优势:线程被挂起的概率减小,线程执行的连贯性增强。用于对于锁竞争不是很激烈,锁占用时间很短的并发线程。

    • 2.缺点:过多浪费CPU时间,有一个线程连续两次试图得到自旋锁引发死锁

  • 2.阻塞锁:没获得锁的线程等待或者挂起,Sycn、Lock

  • 3.可重入锁:一个线程可屡次获取该锁,Sycn、Lock

  • 4.悲观锁:每次去拿数据的时候都认为别人会修改,因此会阻塞所有其余线程 Sycn、Lock

  • 5.乐观锁:每次去拿数据的时候都认为别人不会修改,因此不会上锁,可是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可使用版本号等机制。cas

  • 6.显示锁和内置锁:显示锁用Lock来定义、内置锁用synchronized。

  • 7.读-写锁:为了提升性能,Java提供了读
    3.volatile

  • 1.只能保证可见性,不能保证原子性

  • 2.自增操做有三步,此时多线程写会出现问题
    4.cas

  • 1.操做:内存值V、旧的预期值A、要修改的值B,当且仅当预期值A和内存值V相同时,将内存值修改成B并返回true,不然什么都不作并返回false。

  • 2.解释:本地副本为A,共享内存为V,线程A要把V修改为B。某个时刻线程A要把V修改为B,若是A和V不一样那么就表示有其余线程在修改V,此时就表示修改失败,不然表示没有其余线程修改,那么把V改为B。

  • 3.局限:若是V被修改为V1而后又被改为V,此时cas识别不出变化,仍是认为没有其余线程在修改V,此时就会有问题

  • 4.局限解决:将V带上版本。
    5.线程不安全究竟是怎么回事:

  • 1.一个线程写,多个线程读的时候,会形成写了一半就去读

  • 2.多线程写,会形成脏数据

26.Asynctask和线程池,GC相关(怎么判断哪些内存该GC,GC算法)

1.Asynctask:异步任务类,单线程线程池+Handler
2.线程池:

  • 1.ThreadPoolExecutor:经过Executors能够构造单线程池、固定数目线程池、不固定数目线程池。

  • 2.ScheduledThreadPoolExecutor:能够延时调用线程或者延时重复调度线程。
    3.GC相关:重要

  • 1.搜索算法:

    • 1.引用计数

    • 2.图搜索,可达性分析

  • 2.回收算法:

    • 1.标记清除复制:用于青年代

    • 2.标记整理:用于老年代

  • 3.堆分区:

    • 1.青年区eden 80%、survivor1 10%、survivor2 10%

    • 2.老年区

  • 4.虚拟机栈分区:

    • 1.局部变量表

    • 2.操做数栈

    • 3.动态连接

    • 4.方法返回地址

  • 5.GC Roots:

    • 1.虚拟机栈(栈桢中的本地变量表)中的引用的对象

    • 2.方法区中的类静态属性引用的对象

    • 3.方法区中的常量引用的对象

    • 4.本地方法栈中JNI的引用的对象

27.网络

1.ARP协议:在IP以太网中,当一个上层协议要发包时,有了该节点的IP地址,ARP就能提供该节点的MAC地址。
2.HTTP HTTPS的区别:

  • 1.HTTPS使用TLS(SSL)进行加密

  • 2.HTTPS缺省工做在TCP协议443端口

  • 3.它的工做流程通常如如下方式:

    • 1.完成TCP三次同步握手

    • 2.客户端验证服务器数字证书,经过,进入步骤3

    • 3.DH算法协商对称加密算法的密钥、hash算法的密钥

    • 4.SSL安全加密隧道协商完成

    • 5.网页以加密的方式传输,用协商的对称加密算法和密钥加密,保证数据机密性;用协商的hash算法进行数据完整性保护,保证数据不被篡改

  • 3.http请求包结构,http返回码的分类,400和500的区别

    • 1.请求:请求行、头部、数据

    • 2.返回:状态行、头部、数据

    • 1.包结构:

    • 2.http返回码分类:1到5分别是,消息、成功、重定向、客户端错误、服务端错误

  • 4.Tcp

    • 1.fin-c = x , 表示如今须要关闭c到s了。ack-c = y,表示上一条s的消息已经接收完毕

    • 2.ack-s = x + 1,表示须要关闭的fin-c消息已经接收到了,赞成关闭

    • 3.fin-s = y + 1,表示s已经准备好关闭了,就等c的最后一条命令

    • 4.ack-c = y + 1,表示c已经关闭,让s也关闭

    • 1.三次握手:防止了服务器端的一直等待而浪费资源,例如只是两次握手,若是s确认以后c就掉线了,那么s就会浪费资源

    • 1.syn-c = x,表示这消息是x序号

    • 2.ack-s = x + 1,表示syn-c这个消息接收成功。syn-s = y,表示这消息是y序号。

    • 3.ack-c = y + 1,表示syn-s这条消息接收成功

    • 1.可靠链接,三次握手,四次挥手

    • 2.四次挥手:TCP是全双工模式

    • 3.滑动窗口,中止等待、后退N、选择重传

    • 4.拥塞控制,慢启动、拥塞避免、加速递减、快重传快恢复

28.数据库性能优化:索引和事务,须要找本专门的书大概了解一下

29.APK打包流程和其内容

1.流程

  • 1.aapt生成R文件

    • 2.aidl生成java文件

    • 3.将所有java文件编译成class文件

    • 4.将所有class文件和第三方包合并成dex文件

    • 5.将资源、so文件、dex文件整合成apk

    • 6.apk签名

    • 7.apk字节对齐

  • 2.内容:so、dex、asset、资源文件

30.网络劫持的类型原理:能够百度一下了解一下具体概念

1.DNS劫持、欺骗、污染
2.http劫持:重定向、注入js,http注入、报文扩展

31.java类加载过程:

1.加载时机:建立实例、访问静态变量或方法、反射、加载子类以前
2.验证:验证文件格式、元数据、字节码、符号引用的正确性
3.加载:根据全类名获取文件字节流、将字节流转化为静态储存结构放入方法区、生成class对象
4.准备:在堆上为静态变量划份内存
5.解析:将常量池中的符号引用转换为直接引用
6.初始化:初始化静态变量
7.书籍推荐:深刻理解java虚拟机,博客推荐:Java/Android阿里面试JVM部分理解

32.retrofit的了解

1.动态代理建立一个接口的代理类
2.经过反射解析每一个接口的注解、入参构造http请求
3.获取到返回的http请求,使用Adapter解析成须要的返回值。

33.bundle的数据结构,如何存储

1.键值对储存
2.传递的数据能够是boolean、byte、int、long、float、double、string等基本类型或它们对应的数组,也能够是对象或对象数组。
3.当Bundle传递的是对象或对象数组时,必须实现Serializable 或Parcelable接口

34.listview内点击buttom并移动的事件流完整拦截过程:

1.点下按钮的时候:

  • 1.产生了一个down事件,activity→phoneWindow→ViewGroup→ListView→botton,中间若是有重写了拦截方法,则事件被该view拦截可能消耗。

  • 2.没拦截,事件到达了button,这个过程当中创建了一条事件传递的view链表

  • 3.到button的dispatch方法→onTouch→view是否可用→Touch代理
    2.移动点击按钮的时候:

  • 1.产生move事件,listView中会对move事件作拦截

  • 2.此时listView会将该滑动事件消费掉

  • 3.后续的滑动事件都会被listView消费掉
    3.手指抬起来时候:前面创建了一个view链表,listView的父view在获取事件的时候,会直接取链表中的listView让其进行事件消耗。

35.service的意义:不须要界面,在后台执行的程序

36.android的IPC通讯方式,线程(进程间)通讯机制有哪些

1.ipc通讯方式:binder、contentprovider、socket
2.操做系统进程通信方式:共享内存、socket、管道

37.操做系统进程和线程的区别

1.简而言之,一个程序至少有一个进程,一个进程至少有一个线程.
2.线程的划分尺度小于进程,使得多线程程序的并发性高。
3.另外,进程在执行过程当中拥有独立的内存单元,而多个线程共享内存,从而极大地提升了程序的运行效率。
4.多线程的意义在于一个应用程序中,有多个执行部分能够同时执行。有将多个线程看作多个独立的应用,来实现进程的调度和管理以及资源分配

38.HashMap的实现过程:Capacity就是buckets的数目,Load factor就是buckets填满程度的最大比例。若是对迭代性能要求很高的话不要把capacity设置过大,也不要把load factor设置太小。

1.简单来讲HashMap就是一个会自动扩容的数组链表
2.put过程

  • 1.对key的hashCode()作hash,而后再计算index;

  • 2.若是没碰撞直接放到bucket里;

  • 3.若是碰撞了,以链表的形式存在buckets后;

  • 4.若是碰撞致使链表过长(大于等于TREEIFY_THRESHOLD),就把链表转换成红黑树;

  • 5.若是节点已经存在就替换old value(保证key的惟一性)

  • 6.若是bucket满了(超过load factor*current capacity),就要resize。
    3.resize:当put时,若是发现目前的bucket占用程度已经超过了Load Factor所但愿的比例,那么就会发生resize。在resize的过程,简单的说就是把bucket扩充为2倍,以后从新计算index,把节点再放到新的bucket中
    4.get过程

  • 1.根据key的hash算出数组下表

  • 2.使用equals遍历链表进行比较

39.mvc、mvp、mvvm:

1.mvc:数据、View、Activity,View将操做反馈给Activity,Activitiy去获取数据,数据经过观察者模式刷新给View。循环依赖

  • 1.Activity重,很难单元测试

  • 2.View和Model耦合严重
    2.mvp:数据、View、Presenter,View将操做给Presenter,Presenter去获取数据,数据获取好了返回给Presenter,Presenter去刷新View。PV,PM双向依赖

  • 1.接口爆炸

  • 2.Presenter很重
    3.mvvm:数据、View、ViewModel,View将操做给ViewModel,ViewModel去获取数据,数据和界面绑定了,数据更新界面更新。

  • 1.viewModel的业务逻辑能够单独拿来测试

  • 2.一个view 对应一个 viewModel 业务逻辑能够分离,不会出现全能类

  • 3.数据和界面绑定了,不用写垃圾代码,可是复用起来不舒服

40.java的线程如何实现

1.Thread继承
2.Runnale
3.Future
4.线程池

41.ArrayList 如何删除重复的元素或者指定的元素;

1.删除重复:Set
2.删除指定:迭代器

42.如何设计在 UDP 上层保证 UDP 的可靠性传输;

1.简单来说,要使用UDP来构建可靠的面向链接的数据传输,就要实现相似于TCP协议的超时重传,有序接受,应答确认,滑动窗口流量控制等机制,等于说要在传输层的上一层(或者直接在应用层)实现TCP协议的可靠数据传输机制。
2.好比使用UDP数据包+序列号,UDP数据包+时间戳等方法,在服务器端进行应答确认机制,这样就会保证不可靠的UDP协议进行可靠的数据传输。
3.基于udp的可靠传输协议有:RUDP、RTP、UDT

43.Java 中内部类为何能够访问外部类

1.由于内部类建立的时候,须要外部类的对象,在内部类对象建立的时候会把外部类的引用传递进去

44.设计移动端的联系人存储与查询的功能,要求快速搜索联系人,能够用到哪些数据结构?数据库索引,平衡二叉树(B树、红黑树)

45.红黑树特色

1.root节点和叶子节点是黑色
2.红色节点后必须为黑色节点
3.从root到叶子每条路径的黑节点数量相同

46.linux异步和同步i/o:

1.同步:对于client,client一直等待,可是client不挂起:主线程调用
2.异步:对于client,client发起请求,service好了再回调client:其余线程调用,调用完成以后进行回调
3.阻塞:对于service,在准备io的时候会将service端挂起,直至准备完成而后唤醒service:bio
3.非阻塞:对于service,在准备io的时候不会将service端挂起,而是service一直去轮询判断io是否准备完成,准备完成了就进行操做:nio、linux的select、poll、epoll
4.多路复用io:非阻塞io的一种优化,java nio,用一个线程去轮询多个 io端口是否可用,若是一个可用就通知对应的io请求,这使用一个线程轮询能够大大加强性能。

  • 1.我能够采用 多线程+ 阻塞IO 达到相似的效果,可是因为在多线程 + 阻塞IO 中,每一个socket对应一个线程,这样会形成很大的资源占用。

  • 2.而在多路复用IO中,轮询每一个socket状态是内核在进行的,这个效率要比用户线程要高的多。
    5.异步io:aio,用户线程彻底不感知io的进行,全部操做都交给内核,io完成以后内核通知用户线程。

  • 1.这种io才是异步的,二、三、4都是同步io,由于内核进行数据拷贝的过程都会让用户线程阻塞。

  • 2.异步IO是须要操做系统的底层支持,也就是内核支持,Java 7中,提供了Asynchronous IO

47.ConcurrentHashMap内部实现,HashTable的实现被废弃的缘由:

1.HashTable容器在竞争激烈的并发环境下表现出效率低下的缘由,是由于全部访问HashTable的线程都必须竞争同一把锁,那假如容器里有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不一样数据段的数据时,线程间就不会存在锁竞争,从而能够有效的提升并发访问效率,这就是ConcurrentHashMap所使用的锁分段技术,首先将数据分红一段一段的存储,而后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其余段的数据也能被其余线程访问。
2.ConcurrentHashMap是由Segment数组结构和HashEntry数组结构组成。Segment是一种可重入锁ReentrantLock,在ConcurrentHashMap里扮演锁的角色,HashEntry则用于存储键值对数据。一个ConcurrentHashMap里包含一个Segment数组,Segment的结构和HashMap相似,是一种数组和链表结构, 一个Segment里包含一个HashEntry数组,每一个HashEntry是一个链表结构的元素,每一个Segment守护者一个HashEntry数组里的元素,当对HashEntry数组的数据进行修改时,必须首先得到它对应的Segment锁。

48.HandlerThread是什么

1.MessageQueue + Looper + Handler

49.IntentService是什么

1.含有HandlerThread的Service,能够屡次startService()来屡次在子线程中进行 onHandlerIntent()的调用。

50.class和dex

1.dvm执行的是dex格式文件,jvm执行的是class文件,android程序编译完以后生产class文件。而后dex工具会把class文件处理成dex文件,而后把资源文件和.dex文件等打包成apk文件。
2.dvm是基于寄存器的虚拟机,而jvm执行是基于虚拟栈的虚拟机。寄存器存取速度比栈快的多,dvm能够根据硬件实现最大的优化,比较适合移动设备。
3.class文件存在不少的冗余信息,dex工具会去除冗余信息,并把全部的class文件整合到dex文件中。减小了I/O操做,提升了类的查找速度

51.内存泄漏

1.其余线程持有一个Listener,Listener操做activity。那么在线程么有完毕的时候,activity关闭了,本来是要被回收的可是,不能被回收。
2.例如Handler致使的内存泄漏,Handler就至关于Listener。
3.在activity关闭的时候注意中止线程,或者将Listener的注册取消
3.使用弱引用,这样即便Listener持有了activity,在GC的时候仍是会被回收
4.工具:LeakCanary

52.过分绘制、卡顿优化:

1.过分绘制:

  • 1.移除Window默认的Background:getWidow.setBackgroundDrawable(null);

  • 2.移除XML布局文件中非必需的Background

  • 3.减小布局嵌套(扁平化的一个体现,减小View数的深度,也就减小了View树的遍历时间,渲染的时候,先后期的工做,老是按View树结点来)

  • 4.在引入布局文件里面,最外层能够用merge替代LinearLayout,RelativeLayout,这样把子UI元素直接衔接在include位置

  • 5.工具:HierarchyViewer 查看视图层级
    2.卡顿优化:16ms数据更新

53.apk瘦身:

1.classes.dex:经过代码混淆,删掉没必要要的jar包和代码实现该文件的优化
2.资源文件:经过Lint工具扫描代码中没有使用到的静态资源
3.图片资源:使用tinypng和webP,下面详细介绍图片资源优化的方案,矢量图
4.SO文件将不用的去掉,目前主流app通常只放一个arm的so包

54.ANR的造成,各个组件上出现ARN的时间限制是多少

1.只要是主线程耗时的操做就会ARN 如io
2.broadcast超时时间为10秒 按键无响应的超时时间为5秒 前台service无响应的超时时间为20秒,后台service为200秒

55.Serializable和Parcelable 的区别

1.P 消耗内存小
2.网络传输用S 程序内使用P
3.S将数据持久化方便
4.S使用了反射 容易触发垃圾回收 比较慢

56.Sharedpreferences源码简述

1.储存于硬盘上的xml键值对,数据多了会有性能问题
2.ContextImpl记录着SharedPreferences的重要数据,文件路径和实例的键值对
3.在xml文件所有内加载到内存中以前,读取操做是阻塞的,在xml文件所有内加载到内存中以后,是直接读取内存中的数据
4.apply由于是异步的没有返回值, commit是同步的有返回值能知道修改是否提交成功
5.多并发的提交commit时,需等待正在处理的commit数据更新到磁盘文件后才会继续往下执行,从而下降效率; 而apply只是原子更新到内存,后调用apply函数会直接覆盖前面内存数据,从必定程度上提升不少效率。 3.edit()每次都是建立新的EditorImpl对象.
6.博客推荐:全面剖析SharedPreferences

57.操做系统如何管理内存的:

1.使用寄存器进行将进程地址和物理内存进行映射
2.虚拟内存进行内存映射到硬盘上增大内存
3.虚拟内存是进行内存分页管理
4.页表实现分页,就是 页+地址偏移。
5.若是程序的内存在硬盘上,那么就须要用页置换算法来将其调入内存中:先进先出、最近未使用最少等等
6.博客推荐:现代操做系统部分章节笔记

58.浏览器输入地址到返回结果发生了什么

1.DNS解析
2.TCP链接
3.发送HTTP请求
4.服务器处理请求并返回HTTP报文
5.浏览器解析渲染页面
6.链接结束

59.java泛型类型擦除发生在何时,通配符有什么须要注意的。

1.发生在编译的时候
2.PECS,extends善于提供精确的对象 A是B的子集,Super善于插入精确的对象 A是B的超集
3.博客推荐:Effective Java笔记(不含反序列化、并发、注解和枚举)android阿里面试java基础锦集

60.activity的生命周期

1.a启动b,后退键再到a的生命周期流程:a.create→a.start→a.resume→a.pause→b.create→b.start→b.resume→b界面绘制→a.stop→b.pause→b.stop→b.destroy→a.restart→a.start→a.resume
2.意外销毁会调用saveInstance,从新恢复的时候回调用restoreInstance。储存数据的时候使用了委托机制,从activity→window→viewGroup→view 会递归调用save来保持本view的数据,restore则是递归恢复本view数据。咱们能够在里面作一些本身须要的数据操做。

61.面试常考的算法

1.快排、堆排序为首的各类排序算法
2.链表的各类操做:判断成环、判断相交、合并链表、倒数K个节点、寻找成环节点
3.二叉树、红黑树、B树定义以及时间复杂度计算方式
4.动态规划、贪心算法、简单的图论
5.推荐书籍:算法导论,将图论以前的例子写一遍

62.Launcher进程启动另一个进程的过程:启动一个app

63.开源框架源码

1.Fresco

  • 1.mvc框架:

    • 1.Controller控制数据显示在Hierarchy中的Drawable的显隐

    • 2.ImagePipeline在Controller中负责进行数据获取,返回的数据是CloseableImage

    • 3.Drawee把除了初始化以外的操做所有交给Holder去作,Holder持有Controller和Hierarchy

  • 2.Drawable层次以及绘制:

    • 1.若是要绘制一次Drawable就调用invalidateSelf()来触发onDraw()

    • 2.Drawable分为:容器类(保存一些Drawable)、自我绘制类(进度条)、图形变换类(scale、rotate、矩阵变换)、动画类(内部不断刷新,进行webp和gif的帧绘制)

    • 3.ImagePipeline返回的CloseableImage是由一个个DrawableFactory解析成Drawable的

    • 4.webp和gif动画是由jni代码解析的,而后其余静态图片是根据不一样的android平台使用BitmapFactory来解析的

  • 3.职责链模式:producer不作操做标n,表示只是提供一个consumer。获取图片—》解码图片缓存Producer—》后台线程Producer—》client图片处理producer(n)—》解码producer(n)—》旋转或剪裁producer(n)—》编码图片内存缓存producer—》读硬盘缓存producer—》写硬盘缓存producer(n)—》网络producer提供CloseableImage《—解码图片缓存consumer《—client图片处理consumer《—解码consumer《—旋转或剪裁consumer《—编码图片内存缓存consumer《—写硬盘缓存consumer《—图片数据

  • 4.内存缓存:

    • 1.一个CountingLruMap保存已经没有被引用的缓存条目,一个CountingLruMap保存全部的条目包括没有引用的条目。每当缓存策略改变和必定时间缓存配置的更新的时候,就会将 待销毁条目Map中的条目一个个移除,直到缓存大小符合配置。

    • 2.这里的引用计数是用Fresco组件实现的引用计数器。

    • 3.缓存有一个代理类,用来追踪缓存的存取。

    • 4.CountingLruMap是使用LinkedHashMap来储存数据的。

  • 5.硬盘缓存:

    • 1.DefaultDiskStorage使用Lru策略。

    • 2.为了避免让全部的文件集中在一个文件中,建立不少命名不一样的文件夹,而后使用hash算法把缓存文件分散

    • 3.DiskStorageCache封装了DefaultDiskStorage,不只进行缓存存取追踪,而且其在内存里面维持着一个

      的键值对,由于文件修改频繁,全部只是定时刷新,所以若是在内存中找不到,还要去硬盘中找一次。
    • 4.删除硬盘的缓存只出如今硬盘数据大小超限的时候,此时同时也会删除缓存中的key,因此不会出现内存中有key,可是硬盘上没有的状况。

    • 5.在插入硬盘数据的时候,采用的是插入器的形式。返回一个Inserter,在Inserter.writeData()中传入一个CallBack(里面封装了客户端插入数据的逻辑和文件引用),让内部实现调用CallBack的逻辑来插入文件数据,前面写的文件后缀是.temp,只有调用commit()以后才会修改后缀,让文件对客户端可见。

    • 6.使用了java提供的FileTreeVisitor来遍历文件

  • 6.对象池:

    • 1.使用数组来存储一个桶,桶内部是一个Queue。数组下标是数据申请内存的byte大小,桶内部的Queue存的是内存块的。因此数组使用的是稀疏数组

    • 2.申请内存的方式有两种 1.java堆上开辟的内存 2.ashme 的本地内存中开辟的内存

  • 7.设计模式:Builder、职责链、观察者、代理、组合、享元、适配器、装饰者、策略、生产者消费者、提供者

  • 8.自定义计数引用:相似c++智能指针

    • 1.使用一个静态IdentityHashMap <储存须要被计数引用的对象,其被引用的次数>

    • 2.用SharedReference分装须要被计数引用的对象,提供一个销毁资源的销毁器,提供一个静态工厂方法来复制本身,复制一个引用计数加一。提供一个方法销毁本身,表示本身须要变成无人引用的对象了,此时引用计数减一。

    • 3.引用计数归零,销毁器将销毁资源,如bitmap的recycle或者是jni内存调用jni方法归还内存。

  • 9.博客推荐:Android Fresco源码文档翻译从零开始撸一个Fresco之硬盘缓存从零开始撸一个Fresco之gif和Webp动画从零开始撸一个Fresco以内存缓存从零开始撸一个Fresco之总结


2.oKhttp:

  • 1.同步和异步:

    • 1.异步使用了Dispatcher来将存储在 Deque 中的请求分派给线程池中各个线程执行。

    • 2.当任务执行完成后,不管是否有异常,finally代码段总会被执行,也就是会调用Dispatcher的finished函数,它将正在运行的任务Call从队列runningAsyncCalls中移除后,主动的把缓存队列向前走了一步。

  • 2.链接池:

    • 1.一个Connection封装了一个socket,ConnectionPool中储存s着全部的Connection,StreamAllocation是引用计数的一个单位

    • 2.当一个请求获取一个Connection的时候要传入一个StreamAllocation,Connection中存着一个弱引用的StreamAllocation列表,每当上层应用引用一次Connection,StreamAllocation就会加一个。反之若是上层应用不使用了,就会删除一个。

    • 3.ConnectionPool中会有一个后台任务定时清理StreamAllocation列表为空的Connection。5分钟时间,维持5个socket

  • 3.选择路线与创建链接

    • 1.链接池中已经存在链接,就从中取出(get)RealConnection,若是没有命中就进入下一步

    • 2.根据选择的路线(Route),调用Platform.get().connectSocket选择当前平台Runtime下最好的socket库进行握手

    • 3.将创建成功的RealConnection放入(put)链接池缓存

    • 4.若是存在TLS,就根据SSL版本与证书进行安全握手

    • 5.构造HttpStream并维护刚刚的socket链接,管道创建完成

    • 1.无代理,那么在本地使用DNS查找到ip,注意结果是数组,即一个域名有多个IP,这就是自动重连的来源

    • 2.有代理HTTP:设置socket的ip为代理地址的ip,设置socket的端口为代理地址的端口

    • 3.代理好处:HTTP代理会帮你在远程服务器进行DNS查询,能够减小DNS劫持。

    • 1.选择路线有两种方式:

    • 2.创建链接

  • 4.职责链模式:缓存、重试、创建链接等功能存在于拦截器中网络请求相关,主要是网络请求优化。网络请求的时候遇到的问题

  • 5.博客推荐:Android数据层架构的实现 上篇Android数据层架构的实现 下篇


3.okio

  • 1.简介;

    • 1.sink:本身—》别人

    • 2.source:别人—》本身

    • 3.BufferSink:有缓存区域的sink

    • 4.BufferSource:有缓存区域的source

    • 5.Buffer:实现了三、4的缓存区域,内部有Segment的双向链表,在在转移数据的时候,只须要将指针转移指向就行

  • 2.比java io的好处:

    • 1.减小内存申请和数据拷贝

    • 2.类少,功能齐全,开发效率高

  • 3.内部实现:

    • 1.Buffer的Segment双向链表,减小数据拷贝

    • 2.Segment的内部byte数组的共享,减小数据拷贝

    • 3.SegmentPool的共享和回收Segment

    • 4.sink和source中被实际操做的实际上是Buffer,Buffer能够充当sink和source

    • 5.最终okio只是对java io的封装,全部操做都是基于java io 的。

转载自安卓巴士开发者门户
相关文章
相关标签/搜索