面试题大纲

80 阅读10分钟

数据结构

二叉树的前中后序遍历

算法

网络

三次握手四次挥手

get和post的区别

http和https的区别

设计模式

六大原则

常用的几种设计模式

单例设计模式

java基础

八种数据类型

String、StringBuffer、StringBuilder

=和equals

泛型擦除

extends和super的区别

四种引用

hashmap

hashMap存数据的过程

hashMap解决冲突

hashMap和hashTable的区别

hashMap和LinkedHashMap的区别

如何保证线程安全

集合

ArrayList和LinkedList

ArrayList扩容

java多线程

线程和进程的区别

线程状态

线程状态转换及控制

sleep和wait的区别

synchronized

synchronized的原理

synchronized与Lock的区别

死锁产生的条件

CAS乐观锁

原子性(synchronized + Lock)

可见性(synchronized + volatile + lock)

有序性(volatile)

volatile的两大特性(主存+禁止指令重排序)

synchronized和volatile的区别

线程池

创建线程池的7个参数

线程池的工作流程

五种线程池

1、newSingleThreadExecutor() : 1个核心线程 + 0个非核心线程 + 无界的队列

2、newFixedThreadPool():固定的核心线程 + 0个非核心线程 + 无界的队列

3、newCachedThreadPool(): 0个核心线程 + 无限的非核心线程 + 直接提交的队列

4、newScheduledThreadPool(): 线程池大小为1 + 等待队列

5、newSingleThreadScheduledExecutor(): 固定的核心线程 + 无限的非核心线程 + 等待队列

阻塞队列类型(无界的 + 直接提交的 + 等待的)

AsyncTask

AsyncTask是串行的还是并行的

AsyncTask的原理

AsyncTask的缺陷

HandlerThread

HandlerThread的原理

IntentService

IntentService的原理

IntentService的使用场景

java虚拟机

java虚拟机和Davik虚拟机的区别

内存区域

java内存区域

回收机制

哪些对象可以被回收

可以作为GC Roots的对象包括哪些

  1. 虚拟机栈中 引用的对象
  2. 本地方法栈中 引用的对象
  3. 方法区中类静态属性 引用的对象
  4. 方法区中常量 引用的对象

采用什么样的方式回收

何时回收这些对象

类加载

类加载器分类

类加载过程(加载、验证、准备、解析、初始化、使用、卸载)

双亲委派模型

为什么要双亲委派

handler

handler原理

子线程能不能new一个handler?为什么主线程可以?

一个线程会有几个Looper,几个handler,几个MessageQueen对象?

创建Message的几种方式及区别

MessageQueue是什么数据结构?

阻塞唤醒机制

当MessageQueue中没有即时执行的任务时,会阻塞在MessageQueue.next()方法中的nativePollOnce()方法中,此时线程会释放CPU进入休眠状态,就将Looper.loop()阻塞,直到下个任务的执行时间到达或者出现某些特殊的情况再将其唤醒,从而避免资源的浪费。

epoll机制: 在native层会有一个读取端和一个写入端,当有消息发送过来的时候会去唤醒读取端,然后进行消息发送与处理,没消息的时候是处于休眠状态,所以不会阻塞。

ThreadLocal原理

每一个Thread线程都会拥有自己的一个成员变量ThreadLocalMap,该变量默认为空(实际是ThreadLocal的静态内部类,只是Thread持有引用)。

当往ThreadLocal存数据时,调用的是ThreadLocal的set方法,该方法先拿到当前线程的ThreadLocalMap实例,然后以当前threadLocal实例为key把数据存进该map中。

当取数据时,一样拿到当前线程的ThreadLocalMap实例,并以当前threadLocal实例为key从里面拿出数据。

looper是如何区分多个handler的?

为什么主线程不会因为Looper.loop()里的死循环卡死?

App进程中是需要死循环的,如果循环结束的话,App进程就结束了。

首先,Looper.loop()的阻塞和UI线程上执行耗时操作导致卡死是完全的两回事。

Looper上的阻塞,前提是没有输入事件,MessageQueue 为空(有可能有延时的消息),Looper空闲状态,线程进入阻塞,释放CPU执行权,等待唤醒。

UI耗时导致卡死,前提是要有输入事件,MessageQueue 不为空,Looper正常轮询,线程并没有阻塞,但是该事件执行时间过长,然后就ANR异常了。

