知识点
网络基础
1. TCP三次握手
2. TCP,UDP区别
3. Http与Https
4. 多线程断点续传如何实现
通过请求头 Range bytes=100-500告诉服务器要哪段数据
服务器状态码206(HTTP_PARTRIAL)表示支持断点下载
通过RandomAccessFile seek到开始写入的位置,写入文件。
Java基础
1.并发编程
synchronized关键字(类锁,对象锁的区别;synchronized底层实现)
synchronized代码块:monitorenter,monitorexit指令
synchronized方法:ACC_SYNCHRONIZED标志
内存模型和volatile
工作内存,主内存。内存屏障-storestore,storeload,loadload,loadstore,防止指令重排序。通知工作内存数据失效,从主内存取,保证了可见性。
并发相关的数据结构和系统类(Atomic*,BlockingQueue)
Java并发编程-无锁CAS与Unsafe类及其并发包Atomic
线程,线程池
ThreadLocal原理?
ThreadLocal对象本身会被当作key,每一个Thread对象内部都有一个TheadLocalMap
ThreadLocalMap内部通过Entry数组存数据。当我们通过threadLocal set一个value时候,其实set方法内部做的是找到当前线程t,取出t的ThreadLocalMap,调用threaLocalMap.set(threadLocal,value),threadLoca自身带有一个hashCode,与线程threadlocalMap内部数组长度-1按位与(&)产生数组下标,把value存到该下标位置。所以每个线程都是通过自己内部的ThreadLocalMap存数据的,数据当然会互不干扰。
sleep,wait区别?哪个会释放锁?
线程池有哪几种?如何创建?
FixedThreadPool
,SingleThreaPool
,CachedThreadPool
,ScheduledThreadPool
线程池如何复用线程的?
其实是一个生产消费者模型,Worker内部有一个Thread,start之后就一直while循环从任务队列中取任务;
如果没有达到核心线程数,直接new一个Worker,执行任务。
AsyncTask源码,可以在子线程实例化AsyncTask吗?可以在子线程调用execute吗?
答:都可以。在子线程调用execute要注意,onPreExecute方法中,不能操作ui,因为execute会间接回调该方法。
HandlerThread,IntentService原理?使用场景?
HandlerThread继承自Thread,其run方法中,调用Looper.prepare,Looper.loop开启了消息循环。
IntentService的onCreate方法中new除了一个HandlerThread,使用该HandlerThread内部的looper初始化了ServiceHandler,每次调用startService的时候,IntentService的onStartCommand就会被调用,onStartCommand调用onStart,onStart中把intent数据封装成message,通过ServiceHandler发送到消息循环中,ServiceHandler的handleMessage接收到数据就会回调onHandleIntent(),我们使用IntentService就是重载onHandleIntent,onHandleIntent执行完就会调用stopSelf结束自己。由此可见,IntentService适合在后台顺序执行一系列任务(比如静默的上传一些日志文件),顺序执行是因为这些任务都会被投递到messagequeue进行消息循环。
2.GC相关
内存划分:
标记垃圾对象:引用计数,GCRoot可达性分析(哪些变量或常量可作为GCRoot?)
GCRoot:
Java虚拟机栈引用的变量
方法区中静态属性引用的对象
方法区中常量引用的对象
Native方法中引用的对象
回收垃圾对象:
标记清除,
标记整理,
复制算法,
分代回收(对jvm内存区域分代,对不同的代使用不同的回收算法)
3.类加载机制
Java 中的类加载器:
BootstrapClassloader
(jre/lib
)ExtensionClassloader
(jre/lib/ext
)AppClassloader
(classpath
)
Android中的类加载器:
ClassLoader
BootClassLoader
,BaseDexClassLoader
,SecureClassLoader
PathClassLoader
,DexClassLoader
,InMemoryClassLoader
双亲委派模型
basedexclassloader.findclass
->dexpathlist.findclass
->循环dexpathlist
内部的element
数组,调用element .findclass
->dexfile.loadClassBinaryName
热修复应用
插件化应用
4.常用的数据结构
ArrayList
,HashMap
,ConcurrentHashMap
,HashTable
Lrucache
与LinkedHashMap
SparseArray
与HashMap
对比ArrayMap
5.常用技术
反射
动态代理
注解
Android知识点
1.Activity相关问题
Activity生命周期
onSaveInstanceState
,onRestoreInstanceState
是否用过?(保存Activity状态)
启动一个透明主题的Activity,当前Activity生命周期的变化?弹出一个dialog呢?Activity启动模式
用过哪些启动模式?(比如MainActivity使用singleTask)IntentFilter
匹配规则
对于一个Activity
有多个intent-filter
,一个匹配成功就行。一个intent-filter
有data
、category
、action
多个条件,所有条件都匹配才算成功。action
匹配规则:intent
中要存在action
,且只要一个action
值匹配上就行(字母区分大小写)category
匹配规则:intent
中可以没有category
,但只要有,必须和intent-filter
中指定的某个category
相匹配。data
匹配规则:intent
中必须有data
。为什么模块化/组件化的架构中
schema
跳转?Activity启动过程
startActivityForResult
->instrumetion.execStartActivity
->ActivityManagerNative
->AMS
->ActivitySuperVisor
->ActivityStack
->ApplicationThread
->ActivityThread
->H
->handleLaunchActivity
2.Android的IPC机制
- Android有哪些跨进程通信的方法,用过哪种
AIDL
,ContentProvider
,Socket
,BroadcastReceiver
- Binder机制
Binder学习指南
Android Binder设计与实现 - 设计篇3.View事件分发相关问题
- 简述View的事件传递机制
- 如何解决滑动冲突
具体来说,viewpager如何解决滑动冲突?4.View绘制流程
- onMeasure
measurespec
getWidth
,getMeasuredWidth
有什么区别?getMeasuredWidth
在onMeasure
之后就能取得值getWidth
要在onLayout
之后才有值,因为mWidth=mRight-mLfet
,而mRight
和mLeft
要在onLayout
时才确定。
一般情况下getMeasuredWidth
和getWidth
取得的值一样,除非在onLayout
中强行改变了mRight
,mLeft
。 - onLayout
- onDraw
-
invalidate
,postinvalidate
,requestlayout
区别invalidate
和postinvalidate
都只会引起view
重新绘制,前者在主线程中调用,后者可在子线程调用requestlayout
会引起view树
重新measure
,layout
,draw
。 - 分辨率适配,原理?
-
recyclerview
,listview
对比?缓存实现有什么不同 -
LinearLayout
,RelativeLayout
当使用weight
时,linearlayout
会measure
两次,第二次是给使用了weight
的view
分配剩余空间。relativelayout
本身就需要measure
两次,因为其子view
布局在横向和纵向上都会相互依赖。
但是relativelayout
可以有效减少布局层级。5.动画
animation
,animator
什么区别?原理?
属性动画画一个抛物线?
6.消息机制
-
Handler
,MessageQueue
,Looper
-
epoll
机制(epoll_create
,epoll_wait
,epollctl
) - 异步
message
,同步message
,barrier
Handler之同步屏障机制(sync barrier)
Handler之同步屏障机制(sync barrier)7.四大组件工作过程
- Activity启动流程
ams是如何匹配到要启动的activity的? - Service启动流程(bind和start的区别)
多次start
只会调用一次onCreate
。每次都调用onStartCommand
。通过stopService
或stopSelf
停止bind
需要结合ServiceConnection
,在onServiceConnected
中拿到服务端返回的binder
,和服务端进行通信。 - BroadcastReceiver
两个应用同时注册一个广播,优先级一样,哪个会先收到? - ContentProvider
contentprovider
怎么升级维护?8.Bitmap相关
bitmap格式?各占多少字节?
Android性能优化:Bitmap详解&你的Bitmap占多大内存
大图加载如何不oom?
regionDecoder
Android各个版本新特性
- art,dvm的区别
dvm:
运行期解释dex文件
堆内存划分为Zygote Space,Allocation Space
2.2之后引入JIT对热点代码预编译
Art:
安装时通过AOT把字节码编译成了本地机器码,运行速度更快。安装速度变慢,同时需要更多的空间存储机器码。
7.0之后引入JIT作为AOT的补充,节省了安装时间也节省了空间
Art减少了GC停顿的次数
Art堆内存划分:Zygote Space,Allocation Space,Image Space,Large Object Space。
- 5.0Material Design,自定义behavior?
- 6.0运行时权限,权限适配?
- 9.0hide api限制
开源框架源码
- ButterKnife
- EventBus
- OkHttp
RealCall,Dispatcher,InterceptorChain,StreamAllocation
RetryAndFllowUpInterceptor 失败重试
CacheInterceptor 缓存策略
BridgeInterceptor 添加请求头信息
ConnectionInterceptor 构造httpcodec和获取realconnection
CallServerInterceptor 使用httpcodec和realconnection发送请求
- Retrofit
create->loadServiceMethod->ServiceMethod.Builder
ServiceMethod的build方法调用createCallAdapter创建了CallAdapter
CallAdapter在这里默认返回的是ExecutorCallAdapterFactory.get所返回的。
ExecutorCallbackCall
Paltform为Android平台提供了切换回主线程的Executor
- Glide
一次图片加载流程:
缓存机制:
Glide有三级缓存,Lrucache,WeakRefrence(会通过IdleHandler清理),DiskLrucache。
Android常用架构,设计模式
- MVC,MVP,MVVM
- 源码中的设计模式
Dialog的builder模式
WindowManagerImpl和WindowManagerGlobal之间的桥接模式
Retrofit动态代理(动态代理的底层原理?),对方法参数的处理是策略模式。
OkHttp中的责任链模式
性能优化
1.启动速度优化
- 启动速度测量
- 耗时方法分析
- 体验优化,异步化,task化
2.内存优化
3.卡顿优化
- CPU Profiler(Trace View),Systrace,StrictMode
以上方案无法带到线上
- 自动化卡顿检测AndroidPerformanceMonitor
- ANR
原因:
Keydispatchtimeout 5s
Broadcasttimeout 前台10s 后台60s
Service 前台20s 后台200s
4.网络优化
指标:流量,接口访问速度,请求成功率
手段:HttpDNS,gzip,图片压缩,请求合并
5.电量优化
6.包体积优化
项目细节
1.可能被问到的模块,功能点
- 轮播图原理?会引起内存问题吗?
- 扫码使用的zxing原理?如何优化提高速度识别率?
- 模块化?ARouter原理?
2.亮点难点
AOP实现统一登陆状态判断
自定义gradle插件,在构建过程中修改字节码,实现了耗时盲区监控,自动替换引导页
模块化
常见算法题
计算viewgroup层级
手写生产者消费者模型?不用BlockingQueue如何实现?
用两个栈实现一个队列?
快排,堆排序,冒泡排序?
动态规划钱币问题,走台阶问题?
Framework知识点
一、系统服务相关
1.谈谈zygote作用
作用:zygote作用有孵化应用进程、启动SystemServer。
启动流程:init进程通过读取init.rc配置文件,启动zygote。zygote启动过程主要分为native部分和Java部分。native部分完成了Android虚拟机的创建、JNI函数(TODO:比如哪些JNI函数呢)的注册、通过JNI调用ZygoteInit.java的main函数进入Java世界。Java部分完成了预加载资源、启动Systemserever、开始loop循环处理socket消息。
工作原理:runOnce函数处理socket消息,根据参数孵化子进程。
2.说说Android系统的启动流程
3.你知道怎么添加一个系统服务吗
添加系统服务的时机:可在SystemServer中启动系统服务的地方添加,跑在SystemServer进程。也可以在init.rc文件中配置,跑在独立的进程。
服务端需要做什么:启用binder机制(如果是跑在SystemServer进程的服务则不需要,因为SystemServer已经启用了),把自己注册到ServiceManager。如果是配置在init.rc文件中的服务,需要提供一个main入口函数。
客户端需要做什么:为系统服务实现一个ServiceFetcher,添加到缓存中,这样可以保证和其他系统服务一致的调用方式。
4.系统服务和bind的应用服务有什么区别
启动方式区别:系统服务在SystemServer中启动或在init.rc文件中配置,由init进程拉起。应用开发中的Service,由开发者调用bindService启动。
注册方式区别:系统服务由ServiceManager的addService方法注册
使用方式区别:系统服务通过context.getSystemService获取到binder来使用,应用服务通过ServiceConnection中的onBind回调拿到binder对象来使用。
5.ServiceManager启动和工作原理是怎样的
启动:init进程读取init.rc文件,拉起ServiceManager进程,执行入口main函数。main函数会启用binder机制,通过BINDER_SET_CONTEXT_MGR命令将自己注册为上下文管理者。通过BC_ENTER_LOOP指令将当前线程注册为binder线程,开启binder loop循环,处理binder中的消息,这样就可以和其他进程通信了。
工作原理:
1.如何获取ServiceManager的binder?
通过默认的0号引用
2.如何通过smgr添加服务
调用addService
3.如何通过smgr获取服务
调用getService
二、应用进程相关
1.你知道应用进程是怎么启动的吗
当系统尝试打开一个activity或者service时,会先检查其所在的进程是否已经存在(app!=null && app.thread!=null)。由AMS通过socket通信将ActivityThread的类名发送给zygote进程,zygote进程孵化出子进程,执行ActivityThread的main函数。main函数中通过thread.attach(false)通知AMS进程启动完成。
2.应用是怎么启用binder机制的
zygote在fork出应用进程后,调用handleChildProc->zygoteint.zygoteinit(),最终调用AppRuntime中的onZygoteInit这个native方法,onZygoteInit中会通过调用ProcessState.startThreadPool()开启binder线程池,其中打开binder驱动,映射内存等操作都是在获取ProcessState实例时做的,startThreadPool最终是调用IPCThreadState.joinThreadPool()开始了一个do。。while循环,不断从处理binder中的消息。到此,应用的binder机制就启动了。
3.谈谈你对Application的理解
作用:1.常在其onCreate生命周期中做一些sdk初始化工作
2.常用来保存一些应用运行期间所需的数据
3.提供应用上下文
继承关系:Application->ContextWrapper->Context
生命周期:在应用进程启动后,执行ActivityThread的main函数,其中会调用thread.attach(appThread)向AMS报告应用进程启动完成,并把appThread(ApplicationThread)的binder对象传了过去,这样AMS和应用进程就可以进行双向的binder调用了。AMS端收到appThread后,调用其bindApplication,应用端收到跨进程调用后,发送BIND_APPLICAION消息,应用主线程收到消息,调用handleBindApplication,反射创建appliaction,调用其onCreate。所以这里调用顺序是:application构造函数->attachBaseContext->onCreate。
4.谈谈你对Context的理解
作用:应用上下文,用来获取一些应用信息,系统服务。
应用中有几种Context?其继承关系?
Activity-ContextThemeWrapper-ContextWrapper-Context
Service-ContextWrapper
Application-ContextWrapper
所以应用中context的个数=application个数+activity个数+service个数
Context是一个抽象类,其实现是ContextImpl,context的创建是在创建每个application,activity或者service之前,通过new ContextImpl()创建的,并且各组件调用attach保存context,实际是attach是调用了attachBaseContext给ContextWrapper的成员mBase赋了值,ContextWrapper继承了Context,其实现的抽象方法都是间接调用了mBase相应的方法,是一种静态代理。如果我们通过反射换掉ContextWrapper的mBase,就可以对context的一些方法进行hook或者改造。
三、Activity组件相关面试题
1.说说Activity的启动流程
2.说说Activity的显示原理
通常我们通过setContentView设置Activity的布局文件,这其实是调用了window.setContentView。Activity的window是在attach方法中初始化的,Window是一个接口,PhoneWindow是其实现。所以在Activity中调用setContentView实际上调用了phonewindow的setContentView,在PhoneWindow该方法中,会先installDecor,即初始化DecorView,DecorView就是一个FrameLayout,是activity界面布局的根view。installDecor方法中会根据不同的feture选择不同的系统布局,加载到decorview中。这些系统布局中都有一个id为ID_ANDROID_CONTENT(即contentParent)的viewgroup,我们通过setContentView设置的布局,会被加载到contentParent中。至此,setContentView算是完成了activity布局的加载,view的创建。
而activity布局中这些view的测量,绘制,布局,是在ActivityThread中handleResumeActivity中触发的。
3.应用的UI线程是怎么启动的
四、其他应用组件相关面试题
1.
五、UI体系相关面试题
1.说说屏幕的刷新机制
2.surface跨进程传递原理
六、进程间通信相关面试题
1.Android Framework用到了哪些跨进程通信方式
- 管道
特点:半双工,传输的数据量小
用处:Android消息机制中,Looper的死循环就通过epoll_wait阻塞在管道的读端,监听写事件,一旦有数据写入,就唤醒当前线程。
- socket
特点:全双工
用处:AMS和zygote通信是采用的socket方式,比如启动应用进程是,AMS通过socket把ActivityThread类名发送到了zygote进程,zygote进程在runOnce方法解析参数,执行ActivityThread的main方法
- 共享内存
- binder
2.谈谈你对binder的理解
作用:Android特有的跨进程通信方式
特点:相比于其他方式,它安全,高效,使用方便。安全体现在其调用者的身份标记只能由binder机制在内核态中添加。高效在于其使用了内存映射,只需要一次数据拷贝。方便在于我们可以像调用普通的java方法一样使用binder机制,模糊了进程边界。
binder通信架构图: