1.Android启动模式
1.standard->默认启动模式,启动即创建.
应用场景:默认启动模式
2.singleTop->栈顶复用,栈顶存在即复用,否则新建.
应用场景:通知跳转详情页.
3.singleTask->栈内复用,栈内存在则复用,并且清除该activity之上的所有实例,否则新建.该模式下,如果要启动的activtiy已经存在,则会调用activity的onNewIntent()方法.
应用场景:App的home页面如果跳转到其它页面又要跳转回来.
4.singleInstance->新建一个任务栈单独存放该实例,其它app亦可启动该实例.
应用场景:项目中语音通话功能,来电显示页面.
2.Activity的生命周期
1.onCreate()->onRestart()->onStart()->onResume()->onPause()->onStop()->onDestroy().
2.activity4种生命状态
运行状态:当活动处于返回栈栈顶,并可与用户进行交互时.
暂停状态:当活动不在处于栈顶,但依然可见.比如弹出对话框时,activity是可见的,但此时不可交互.
停止状态:当活动不在处于栈顶,并不可见.系统仍然会保存活动的状态和成员变量.
销毁状态:活动从返回栈中移除.
3.Kotlin中常用语法糖和扩展函数
4.Java中有几种引用类型
四种:
1.强引用->最常用,因为jvm认为强引用是用户正在使用的对象,它无法确认到底该回收哪个,强行回收可能会导致系统严重错误,所以强引用不会被回收,当内存不足时,宁愿抛出OutOfMemeryError异常.
2.软引用->内存不足时会被jvm回收.软引用很适合用在缓存场景,当内存不足时可以主动释放,防止内存溢出.
3.弱引用->当jvm触发GC时就会被回收.再ThreadLocal中有被用到.
4.虚引用->可以在任何时候被回收.再mysql驱动中有被用到,当Connection对象被垃圾回收时,可以主动关闭连接.
5.Android消息机制是如何实现的
详细可参考:Android异步通信:手把手带你深入分析 Handler机制源码
Handler总结
6.Android触摸事件如何传递
详细可参考android事件分发机制详解
7.View的绘制流程
8.Android版本适配
9.IntentService
Android——IntentService浅析
IntentService是专门为开发者提供能在service内部实现耗时操作的service.可通过重写handleIntent实现耗时操作的处理.而且IntentService完成耗时操作后会主动销毁自己,IntentService可通过多次启动来完成多个任务,而IntentService只会创建一次,每次启动只会触发onStart()方法,内部实现了handler异步处理耗时操作的功能,一般多用在内部处理耗时操作的功能.
*为什么IntentService内部可以实现耗时操作.
解:在onCreate()中,通过handlerthread来开启一条线程,而handlerthread线程中会和我们平时用的不一样,在run方法中创建了looper对象,所以handlerthread能让IntentService在子线程中做耗时任务.
*HandlerThread本身也是Thread,只是在thread的基础上封装了handler的载体,并且在run方法中创建了looper对象,这也是为什么IntentService能在handlerThread中直接用handler的原因,而我们知道一个线程可以有多个handler,所以用handlerThread更加不用担心handler的创建,一般多用在多线程中直接处理任务.
10.app启动流程
源码阅读之Activity启动与App启动流程 - Android 9.0
无论应用是否启动,都会调用Activity.startActivity(),然后会进入Instrumentation.execStartActivity(),然后再跨进程进入ams.startActivity()(跨进程用的是Binder),ams在启动activity的时候会判断该启动的activity所在的进程是否存在,如果存在调用ActivityStackSupervisor.realStartActivityLocked()启动该activity,如果不存在ams会通过socket通知zygote进程fork出ActivityThread(activity需要的进程),fork出之后,activity就会通过attachApplication()把它的applicationThread给到ams,ams拿到applicationThread之后就可以调用realStartActivityLocked启动activity。
11.EventBus原理
Android面试之EventBus原理分析
EventBus:一款在Android开发中使用发布/订阅事件的总线框架,基于观察者模式,将事件的接收者和发送者分开,主要包括以下几步:
*注册事件的订阅方法:该步骤主要是找到订阅者下面有哪些方法需要被订阅。
*订阅操作:将需要订阅的方法存储到类似HashMap的数据结构中存储起来,方便后面发送事件,取消注册,资源释放的时候使用。
*发送事件:该步骤首先遍历事件队列,然后从队列中取出事件,并移除,拿到事件后判断处于什么线程,如果是非UI线程,则需要Handler去处理,如果是UI线程,则直接通过反射调用被观察的方法。
*反注册:该步骤主要是存储到HashMap中方法的移除和资源的释放。
12.RxJava
给 Android 开发者的 RxJava 详解
RxJava详解-线程切换原理篇
构成:Observer(观察者),Observeable(被观察者),emitter(发射器)
12.1.Rxjava:响应式编程,基于事件流链式调用的异步操作库。
*使用观察者模式,主要用于线程切换和提供一系列操作符。
12.2.Rxjava观察者模式
*传统观察者是一个被观察者多个观察者,当被观察者发生改变时,及时通知所有观察者。
*Rxjava是一个观察者多个被观察者,被观察者像链条一样串起来,数据在被观察者之间朝着一个方向传递,直到传递给观察者。
12.3.线程切换操作符
*subscribeOn():数据来源的线程.
*observeOn():数据处理的线程.
13.4.Scheduler类型
13.5线程切换原理
*RxJava通过subscribeOn指定被观察者发生的线程,observeOn指定观察者发生的线程.其中Schedulers.IO生成的是IoScheduler.通过观察者与被观察者订阅的过程中,首先会触发被观察者subscribeActual方法,在该方法中,可以看到最终会走scheduler的schedule方法,所以上面提到的IoScheduler实际是调用了schedule方法,最终会在NewThreadWorker里面生成ScheduledExecutorService对象,而ScheduledExecutorService实际是由ScheduledThreadPoolExecutor创建的一个核心线程,最大线程个数是Integer.Max_Value的线程池.最终会由ScheduledThreadPoolExecutor的submit或schedule方法执行传过来的Runnable对象,而Runnable执行的是被观察者的subscribe方法.所以解释了被观察者的subscribe方法是在子线程中执行的.
*observeOn是观察者发生的线程,AndroidSchedulers.mainThread()实质是HandlerScheduler对象,而在观察者部分,最终观察部分会走Scheduler的scheduleDirect方法,而HandlerScheduler的该方法里面包装了一个ScheduledRunnable对象,通过主线程的handler.postDelayed处理这个runnable对象.
13.AsyncTask原理
详细了解可参考:Android多线程:手把手教你使用AsyncTask
AnsynTask主要是对android中java线程池的封装,该类中默认开启两个线程池,一个线程池负责任务的排队处理,保证任务被单个处理,另一个线程池用来专门处理任务,最后任务处理完交给handler发送消息到主线程,由handler处理线程并交给onPostExecute()方法.
内部过程:
*AsyncTask初始化阶段创建了WorkerRunnable对象,它是处理doInBackground的callback对象,接着创建了futuretask对象,它是将上面的WorkerRunnable包装了一层runnable和future对象,实际上线程池要执行的任务就是WorkerRunnable对象。
*在执行任务的过程中,通过SerialExecutor对象来排队处理FutureTask,里面通过ArrayDeque来按顺序取出FutureTask对象,取出后交给了THREAD_POOL_EXECUTOR对象,它是在静态代码中创建的线程池,所以说THREAD_POOL_EXECUTOR才是真正执行关键任务的地方。
*执行完成后,剩下的就是主线程的handler将消息发送到主线程去处理。
问题:
*AsyncTask内部创建了一个线程池?
答案:两个线程池,一个负责排队处理任务,另一个线程池负责处理futuretask,也就是将上面的WorkerRunnable包装了一层Runnable对象。
14.mvc,mvp,mvvm的特点
正确认识 MVC/MVP/MVVM
Android架构之MVC、MVP、MVVM详解
MVC:
M=数据逻辑+业务逻辑
V=视图展示和用户交互
C=Model与View沟通的桥梁,将Model获取的数据回传给View
在Android中,view一般使用xml进行编写,但xml的能力不全面,需要Activity进行一些UI逻辑的编写,因而MVC中的V即为xml+Activity。Model数据层,在Android中负责网络请求和数据库操作,并向外暴露接口。Controller是争议比较多的写法:一种是直接把Activity当成Controller;一种是独立出Controller类,进行逻辑分离。比较符合MVC思想的笔者认为是后者。因为前者直接在Activity中进行书写业务逻辑就会和UI逻辑混合在一起了,达不到模块分工的效果。
特点:
*耦合性低:模块代码之间的关联程度不高,可以拆解各种业务模块,利用这个框架可以使view层和model层很好的分离.
*可扩展性好:由于mvc具有耦合性低的特点,所以当我们添加代码,扩展代码的时候,可以不用修改太多代码,有效降低bug和线上crash的出现效率.
MVP:通过P层建立Model与View的关联,以接口的方式实现M层和V层的解耦.缺点是每增加一个功能,需要增加相应的接口回调,因为Mvp的核心就是通过接口实现隔离,将相关的业务交给了P层.
需要注意的几点:
*p层的逻辑处理单一的功能,不要融合一个模块下的增删改查的整个功能.
*由于P层持有了V层的引用,通常在p层使用弱引用持有V层实例,在P层销毁的时候需要销毁V层的引用.
*契合类是指p层和v层的接口类放在一个contract接口类中,契合类方便管理业务层的功能,将单个功能放在一个contract契合类中.
MVVM:主要用到了观察者模式,利用数据绑定当数据改变时反映到相应View进行改变.M层同MVP的M层,都是网络请求+数据存储来实现该层的.里面的双V,一个指的ViewModel实现的,另外一个AndroidDataBinding实现V层,ViewModel获取到Model层的数据后,通过观察者模式通知AndroidDataBinding在UI上改变,缺点的话,只能吐槽下AndroidDataBinding在xml中写逻辑的时候,无代码提示,感觉完全是在写js似的,可读性对于初级的来说有点难看懂.
15.android中用到的观察者模式有哪些地方
观察者模式是由一个被观察者和一个观察者组成的,被观察者的状态改变时会主动通知所有的观察者做相应的刷新.android中最经典的要说listview数据源刷新,在setAdapter的时候,生成一个AdapterDataSetObserver,紧接着就是订阅该观察者,该观察者onChange方法里面有个requestLayout方法,该方法是触发UI发生变化的方法.在BaseAdapter里面可以看到notifyDataSetChange方法实际上触发的是DataSetObservable被观察者的notifyChanged方法,notifyChanged会触发AdapterDataSetObserver的onChange方法.所以最终会走listview的requestLayout,最后刷新UI.
16.说说Google新出的Lifecycle框架
详细了解可参考:“终于懂了“系列:Jetpack AAC完整解析(一)Lifecycle 完全掌握!
将类的生命周期方法移交到Lifecycle中管理,实现对类的生命周期的监听,从而在lifecycle中处理生命周期的逻辑代码.这里涉及到几个对象:
lifecycleObserver接口(LifeCycle观察者):实现该接口的类,通过注解的方式,可以通过被LifecycleOwner类的addObserver(LifecycleObserver o)方法注册,被注册后,LifecycleObserver便可以观察到LifecycleOwner的生命周期事件.
LifecycleOwner接口(Lifecycle持有者):实现该接口的类持有生命周期(Lifecycle对象),该接口的生命周期(Lifecycle对象)的改变会被其注册的观察者LifecycleObserver观察到并触发其对应的事件.
Lifecycle(生命周期):和LifecycleOwner不同的是,LifecycleOwner本身持有Lifecycle对象,LifecycleOwner通过其Lifecycle getLifecycle()的接口后去内部Lifecycle对象.
State(当前生命周期所处状态):几种事件状态.
Event(当前生命周期改变对应的事件):当Lifecycle发生改变,事件状态的回调event.
17.Okhttp原理
知识点:OkHttp 原理 8 连问
整个网络请求大致过程:
1.通过建造者模式构建OkhttpClient与Request。
2.OkhttpClient通过newCall发起一个新的请求。
3.通过分发器维护请求队列和线程池,完成请求调配。
4.通过五大默认拦截器完成请求重试,缓存处理,建立连接等一系列操作。
5.得到网络请求结果
总结:okhttp主要实现了异步,同步的网络操作,创建了不同的call对象,这里的call对象是一个个的runnable对象,由于我们的任务是很多的,因此这里有Dispatcher包装了线程池来处理不同的call,其中该类中创建了三个队列,分别用于存放正在执行的异步队列,同步队列以及准备的队列.最后在执行每个任务的时候,采用队列的先进先出原则处理每一个任务,都是交给了后面的各种拦截器处理,有请求准备的拦截器,缓存拦截器,网络连接器拦截器,每一个拦截器组成了一个责任链的形式.到最后返回response信息.
Okhttp的底层是通过java的Socket发送Http请求与接收的(http基于tcp协议),但是okhttp实现了连接池的概念,即对于同一主机的多个请求,可以公用一个socket连接,而不是每次发送完http请求就关闭底层的socket,这样就实现了连接池的概念.而okhttp对socket的读写操作使用的okio库进行了一层封装.
18.Retorfit原理
retrofit是基于okhttp封装成的Restful网络请求框架,通过工厂模式配置各种参数,通过动态代理,注解实现网络请求。retrofit利用了工厂模式,将分为生产网络请求执行器(callFactory),回调方法执行器(callbackExecutor),网络请求适配器(callAdapterFactory),数据转换器(converterFactory)等几种工厂。
callFactory:负责生产okhttp的call,大家都知道okhttp通过生产call对象完成同步和异步的请求。
callbackExecutor通过判断不同的平台,生产对应平台的数据回调执行器。其中android端的回调执行器是通过handler回调数据。
callAdapterFactory:数据解析工厂,一般我们配置json的数据解析适配器就行。
converterfactory:数据转换的工厂,一般我们配置rxjava的数据转换就行。
retrofit通过动态代理的模式实现将接口类配置的注解,参数解析成http对象,最后通过okhttp实现网络请求。
优点:
1.可以配置不同的http实现网络请求,如okhttp,httpclient等。
2.请求的方法参数注解都可以定制。
3.支持同步,异步,rxjava。
4.超级解耦。
5.可以配置不同的反序列化工具解析数据,如json,xml等。
6.使用方便灵活。
缺点:
1.不能解除序列化实体和相应数据。
2.执行机制太严格。
3.使用转换器比较低效。
4.只能支持简单的自定义参数类型。
19.RecycleView源码,缓存分析
抽丝剥茧RecyclerView - 化整为零
深入理解RecyclerView的缓存机制
RecycleView使用了强大的分工操作,显示,排版由LayoutManager处理,数据显示由adapter处理,item上下左右动态加入绘制由ItemDecoration处理,item的动画由ItemAnimation处理.
面试主要分析recycleView缓存,recycleView缓存是有内部类Recycler维护。
一级缓存有mAttachedScrap,里面存放的都是当前屏幕正在显示的viewHolder的缓存。
二级缓存是mCachedViews,里面放的都是移除到屏幕外的viewHolder缓存。
三级缓存mRecyclerPool存放以itemType区分的ViewHolder。一般用在RecycleView嵌套RecycleView的时候用到,比如外层的RecycleView的item中有RecycleView,那么里面的RecycleView通过公用外层的RecycleView的RecyclePool来减少里面RecycleView的ViewHolder创建.
20.Binder机制
Carson带你学Android:全面剖析Binder跨进程通信原理
binder机制是android端进程间通信的基石,采用aidl的ipc通讯方式,我们可以利用它来定义两个进程相互通信的接口。它是基于service实现的一种进程间通信机制。它的本质是c/s架构的,需要一个服务端,一个客户端。AIDL通信方式里面有四个对象。
1.IInterface:专门负责接口的调度
2.Stub:负责通信的响应和发送给service端的数据。
3.Proxy:负责两个进程通信的包装,算是间接调用Stub的包装类。
4.service:服务端处理数据的关键类。
关系图如下:
21.Android JetPack
android jetpack是google提供专门快速开发app的一套组件,快速搭建mvvm框架的实现,其中包括Lifecycle,LiveData,ViewModel,Room,DataBinding,Navigation,Paging,WorkerManager等一系列优秀框架。
*Lifecycle:实现和activity,fragment生命周期感知的框架,实现数据层和view层销毁时候解绑。原理是Lifecycle为每个活动组件添加了一个没有界面的Fragment,利用Fragment周期会根据活动生命周期变化的特性实现的特性,从而实现生命周期的感知,然后根据注解Event查找执行相应的方法。
*LiveData:数据改变的同时,主动通知ui,让ui做出相应的逻辑判断。原理是内部保存了LifecycleOwner和Observer,利用LifecycleOwner感知生命周期中的变化,Observer在数据改变时遍历所有观察者并回调方法。
*ViewModel:view层和model层的桥梁,是数据驱动界面的关键地方,也是我们ui层在数据丢失的情况下,viewmodel还能继续保持原有的数据,原理是将数据保存到viewmodel中,然后为活动添加一个HolderFragment,HolderFragment中保存了ViewStore的实例,ViewStore中使用Map保存了ViewModel,从而在活动重新创建时获取到原来的ViewModel.
*Room:model层本地数据库的框架,通过实体映射对应的db表结构,将实体映射到db关系型数据库里面。跟greendao差不多,room数据库版本升级数据迁移比greendao迁移要麻烦。
*DataBinding:是一个可以在xml布局文件中实现ui逻辑的框架,并且它的ui层和数据层双向驱动还是挺不错的。
*Navigation:新出的可视化管理fragment的组件,通过在xml中配置fragment之间的跳转。
22.协程
23.热修复
24.get请求能不能带body
HTTP GET 请求可以有 body 吗?
结论:Http协议没有为GET请求的body赋予语义,也就是既不要求,也不禁止请求带body.大多数http实现从技术上都支持http请求带body,少数实现会禁止,少数实现会不建议.
25.线程池
26.Glide缓存
Android:深入剖析图片加载库Glide缓存功能(源码分析)
27.android versionCode和versionName的区别
28.gradle知识总结
Android Studio之Gradle和Gradle插件的区别
*gradle
定义:java项目自动化构建工具,基于Groovy特定领域语言来声明设置.
引申:Groovy语言是一种动态语言,语法跟java很像,在java基础上做了不少改进.
作用:能够简化项目的编译,打包,测试过程,对项目进行构建,依赖管理等功能.\
gradle插件(开发中常说的gradle就是指gradle插件)
作用:可以调用gradle本身的代码和批处理工具来构建项目,进行依赖管理,同时也可以调用android sdk的编译,打包,签名功能.
*gradle和android studio的关系
没有关系,只是用gradle用来作为android studio的构建工具而已.
29.进程间通信方式
1.AIDL:功能强大,支持进程间一对多的实时并发通信,并可实现RPC(远程过程调用).
2.Messenger:支持一对多的串行实时通信,AIDL的简化版本.
3.Bundle:四大组件的进程通信方式,只能传输Bundle支持的数据类型.
4.ContentProvider:强大的数据源访问支持,主要支持CRUD操作,一对多数据共享.
5.BroadcastReceiver:广播,但只能单向通信,接受者只能被动接受信息.
6.文件共享:在非高并发的情况下共享简单的数据.
30.Android性能优化总结
31.Android 之 Context
深度详解 Android 之 Context
描述:android上下文环境,可以理解为当前对象在应用程序中所处的工作环境,其内部定义了很多访问应用程序环境中全局信息的接口,通过它可以访问到应用程序资源有关的类,如Resources,Package等,和调用应用程序级的操作.如启动activity,service,发送广播等.
*context是一个接口,抽象类是ContextWrapper,实现类是ContextImpl.
*Android系统中一个应用程序的context个数=activity个数+service个数+1(application)