Looper.quit/quitSafely的区别?

handler 有哪些发送消息的方法

Handler.postDelayed后消息队列有什么变化,假设先postDelayed 10s, 再postDelayed 1s,怎么处理这2条消息?

Handler.post(Runnable)和Handler.sendMessage方法有什么区别?

Handler如何与Looper关联的?

Handler如何实现线程的切换?

当在A线程中创建Handler的时候,同时创建Looper和MessageQueue,Looper在A线程中调用loop()进入一个 无限的for循环,从MessageQueue中取消息;

当B线程调用Handler发送一个message的时候,会通过msg.target.dispatchMessage(msg);将message插入到Handler对应的MessageQueue中;

Looper发现有message插入到MessageQueue中,便取出message执行相应的逻辑,因为Looper.loop()是在A线程中启动的,所以则回到了A线程,达到了从B线程切换到A线程的目的。

IdleHandler是什么

IdleHanlder的使用场景

同步屏障机制

handler内存泄漏

handler内存泄漏引用关系

事件分发

事件是先到DecorView还是先到Window?

为什么DecorView就走了两次?

onTouch 和onTouchEvent 的区别?

点击事件被拦截,但是想传到下面的View,如何操作?

同时对父 View 和子 View 设置点击方法,优先响应哪个?

ACTION_CANCEL什么时候触发,触摸button然后滑动到外部抬起会触发点击事件吗,再滑动回去抬起会么?

在ViewGroup.dispatchTouchEvent中消费ACTION_DOWN事件,ACTION_UP事件是怎么传递?

在 ViewGroup 中的 onTouchEvent 中消费 ACTION_DOWN 事件, ACTION_UP事件是怎么传递?

Activity ViewGroup和View都不消费ACTION_DOWN,那么ACTION_UP 事件是怎么传递的?

View的绘制

Activity界面的显示流程

ActivityThread.handleLaunchActivity

->ActivityThread.performLaunchActivity

->Activity.attach

->完成DecorView的创建

->ActivityThread.handleResumeActivity

->Activity.onResume

->ViewRootImpl.performTraversals。

performTraversals方法主要执行了3个方法,分别是performMeasure、performLayout、performDraw,在其方法的内部又会分别调用View的measure(测量)、layout(布局)、draw(绘制)方法。

Measure

子View创建MeasureSpec的规则是什么?

image.png

单一View的measure过程(具体方法)

measure():基本测量逻辑的判断 + 调用下一个方法

onMeasure():调用后面两个方法

getDefaultSize():根据View宽/高的测量规格计算View的宽/高值

setMeasureDimension(): 存储测量后的子View宽/高

ViewGroup的measure过程(具体方法)

measure()--->onMeasure()--->measureChildren()--->measureChild()--->getChildMeasureSpec()--->setMeasuredDimension()

为什么要重写onMeasure?

问: 自定义View wrap_content不起作用,而且是起到与match_parent(填充父容器)相同作用,为什么?

1.getDefaultSize(): 当View的测量模式是AT_MOST(wrap_content)或EXACTLY(match_parent)时,大小都会被设置成MeasureSpec的specSize

2.getChildMeasureSpec():子View的MeasureSpec值是根据子View的布局参数(LayoutParams)和父容器的MeasureSpec值计算得来,子View MeasureSpec在属性被设置为wrap_content或match_parent时,specSize被设置成 parenSize = 父容器当前剩余空间大小

解决: 重写onMeasure()设置一个默认值。

layout

单一View的layout过程(具体方法)

仅计算本身View的位置: Layout()、onLayout()、setFrame()

ViewGroup的layout过程(具体方法)

1.计算自身的位置layout()

2.遍历子View、计算子View的位置 & 设置( (复写)ViewGroup.onLayout()、子View.layout()、子View.onLayout() )

  1. 如此不断循环,最终确定所有子View在父容器的位置,即layout过程完毕

单一View的draw过程(具体方法)

  1. 开始绘制
  2. draw: 绘制View自身
  3. drawBackgroud(): 绘制View自身的背景
  4. onDraw(): 绘制View自身的内容
  5. dispatchDraw():绘制子View(空实现,因为没有子View)
  6. onDrawScrollBars():绘制装饰
  7. 结束绘制

ViewGroup的draw过程(具体方法)

