2024年春招Android面试指南:1000+道真题及答案详解

前言

这些面试题集结了我们在微信群与新入职小伙伴们的深入讨论。在交流中,我们听到了许多关于面试经历的分享,也感受到了大家对于技术面试的困惑与挫败。起初,许多人都认为技术能力是首要的,而忽视了对面试题的准备。但在实际的面试过程中,面对突如其来的问题,他们往往会感到无所适从。

为了解决这个问题,我们决定采取行动。我们开始整理各种面试题,不仅来自网络,也来自我们自己的经验和学习。我们希望通过这种方式,为后来的求职者提供一个全面的面试题库,帮助他们更好地准备,避免走弯路。

在这里插入图片描述

好了话不多说开始查漏补缺:

首先,Java方面的话一定要全面,各种数据结构,语言特性,并发操作都要熟悉,而且不仅要会用,还要看看关键源码理解原理。JVM也要理解,因为Android的虚拟机其实和JVM很相似,所以开发中很多技术比如热更新之类的都和JVM中的一些原理很相似。因为Java相关的面试问题实在太多太广了我就不一一写出来了。(完整文档扫描下方二维码免费领取!!!)

Android篇

一、Activity 与 Fragment 之间常见的几种通信方式?

viewModel 做数据管理,activity 和 fragment 公用同个viewModel 实现数据传递

二、BroadcastReceiver 与LocalBroadcastReceiver 有什么区别?
  • BroadcastReceiver 是跨应用广播,利用Binder机制实现,支持动态和静态两种方式注册方式。
  • LocalBroadcastReceiver 是应用内广播,利用Handler 实现,利用了IntentFilter的match功能,提供消息的发布与接收功能,实现应用内通信,效率和安全性比较高,仅支持动态注册。
三、子线程能否更新UI?为什么?

子线程是不能直接更新UI的
注意这句话,是不能直接更新,不是不能更新(极端情况下可更新)绘制过程要保持同步(否则页面不流畅),而我们的主线程负责绘制ui,极端情况就是,在Activity的onResume(含)之前的生命周期中子线程都可以进行更新ui,也就是onCreate,onStart和onResume,此时主线程的绘制还没开始。

四、 谈谈 Handler 机制和原理?

首先在UI线程我们创建了一个Handler实例对象,无论是匿名内部类还是自定义类生成的Handler实例对象,我们都需要对handleMessage方法进行重写,在handleMessage方法中我们可以通过参数msg来写接受消息过后UIi线程的逻辑处理,接着我们创建子线程,在子线程中需要更新UI的时候,新建一个Message对象,并且将消息的数据记录在这个消息对象Message的内部,比如arg1,arg2,obj等,然后通过前面的Handler实例对象调用sendMessge方法把这个Message实例对象发送出去,之后这个消息会被存放于MessageQueue中等待被处理,此时MessageQueue的管家Looper正在不停的把MessageQueue存在的消息取出来,通过回调dispatchMessage方法将消息传递给Handler的handleMessage方法,最终前面提到的消息会被Looper
从MessageQueue中取出来传递给handleMessage方法。

五、谈谈Android的事件分发机制?

当点击的时候,会先调用顶级viewgroup的dispatchTouchEvent,如果顶级的viewgroup拦截了此事件(onInterceptTouchEvent返回true),则此事件序列
由顶级viewgroup处理。如果顶级viewgroup设置setOnTouchListener,则会回调接口中的onTouch,此时顶级的viewgroup中的onTouchEvent不再回调,如果不设
置setOnTouchListener则onTouchEvent会回调。如果顶级viewgroup设置setOnClickListener,则会回调接口中的onClick。如果顶级viewgroup不拦截事件,事件就会向下传递给他的子view,然后子view就会调用它的dispatchTouchEvent方法。

Android Framework篇

一、你了解 Android 系统启动流程吗?

当按电源键触发开机,首先会从ROM中预定义的地方加载引导程序BootLoader 到 RAM中,并执行BootLoader程序启动Linux
Kernel,然后启动用户级别的第一个进程: init 进程。init
进程会解析init.rc脚本做一些初始化工作,包括挂载文件系统创建工作目录以及启动系统服务进程等,其中系统服务进程包括
Zygote、service manager、media 等。在 Zygote中会进一步去启动 system_ server进程,然后在
system_server 进程中会启动AMS、WMS、PMS等服务,等这些服务启动之后,AMS中就会打开Launcher应用的home
Activity,最终就看到了手机的“桌面”。

二、能具体说说是怎么导致的死锁的吗?

在POSIX 标准中,fork的行为是这样的:复制整个用户空间的数据(通常使用 copy-on-write
的策略,所以可以实现的速度快)以及所有系统对象,然后仅复制当前线程到子进程。这里:所有父进程中别的线程,到了子进程中都是突然蒸发掉的对于锁来说,从
OS 看,每个锁有一个所有者,即最后一次 lock 它的线程。假设这么一个环境,在 fork 之前,有一个子线程 lock
了某个锁,获得了对锁的所有权。fork
以后,在子进程中,所有的额外线程都人间蒸发了。而锁却被正常复制了,在子进程看来,这个锁没有主人,所以没有任何人可以对它解锁。 当子进程想
lock 这个锁时,不再有任何手段可以解开了。

