史上最全的2022年最新版Android安卓面试题集锦(含答案+源码)

史上最全的2022年最新版Android安卓面试题集锦(含答案+源码)金三银四 又到了一年一度的黄金跳槽季 想必也许有不少 Android 程序员开始摩拳擦掌 蠢蠢欲动了 而网络上的面试题大部分已经过时甚至是错误成堆 漏洞百出 今天结合自己这段时间的面试经验和几个 Android 技术群里面大厂大牛的交流总结出了这篇 2022 年最新的 Android 面试题合集

在这里插入图片描述
金三银四,又到了一年一度的黄金跳槽季,想必也许有不少Android程序员开始摩拳擦掌,蠢蠢欲动了。而网络上的面试题大部分已经过时甚至是错误成堆,漏洞百出,今天结合自己这段时间的面试经验和几个Android技术群里面大厂大牛的交流总结出了这篇2022年最新的Android面试题合集。那么,废话不多说,让我们马上进入正题。

前言

首先要声明的是:面试题的目的不是为了让大家背题,而是从不同维度帮助大家复习,取长补短。让我们正式进入正题:

面试题汇总

1.Android四大组件:Activity、Service、BroadcastReceiver、ContentProvider。它们的作用分别是:

2.Activity 有几种 launch mode?每一种有什么特点?

3.Service 有几种类型?各有什么应用场景?

方法 启动方式 停止方式 与启动的组件通信方法 生命周期
startService 在其他组件中调用startService()方法后,服务即处于启动状态 service中调用stopSelf()方法,或者其他组件调用stopService()方法后,service将停止运行 没有提供默认的通信方式,启动service后该service就处于独立运行状态 一旦启动,service即可在后台无限期运行,即使启动service的组件已被销毁也不受其影响,直到其被停止
bindService 在其他组件中调用bindService()方法后,服务即处于启动状态 所有与service绑定的组件都被销毁,或者它们都调用了unbindService()方法后,service将停止运行 可以通过 ServiceConnection进行通信,组件可以与service进行交互、发送请求、获取结果,甚至是利用IPC跨进程执行这些操作 当所有与其绑定的组件都取消绑定(可能是组件被销毁也有可能是其调用了unbindService()方法)后,service将停止

4.LaunchMode 的应用场景?

LaunchMode 有四种,分别为 Standard,SingleTop,SingleTask 和 SingleInstance,每种模式的实现原理一楼都做了较详细说明,下面说一下具体使用场景:

  • Standard:
    Standard 模式是系统默认的启动模式,一般我们 app中大部分页面都是由该模式的页面构成的,比较常见的场景是:社交应用中,点击查看用户A信息->查看用户A粉丝->在粉丝中挑选查看用户B信息->查看用户A粉丝…这种情况下一般我们需要保留用户操作 Activity 栈的页面所有执行顺序。

  • SingleTop:
    SingleTop 模式一般常见于社交应用中的通知栏行为功能,例如:App 用户收到几条好友请求的推送消息,需要用户点击推送通知进入到请求者个人信息页,将信息页设置为 SingleTop 模式就可以增强复用性。

  • SingleTask:
    SingleTask 模式一般用作应用的首页,例如浏览器主页,用户可能从多个应用启动浏览器,但主界面仅仅启动一次,其余情况都会走onNewIntent,并且会清空主界面上面的其他页面。

  • SingleInstance:
    SingleInstance 模式常应用于独立栈操作的应用,如闹钟的提醒页面,当你在A应用中看视频时,闹钟响了,你点击闹钟提醒通知后进入提醒详情页面,然后点击返回就再次回到A的视频页面,这样就不会过多干扰到用户先前的操作了。

5.后台和前台Service

startForegroundService(intent); public void onCreate() { super.onCreate(); Notification notification = new Notification.Builder(this) .setChannelId(CHANNEL_ID) .setContentTitle("主服务")//标题 .setContentText("运行中...")//内容 .setSmallIcon(R.mipmap.ic_launcher) .build(); startForeground(1,notification); } 
   
   
  • 首先,创建一个JobService:
public class MyJobService extends JobService { @Override public boolean onStartJob(JobParameters params) { return false; } @Override public boolean onStopJob(JobParameters params) { return false; } } 
  • 然后,注册这个服务(因为JobService也是Service)
 
   
  • 最后,创建一个JobInfo并执行
JobScheduler scheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE); ComponentName jobService = new ComponentName(this, MyJobService.class); JobInfo jobInfo = new JobInfo.Builder(ID, jobService) .setMinimumLatency(5000)// 任务最少延迟时间 .setOverrideDeadline(60000)// 任务deadline,当到期没达到指定条件也会开始执行 .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)// 网络条件,默认值NETWORK_TYPE_NONE .setRequiresCharging(true)// 是否充电 .setRequiresDeviceIdle(false)// 设备是否空闲 .setPersisted(true) //设备重启后是否继续执行 .setBackoffCriteria(3000,JobInfo.BACKOFF_POLICY_LINEAR) //设置退避/重试策略 .build(); scheduler.schedule(jobInfo); 

简单说下原理:

WorkManager 是一个 API,可供您轻松调度那些即使在退出应用或重启设备后仍应运行的可延期异步任务。

8.谈一谈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对象。

  1. 既使用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创建的是偶会花去一定时间,这点需要注意)。

  1. 本地服务与远程服务

本地服务依附在主进程上,在一定程度上节约了资源。本地服务因为是在同一进程,因此不需要IPC,也不需要AIDL。相应bindService会方便很多。缺点是主进程被kill后,服务变会终止。