dispatchDraw() 调用draw()、drawBackgroud()、onDraw()、dispatchDraw()、onDrawScrollBars()

View和surfaceView的区别

getWidth()方法和getMeasureWidth()区别

requestLayout()、invalidate() 和 postInvalidate() 方法的区别?

IPC机制

Serializable和Parchlable区别

开启多进程会出现的问题

几种进程间通信方式

管道、消息队列、共享内存、套接字、信号量、信号

为何新增binder来作为主要的IPC方式

binder工作原理

  1. Binder 驱动在内核空间创建一个数据接收缓存区。

  2. 在内核空间开辟一块内核缓存区,建立内核缓存区和数据接收缓存区之间的映射关系,以及数据接收缓存区和接收进程用户空间地址的映射关系。

  3. 发送方进程通过系统调用 copyfromuser() 将数据 copy 到内核空间的内核缓存区,由于内核缓存区和接收进程的用户空间存在内存映射,因此也就相当于把数据发送到了接收进程的用户空间,这样便完成了一次进程间的通信

AIDL

性能优化

启动优化

启动分类

几种启动时间统计方法

一些启动优化方案

内存泄漏

什么是内存泄漏

一些内存泄漏场景

内存检测分析工具

内存溢出

什么是内存溢出

图片的内存优化

内存抖动

什么是内存抖动

如何避免内存抖动

ANR

什么是ANR

ANR有几种类型

造成ANR的原因及解决办法

ANR如何定位

进程保活

进程优先级

进程回收策略

如何提高进程优先级

进程被杀死后拉活方案

布局优化

布局优化方法

包体积优化

APK体积优化方法

网络优化

网络优化方法

电量优化

电量优化手段

LeakCanary

LeakCanary原理

Lecanary的Idle机制

EventBus

EventBus的实现原理

根据事件类型找到所有订阅的类对象和其对应的事件方法(发送事件,取消注册)

根据类对象找到该类中的所有参数类型(取消注册)

okHttp

okHttp的7个拦截器

应用、RetryAndFollowUp、Bridge、Cache、Connect、网络、CallServer

addInterceptor与addNetworkInterceptor的区别

Retrofit

使用Retrofit的七个步骤

Retrofit原理解析

Glide

图片框架对比

自己写个图片加载框架,会考虑哪些问题

异步加载、切换线程、缓存、防止OOM、内存泄漏、列表滑动加载的问题

Glide图片加载流程

Glide如何处理生命周期

Glide的缓存

LruCache

LinkedHashMap

大图加载

Rxjava

Rxjava线程切换

Rxjava背压(Flowable)

Rxjava常用操作符

如何解决Rxjava内存泄漏

map和flatmap的区别

热修复

类加载流程

热修复的原理

插件化

插件化原理

组件化

组件化的原理

Activity

activity的生命周期(正常、跳转、跳到透明主题、点击Home键、弹出dialog、屏幕方向切换)

四种启动模式

onNewIntent()方法什么时候执行?

Service

启动Service的两种方式的区别

Service 的 onStartCommand 方法有几种返回值?各代表什么意思?

如何提高service的优先级?

广播

广播的分类

静态注册广播与动态注册广播的区别

BroadcastReceiver 与 LocalBroadcastReceiver 有什么区别?

ContentProvider

ContentProvider的作用

contentprovider初始化时机

简单framework

AMS WMS PMS

系统启动流程

1.启动电源以及系统启动

2.引导程序BootLoader

3.Linux内核启动

4.init进程启动

5.zygote进程启动

6.SystemServer进程启动

7.Launcher启动

activity启动流程

  1. Launcher进程请求AMS

  2. AMS发送创建应用进程请求 (AMS与Zygote进程建立Socket连接)

  3. Zygote进程接受请求并孵化应用进程

  4. 应用进程启动ActivityThread

  5. 应用进程绑定到AMS

  6. AMS发送启动Activity的请求

  7. ActivityThread的Handler处理启动Activity的请求

16ms原理

动画

android的几种动画

属性动画的原理

开发模式

MVC MVP MVVM的区别

SharedPreferances

SharedPreferances的工作原理

commit和apply的区别

RecyclerVIew

RecyclerView和ListView的缓存区别

打包安装

打包流程

apk结构

安装流程

适配

屏幕适配方案

版本变更及适配