三、Zygote 为什么不采用 Binder 机制进行 IPC 通信?

Binder机制中存在Binder线程池,是多线程的,如果Zygote采用Binder的话就存在上面说的fork()与多线程的问题了。其实严格来说,Binder机制不一定要多线程,所谓的Binder线程只不过是在循环读取Binder驱动的消息而已,只注册一个Binder线程也是可以工作的,比如service
manager
就是这样的。实际上Zygote尽管没有采取Binder机制,它也不是单线程的,但它在fork()前主动停止了其他线程,fork()后重新启动了。

四、Binder是如何做到一次拷贝的

主要是因为Linux是使用的虚拟内存寻址方式,它有如下特性:

  • 用户空间的虚拟内存地址是映射到物理内存中的。
  • 对虚拟内存的读写实际上是对物理内存的读写,这个过程就是内存映射。
  • 这个内存映射过程是通过系统调用mmap()来实现的。
  • Binder借助了内存映射的方法,在内核空间的接收方用户控件的数据缓存区之间做了一层内存映射,就相当于直接拷贝到了接收方用户空间的数据缓存区,从而减少了一次数据拷贝。
五、Binder机制是如何跨进程的
  1. Binder驱动
  • 在内核空间创建一块接收缓存区,
  • 实现地址映射:将内核缓存区、接收进程用户空间映射到同一接收缓存区
  1. 发送进程通过系统调用 (copy_from_user) 将数据发送到内核缓存区。由于内核缓存区和 接收进程用户空间存在映射关系,故相当于也发送了接收进程的用户空间,实现了跨进程通信

Flutter篇

一、Flutter 中的生命周期

initState()表示当前 State 将和一个 BuildContext 产生关联,但是此时BuildContext
没有完全装载完成,如果你需要在该方法中获取 BuildContext ,可以 new Future.delayed(const
Duration(seconds: 0, (){//context}); 一下。

didChangeDependencies()在 initState()之后调用,当 State
对象的依赖关系发生变化时,该方法被调用,初始化时也会调用。deactivate()当 State
被暂时从视图树中移除时,会调用这个方法,同时页面切换时,也会调用。dispose() Widget 销毁了,在调用这个方法之前,总会先调用
deactivate()。didUpdateWidge 当 widget 状态发生变化时,会调用。

通过 StreamBuilder 和 FutureBuilder 我们可以快速使用 Stream 和 Future
快速构建我们的异步控件,Flutter 中 runApp 启动入口其实是一个 WidgetsFlutterBinding
,它主要是通过BindingBase 的子类 GestureBinding 、ServicesBinding
、SchedulerBinding 、PaintingBinding 、SemanticsBinding 、 RendererBinding
、WidgetsBinding 等,通过 mixins 的组合而成的。 Flutter 中的 Dart
的线程是以事件循环和消息队列的形式存在,包含两个任务队列,一个是 microtask 内部队列,一个是event 外部队列,而
microtask 的优先级又高于event。因为 microtask 的优先级又高于 event,同时会阻塞event
队列,所以如果microtask 太多就可能会对触摸、绘制等外部事件造成阻塞卡顿哦。

Flutter 中存在四大线程,分别为 UI Runner、GPU Runner、IO Runner, Platform Runner
(原生主线程),同时在 Flutter 中可以通过 isolate 或者compute 执行真正的跨线程异步操作。

二、Widget 和 element 和 RenderObject 之间的关系?
  • Widget是用户界面的一部分,并且是不可变的。
  • Element是在树中特定位置Widget的实例。
  • RenderObject是渲染树中的一个对象,它的层次结构是渲染库的核心。

Widget会被inflate(填充)到Element,并由Element管理底层渲染树。Widget并不会直接管理状态及渲染,
而是通过State这个对象来管理状态。Flutter创建Element的可见树,相对于Widget来说,是可变的,通常界面开发中,我们不用直接操作Element,而是由框架层实现内部逻辑。就如一个UI视图树中,可能包含有多个TextWidget(Widget被使用多次),但是放在内部视图树的视角,这些TextWidget都是填充到一个个独立的Element中。Element会持有renderObject和widget的实例。记住,Widget
只是一个配置,RenderObject 负责管理布局、绘制等操作。

在第一次创建 Widget 的时候,会对应创建一个 Element,然后将该元素插入树中。如果之后 Widget 发生了变化,则将其与旧的
Widget 进行比较,并且相应地更新 Element。重要的是,Element 不会被重建,只是更新而已。

三、mixin extends implement 之间的关系?

继承(关键字 extends)、混入 mixins (关键字 with)、接口实现(关键字
implements)。这三者可以同时存在,前后顺序是extends -> mixins -> implements。
Flutter中的继承是单继承,子类重写超类的方法要用@Override,子类调用超类的方法要用super。
在Flutter中,Mixins是一种在多个类层次结构中复用类代码的方法。mixins的对象是类,mixins绝不是继承,也不是接口,而是一种全新的特性,可以mixins多个类,mixins的使用需要满足一定条件

由于文章篇幅有限,不能将我整理的所有面试题全部展示出来,不过也没关系,我已经将所有的面试题整理成PDF文档了,有需要完整面试题和答案解析的朋友可以扫码免费领取!👇👇👇
  • 26
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值