远程服务是独立的进程,对应进程名格式为所在包名加上你指定的android:process字符串。由于是独立的进程,因此在Activity所在进程被kill的是偶,该服务依然在运行。缺点是该服务是独立的进程,会占用一定资源,并且使用AIDL进行IPC稍微麻烦一点。

对于startService来说,不管是本地服务还是远程服务,我们需要做的工作都一样简单。

9.Service如何进行保活?

10.线程更新UI导致崩溃的原因?
在触发绘制方法requestLayout中,有个checkThread方法:

void checkThread() { if (mThread != Thread.currentThread()) { throw new CalledFromWrongThreadException( "Only the original thread that created a view hierarchy can touch its views."); } } 

其中对mThread和当前线程进行了比较。而mThread是在ViewRootImpl实例化的时候赋值的。

所以崩溃的原因就是 view被绘制到界面时候的线程(也就是ViewRootImpl被创建时候的线程)和进行UI更新时候的线程不是同一个线程。

11.Activity、Dialog、PopupWindow、Toast 与Window的关系
这是扩展的一题,简单的从创建方式的角度来说一说:

并不是,其实只要是调用了WindowManager的addView方法,那就是创建了Window,跟你有没有创建PhoneWindow无关。View就是Window的表现形式,只不过PhoneWindow的存在让Window形象更立体了一些。

所以PopupWindow也是通过Window展示出来的,而它的Window层级属于子Window,必须依附与应用窗口。

不同的是,Activity和Dialog涉及到了布局比较复杂,还会有布局主题等元素,所以用到了PhoneWindow进行一个解耦,帮助他们管理View。而PopupWindow和Toast结构比较简单,所以直接新建一个类似DecorView的View,通过addView显示到界面。

12.Kotlin 中的扩展函数是什么

kotlin中的扩展函数,实际上是在自己的类中添加了一个static final方法,将需要扩展的类,在使用的时候作为第一个参数传入方法中,然后使用:

fun String.hello(str: String): String{ return "hello" + str + this.length } fun String.hello1(str: String): String{ return "hello$str" } 

经过反编译之后生成字节码如下:

public final class ExtensionTestKt { @NotNull public static final String hello(@NotNull String $receiver, @NotNull String str) { Intrinsics.checkParameterIsNotNull($receiver, "$receiver"); Intrinsics.checkParameterIsNotNull(str, "str"); return "hello" + str + $receiver.length(); } @NotNull public static final String hello1(@NotNull String $receiver, @NotNull String str) { Intrinsics.checkParameterIsNotNull($receiver, "$receiver"); Intrinsics.checkParameterIsNotNull(str, "str"); return "hello" + str; } } 

kotlin中的扩展函数,实际上就是通过给类添加public static final函数的做法来实现,这样做可以减少utils类的使用。

扩展函数是静态解析的,是采用静态分派的过程来处理。这意味着调用的扩展函数是由函数调用所在的表达式的类型来决定的,而不是由表达式运行时求值结果决定的。这意思其实就是在使用该扩展函数的时候,如果类本身和其子类都进行了同一个函数的扩展,这函数是不会有重写关系的,在使用的时候,只会根据需要使用该方法的对象的实际类型来决定是调用了哪个,就是相当于调用静态方法。而不是动态分派。

总结

这次整理的这些每日一题都是一些编程题,其中有些还是我们日常开发中可能会遇到的问题,通过做这些题也可以检验一下自己对这些实用编程技巧的掌握程度。每日一题,每天成长一点点。

如果你觉得自己学习效率低,缺乏正确的指导,可以参考下下面分享我多年工作以来收集整理的学习路线,给大家做个参考:

  1. 确定好方向,梳理成长路线图

思维导图

知识梳理完之后,就需要进行查漏补缺。

  1. 看视频进行系统学习

因为我是转行进的移动开发行业,前几年的学习盲目啃书,结果面试时面试官一问,瞬间脑子空白,至此我才发现自己技术过于零散,对Android也不够深入、不够系统。当时就下定决心:重新进行一个系统的学习。我差的是系统知识,差的是结构框架和思路,于是我决定跟着一个老师的视频来进行系统的学习,效果更好,也更全面。关于视频学习,个人推荐可以去B站进行学习,B站上有很多学习视频,唯一的缺点就是由于是免费的,部分技术容易过时,而且部分涉及版权会被下架。

  1. 通过源码来系统性地学习

只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。

“编程语言是程序员的表达的方式,而架构是程序员对世界的认知”。所以,程序员要想快速认知并学习架构,读源码是必不可少的。阅读源码,是解决问题 + 理解事物,更重要的:看到源码背后的想法;程序员说:读万行源码,行万种实践。

真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。当然必不可少的还有自己手敲一遍,纸上得来终觉浅,绝知此事要躬行。

  1. 简历准备充分

可以去知乎上面搜搜别人写的有关简历的帖子,怎么准备,吸引hr, 突出自己的优点和能力,或者让朋友帮你看看简历有没有问题,比如过于简单或者浮夸,没有重点等。

尽量把你的亮点总结成一句简练的话,再加上数字来说明它的影响和意义。

其次在简历里中加入了可交互、可展示的内容,更能显出你的能力与众不同。

  1. 刷题备战,直通大厂

面试的前一周时间内,就可以开始刷题冲刺了。请记住,刷题的时候,技术的优先,算法的看些基本的,比如排序等即可,而智力题,除非是校招,否则一般不怎么会问。

最后需要的朋友可以添加下方的二维码回复JJ免费领取,我们承诺100%免费
史上最全的2022年最新版Android安卓面试题集锦(含答案+源码)]

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/210511.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 上午7:30
下一篇 2026年3月19日 上午7:31


相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号