精选100道2024Android面试题,助你金三银四,踏入理想职位

前言

今年的金三银四已经来了,在我身边有不少人在质疑这是“金三银四”吗?这明明是“铜三铁四”!!!

不过小编想说的是这重要吗?环境只是一个因素,它确实会影响大家找工作或者跳槽涨薪,但是影响不多,最重要的一个因素在于自己是否已经做好了准备。

在这里插入图片描述

我呢为大家准备了百道Android面试题,为大家保驾护航,后续也会持续更新

废话不多说,直接上干货!!!!

一、Java 中深拷贝与浅拷贝的区别?

1、浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,此为浅拷贝。
2、深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,此为深拷贝。

二、谈谈Error和Exception的区别?

1、Exception是java程序运行中可预料的异常情况,咱们可以获取到这种异常,并且对这种异常进行业务外的处理。
2、Error是java程序运行中不可预料的异常情况,这种异常发生以后,会直接导致JVM不可处理或者不可恢复的情况。所以这
种异常不可能抓取到,比如OutOfMemoryError、NoClassDefFoundError等。

三、什么是反射机制?反射机制的应用场景有哪些?

Java
反射机制是在运行状态中,对于任意一个类,都能够知道这个类中的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为
Java 语言的反射机制。 应用场景:1. 逆向代码,例如反编译2. 与注解相结合的框架,如 Retrofit3.
单纯的反射机制应用框架,例如 EventBus(事件总线)4. 动态生成类框架 例如Gson

四、谈一谈startService和bindService的区别,生命周期以及使用场景?

  1. 生命周期上的区别 执行startService时,Service会经历onCreate- >onStartCommand。当执行stopService时,直接调用onDestroy方法。调用者如果没有stopService,Service
    会一直在后台运行,下次调用者再起来仍然可以stopService。执行bindService时,Service会经历onCreate-

onBind。这个时候调用者和Service绑定在一起。调用者调用unbindService方法或者调用者Context不存在了(如Activity被finish了),Service就会调用onUnbind-
onDestroy。这里所谓的绑定在一起就是说两者共存亡了。多次调用startService,该Service只能被创建一次,即该Service的onCreate方法只会被调用一次。但是每次调用startService,onStartCommand方法都会被调用。Service的onStart方法在API
5时被废弃,替代它的是onStartCommand方法。第一次执行bindService时,onCreate和onBind方法会被调用,但是多次执行bindService时,onCreate和onBind
方法并不会被多次调用,即并不会多次创建服务和绑定服务。

  1. 调用者如何获取绑定后的Service的方法 onBind回调方法将返回给客户端一个IBinder接口实例,IBinder允许客户端回调服务的方法,比如得到Service运行的状态或其他操作。我们需要IBinder对象返回具体的Service对象才能操作,所以说具体的Service对象必须首先实现Binder对象。
  2. 既使用startService又使用bindService的情况 如果一个Service又被启动又被绑定,则该Service会一直在后台运行。首先不管如何调用,onCreate始终只会调用一次。对应startService调用多少次,Service的onStart
    方法便会调用多少次。Service的终止,需要unbindService和stopService同时调用才行。不管startService与bindService的调用顺序,如果先调用unbindService,此时服务不会自动终止,再调用stopService之后,服务才会终止;如果先调用stopService,此时服务也不会终止,而再调用unbindService或者之前调用bindService的Context不存在了(如Activity被finish的时候)之后,服务才会自动停止。
    那么,什么情况下既使用startService,又使用bindService呢?
    如果你只是想要启动一个后台服务长期进行某项任务,那么使用startService便可以了。如果你还想要与正在运行的Service取得联系,那么有两种方法:一种是使用broadcast,另一种是使用bindService。前者的缺点是如果交流较为频繁,容易造成性能上的问题,而后者则没有这些问题。因此,这种情况就需要startService和bindService一起使用了。
    另外,如果你的服务只是公开一个远程接口,供连接上的客户端(Android的Service是C/S架构)远程调用执行方法,这个时候你可以不让服务一开始就运行,而只是bindService,这样在第一次bindService的时候才会创建服务的实例运行它,这会节约很多系统资源,特别是如果你的服务是远程服务,那么效果会越明显(当然在Servcie创建的是偶会花去一定时间,这点需要注意)。
  3. 本地服务与远程服务 本地服务依附在主进程上,在一定程度上节约了资源。本地服务因为是在同一进程,因此不需要IPC,也不需要AIDL。相应
    bindService会方便很多。缺点是主进程被kill后,服务变会终止。远程服务是独立的进程,对应进程名格式为所在包名加上你指定的android:process字符串。由于是独立的进程,因此在Activity所在进程被kill的是偶,该服务依然在运行。缺点是该服务是独立的进程,会占用一定资源,并且使用AIDL进行IPC稍微麻烦一点。对于startService来说,不管是本地服务还是远程服务,我们需要做的工作都一样简单。

