最近面了几家公司,感觉虽然说八股文不怎么被提倡了,面试不怎么考八股文了,但是我怎么感觉这种说法在我身上不适用呢,基本面的每家公司都有八股文的内容,有一家还跟我聊了半小时八股文,差点嘴里要冒火星子了,所以这种东西还是要多准备准备,但是说起来容易,做起来就很难了,光Android应用层能考的八股文就有一大堆,没有一定的时间是没法都理清的,所以只能是慢慢积累,多看多写,能记住一些是一些,这篇文章又整理了几个八股文,有兴趣的可以看下
1.App的启动流程
- 当点击了app图标后,由Launcher进程通过Binder IPC向system_server发出startActivity的请求
- system_server在收到请求后,向zygnote进程发出创建进程的请求
- zygnote在收到请求后,fock出了一个子进程也就是App进程,App进程通过Binder IPC向system_server进程发出attachApplication的请求
- system_server进程收到请求后,经过一系列操作,通过Binder IPC向App进程发出scheduleLaunchActivity的请求
- App进程的binder线程,也就是ApplicationThread,收到请求后,通过handler向主线程发出LAUNCH_ACTIVITY的消息
- 主线程收到消息后,通过发射机制创建目标Activity,并且调用目标Activity的OnCreate方法
- 然后进入Activity生命周期渲染页面,结束后页面就被渲染到屏幕上了
2.线程有哪些状态
- 新建状态(New):新创建了一个线程对象,仅在堆中分配内存
- 就绪状态(Runnable):线程被创建后,其他线程调用了该线程的start方法
- 运行状态(Running):就绪状态下的线程获得了cpu时间片
- 阻塞状态(Blocked):运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态,阻塞状态是正在运行的线程遇到某个特殊情况。例如,延迟、挂起、等待I/O操作完成等。 进入阻塞状态的线程让出CPU,并暂时停止自己的执行。线程进入阻塞状态后,就一直等待,直到引起阻塞的原因被消除,线程又转入就绪状态,重新进入就绪队列排队
- 死亡状态(Dead):线程执行完了或者因异常退出run()方法,该线程结束生命周期。死亡的线程不可再次复生。
画了一个草图来描述这五种状态的关系
3.java中的四大引用
- 强引用:当对象是强引用的时候,就不会被垃圾回收器回收,当内存不足的时候,会抛出oom异常,如果想让垃圾回收器回收该对象,就要显示的将对象置为null,那么垃圾回收器就会在合适的时间回收它
- 软引用:不会很快去回收具有软引用的对象,垃圾回收器会根据具体堆的使用情况去判断是否去回收,即超过一定阀值时才会去回收
- 弱引用:如果一个对象是弱引用的,那么无论什么时候,只要被垃圾回收器检测到,那么都会被回收
- 虚引用:它不会决定对象的生命周期,任何时候都会被垃圾回收器回收,它的作用是跟踪对象被垃圾回收器回收的活动,经常与
ReferenceQueue
一起使用
4.Fragment的生命周期
5.简述双亲委托机制
双亲委托机制的本质就是,当一个类加载器收到类加载请求时候,它首先会一直向上找它的父加载器,直到上面没有父加载器了,再去加载类,只有父加载器在自己的搜索范围内找不到指定类,才会交给子加载器去加载,大致一个流程图如下
6.协程launch有哪些参数
我们通常在使用launch
创建一个协程的时候,没啥意外都会这么写
很简洁,看起来很舒服,久而久之我们就会忽略了一点,其实launch
这个函数也是有其他参数的,当我们点到launch
函数里面后,会看到,launch
函数里面有三个参数
其中第三个参数就是我们的协程作用域,前两个是什么呢?先来看context
,它是一个协程的上下文环境,默认是没有上下文环境的,作用是什么呢?来看下面这段代码
这里有三个协程,分别都是打印一段文字,其中第一个协程在启动后里面将它cancel
掉,第二个协程的上下文环境设置的是第一个协程,那么这段代码的执行结果会怎么样呢?
仅仅只是执行了第三个协程,第一个没执行很好理解因为cancel
掉了,而第二个协程由于它的上下文环境设置的是第一个协程,也就是依赖于第一个协程的,所以第二个协程也不会执行,第一个参数的作用大概理解了,来看下第二个参数start
,它是一个CoroutineStart
的枚举类型,个人把它理解为协程的启动模式,点到里面可以看到有这么些枚举值
- DEFAULT:默认值,立即根据它的上下文环境执行协程
- LAZY:不会立即执行,只有在被调用的时候才会执行
- ATOMIC:当调用cancel函数的时候,会将挂起点之后的代码取消
- UNDISPATCHED:不调度,线程与父协程所在的线程是一致的
7.如果子协程发生异常,会不会影响它的兄弟协程
这种问题知道的肯定直接脱口而出,不知道的咱就自己写段代码试试看
现在有这么一段代码,它的执行结果如下所示
如果其中一个协程里面出现异常了,那么其他协程还会不会执行呢,我们改下代码
现在的执行结果如下所示
可以看到只执行了第一个协程,出现异常的协程的后面的协程都没有执行
8.如何让协程的异常不影响它的其他兄弟协程
上面我们讲到了当协程出现异常后,它的后续要执行的兄弟协程也不会执行了,那么有没有办法让它的兄弟协程别受影响呢,这里介绍俩种方式
SupervisorJob
之前在介绍launch
函数中的参数时候,我们知道context
参数是协程运行的上下文环境,那么这里我们可以给出现异常的协程的上下文环境设置一个SupervisorJob
,这样就能防止协程的异常影响它的兄弟协程
这个时候再看下执行结果有什么不一样
可以看到这里第三个协程也执行了,除此之外,还有另一个办法
supervisorScope
除了给协程设置上下文环境,还可以把所有兄弟协程都包在一个supervisorScope
作用域里面,这样也可以达到某个协程出现异常后,不影响其他协程
这段代码的执行结果如下
同样除了出现异常的协程外,其他协程都执行了
9.协程之间是如何通信的
这题要听清楚了,很容易听成线程之间如何通信,毕竟这个也是个常见题,但是协程之间的通信就不一样了,可能你会脱口而出Flow
,当然这个是对的,但有可能面试官还会继续问你还有吗,那么这个时候,你就要知道协程里面还有一个Channel
也可以实现协程间的通信,来看下面这个例子,假如这里有两个协程
一个协程里面有个字符串,现在我想要让另一个协程拿到这个字符串,就要用到Channel
了,并且使用send
以及receive
函数来发送接收数据,代码如下
这个时候第二个协程就拿到了传送过来的数据
那么如果第一个协程里面是一个网络请求,数据需要等一段时间才能拿到,那么第二个协程还会接收到数据吗,答案是会的,因为receive
函数它是一个挂起函数,它会等到有数据来了以后再获取数据,我们来试一下
我们给第一个协程加了个延迟三秒,并且在操作执行前以及协程二获取到数据的地方打印了时间,看下具体执行结果
和预期的一样,第二个协程在没有接收到数据时候一直是挂起状态,直到延迟时间结束了,数据发送过来了,第二个协程才执行
10.协程的Channel里面的三个参数都是做什么用的
当点到Channel的构造函数里面的时候,会看到它有三个参数
咱先来看第一个参数,capacity
是容量的意思,那么什么时候应该设置这个值呢,来看下这个例子
这里在第一个协程中连续发送了五条数据,在第二个协程里面调用receive
函数来接收数据,我们可能猜到了,它接收的数据应该是第一条数据
那么我们不是还发送了另外四条数据吗,都到哪去了呢?其实我们可以从截图左上角发现,这个程序其实还没有结束,没有结束的原因是程序仍旧在等待去接收另外四条数据,因为我们只调用了一次receive
函数,也就是我们再调用四次receive
函数就可以让程序完成执行了,我们试一下
诶!果然在多调用四次receive
函数后,程序就完成执行了,但是这个做法太傻了,如果我们发送了100条数据呢,也在下面调用100次receive
吗?所以这里就要用上我们第一个参数capacity
了,这个参数就表示一个阻塞队列的大小,默认是0,所以我们只需要扩大这个队列就好了,让其他数据在队列里面等待,代码如下
这里将大小增加到5了,再来运行下程序看看
可以发现虽然只调用了一次receive
函数,但是程序已经执行完成了,因为我们已经扩大阻塞队列的大小了,其余数据都被塞入队列里面去了,当然除了扩大阻塞队列大小,我们还可以使用第二个参数来做同样的事情,第二个参数叫onBufferOverflow
,它是一个枚举类型,有以下三个枚举值
我们默认参数用的就是第一个SUSPEND
,意思就是让多出来的数据处于挂起状态,而另外两个枚举值,字面意思就可以知道,是丢弃最老以及丢弃最新的意思,我们分别使用这俩值对比下执行结果
同样可以让程序完成执行,并且使用DROP_OLDEST
的时候,是将老数据丢弃,留下最新数据也就是message5,而使用DROP_LATEST
的时候,留下的就是最老数据,也就是message1,这个时候可能有人要问了,别丢啊,这些数据我还有用呢,那么这里就要用到Channel
第三个参数onUndeliveredElement
,这是一个函数类型的参数,有个回调参数E,这个就是被丢弃的那些数据,我们以DROP_OLDEST
为例看下
这里要注意的是,想要获取被丢弃的数据,我们的capacity
的值必须是大于0,不然将会拿不到被丢弃的数据,这段代码运行后得到的结果如下
可以看到除了最新数据被接收到之外,其余数据都在onUndeliveredElement
函数内被获取到了
总结
八股文这种东西,看起来貌似都没啥用,有一些在我们开发当中甚至都碰不到,但是这种东西,多准备一些,多掌握一些,可能就可以帮助你在面试当中脱颖而出,给面试官留下更深的印象,我就遇到过一次,上午看了一题,然后下午的面试就问到了,这个题目我要是不看,那么面试中就回答不出来,面试通过的概率小了,所以还是静下心来,多看点多背点多写点吧