五、谈谈你对 Activity.runOnUiThread 的理解?

一般是用来将一个runnable绑定到主线程,在runOnUiThread源码里面会判断当前runnable是否是主线程,如果是直接run,如果不是,通过一个默认的空构造函数handler将runnable
post 到looper里面,创建构造函数handler,会默认绑定一个主线程的looper对象

六、子线程能否更新UI?为什么?

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

七、你了解 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,最终就看到了手机的“桌面”。

八、Binder有什么优势

性能方面
  • 共享内存 0次数据拷贝
  • Binder 1次数据拷贝
  • Socket/管道/消息队列 2次数据拷贝
稳定性方面
  • Binder:基于C/S架构,客户端 (Client) 有什么需求就丢给服务端 (Server) 去完成,架构清晰、职责明确又相互独立,自然稳定性更好
  • 共享内存:虽然无需拷贝,但是控制复杂,难以使用
  • 从稳定性的角度讲,Binder机制是优于内存共享的。
安全性方面
  • 传统的IPC没有任何安全措施,安全依赖上层协议来确保。
  • 传统的IPC方法无法获得对方可靠的进程用户ID/进程UI (UID/PID) ,从而无法鉴别对方身份。
  • 传统的IPC只能由用户在数据包中填入UID/PID,容易被恶意程序利用。
  • 传统的IPC访问接入点是开放的,无法阻止恶意程序通过猜测接收方地址获得连接。
  • Binder既支持实名Binder,又支持匿名Binder,安全性高。

九、Binder机制是如何跨进程的

  1. Binder驱动
  • 在内核空间创建一块接收缓存区,
  • 实现地址映射:将内核缓存区、接收进程用户空间映射到同一接收缓存区
  1. 发送进程通过系统调用 (copy_from_user) 将数据发送到内核缓存区。由于内核缓存区和 接收进程用户空间存在映射关系,故相当于也发送了接收进程的用户空间,实现了跨进程通信

十、简述下Handler机制的总体原理

  1. Looper 准备和开启轮循: Looper#prepare()初始化线程独有的 Looper 以及 MessageQueue Looper#loop()开启死循环读取 MessageQueue 中下一个满足执行时间的 Message 尚无 Message 的话,调用Native 侧的 pollOnce()进入无限等待存在 Message,但执行时间 when 尚未满足的话,调用 pollOnce()时传入剩余时长参数进入有限等待
  2. Message 发送、入队和出队: Native 侧如果处于无限等待的话:任意线程向 Handler 发送 Message 或 Runnable 后,Message 将按照 when 条件的先后,被插 入 Handler 持有的 Looper 实例所对应的 MessageQueue 中适当的位置。 MessageQueue 发现有合适的 Message 插入后将调用 Native 侧的 wake() 唤醒无限等待的线程。这将促使 MessageQueue 的读取继续进入下一次循环,此刻 Queue 中已有满足条件的 Message 则 出队返回给 Looper Native 侧如果处于有限等待的话:在等待指定时长后 epoll_wait 将返回。线程继续读取 MessageQueue, 此 刻因为时长条件将满足将其出队 Looper 处理Message 的实现:
  3. Looper 得到 Message 后回调 Message 的 callback 属性即 Runnable,或依据 target 属性即 Handler,去执行 Handler 的回调。存在 mCallback属性的话回调 Handler$Callback 反之,回调handleMessage()

十一、你了解 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,最终就看到了手机的“桌面”。

十二、system_server 为什么要在 Zygote 中启动,而不是由 init 直接启动呢?

Zygote 作为一个孵化器,可以提前加载一些资源,这样 fork()时基于 Copy-On-Write机制创建的其他进程就能直接使用这些资源,而不用重新加载。 比如 system_server 就可以直接使用 Zygote 中的 JNI函数、共享库、常用的类、以及主题资源。

十三、为什么要专门使用 Zygote 进程去孵化应用进程,而不是让system_server去孵化呢?

首先 system_server 相比 Zygote 多运行了 AMS、 WMS等服务,这些对一个应用程序来说是不需要的。另外进程的fork()对多线程不友好,仅会将发起调用的线程拷贝到子进程,这可能会导致死锁,而system_server中肯定是有很多线程的。

十四、ActivityThread是什么?ApplicationThread是什么?他们的区别

1、ActivityThread 在 Android中它就代表了Android的主线程,它是创建完新进程之后,main函数被加载,然后执行一个loop的循环使当前线程进入消息循环,并且作为主线程。
2、ApplicationThread ApplicationThread是ActivityThread的内部类,是一个Binder对象。在此处它是作为IApplicationThread对象的server端等待client端的请求然后进行处理,最大的client就是AMS。

十五、 Instrumentation是什么?和ActivityThread是什么关系?

AMS与ActivityThread之间诸如Activity的创建、暂停等的交互工作实际上是由Instrumentation具体操作的。每个Activity都持有一个Instrumentation对象的一个引用,整个进程中是只有一个Instrumentation。mInstrumentation的初始化在ActivityThread::handleBindApplication函数。可以用来独立地控制某个组件的生命周期。ActivitystartActivity方法。 startActivity会调用mInstrumentation .execStartActivity();
mInstrumentation 掉用 AMS, AMS 通过 socket 通信告知

十六、 Dart 多任务如何并行的?

刚才也说了,既然 Dart 不存在多线程,那如何进行多任务并行? Dart 当中提供了一个 类似于新线程,但是不共享内存的独立运行的worker - isolate。
那他们是如何交互的? 在dart中,一个Isolate对象其实就是一个isolate执行环境的引用,一般来说我们都是通过当前的isolate去控制其他的isolate完成彼此之间的交互,而当我们想要创建一个新的Isolate可以使用Isolate.spawn方法获取返回的一个新的isolate对象,两个isolate之间使用SendPort相互发送消息,而isolate中也存在了一个与之对应的ReceivePort接受消息用来处理,但是我们需要注意的是,ReceivePort和SendPort在每个isolate都有一对,只有同一个isolate中的ReceivePort才能接受到当前类的SendPort发送的消息并且处理。

十七、mixin extends implement 之间的关系?

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

十八、 使用mixins的条件是什么?

因为mixins使用的条件,随着Dart版本一直在变,这里讲的是Dart2.1中使用mixins的条件:

  • mixins类只能继承自object
  • mixins类不能有构造函数
  • 一个类可以mixins多个mixins类
  • 可以mixins多个类,不破坏Flutter的单继承

最后

面试题的目的不是为了让大家背题,而是从不同维度帮助大家复习,取长补短。最主要的还是增长自身实力,自己实力上去了,不管面试在怎么问,也还是难不住你。

由于文章篇幅有限,不能将全部的面试题+答案解析展示出来,有需要完整面试题可以在图片下方扫码领取

在这里插入图片描述

  • 19
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值