《2022年 Android 中高级面试题汇总》及答案整理(备战金九银十)

面试题分享

Android进程间通信的实现方式

Binder
Socket
文件共享(如sharedPreference)
intent
contentProvider
AIDL
广播
服务

自定义view流程

继承view或groupView或已有原生控件
如有需要自定义属性
在onmeasure中确定view的大小
在ondraw中画出内容
如有需要暴露设置属性的方法

ANR是什么,怎么避免

ANR即Application not responsing,应用无响应
在Android系统中,activity5秒内无响应则出现ANR,广播10秒,服务20秒
避免:将耗时的同步操作放到子线程执行(网络请求,文件读写,海量数据处理等)

消息机制

消息机制中有四个关键类,Handler、Message、Looper、MessageQueue

Handler是用来辅助消息发送和处理的类,可通过复写handleMessage来处理 Message,通过post或postDelay来发送消息
Message是消息的载体,what属性是消息的标识,用int值来标记不同的消息类型,obj为消息中包含的信息,一般用于存放处理消息是要用到的数据;还有一些数组和数值的属性是一些便捷的存放数据的属性
MessageQueue是消息的队列,名字虽然是队列,但是MessageQueue是用单链表实现的,因为单链表在插入和删除上表现较好;MessageQueue使用先进先出的原则,按序取出消息
Looper是一个不断轮询MessageQueue的类,会不断取出MessageQueue中的消息;每一个线程中只能有一个Looper;主线程的Looper在线程创建的时候就自动创建并开始轮询了

Looper的存放使用ThreadLocal实现,ThreadLocal用于创建一个线程的共享变量,当在一个已有Looper的线程中再次创建Looper,会拿到相同的Looper

性能优化

布局优化:尽量将减少布局的层级,很少情况下使用的布局可以使用stub标签,使用include标签减少重复布局的编写
绘制优化:自定义控件中的ondraw方法尽量不要做耗时操作和尽量少的初始化操作,保证绘制的流畅性
线程优化:多线程开发时多使用线程池对线程进行管理,更好地复用线程以及对最大并发进行控制
内存泄漏优化:handler、AsynTask、静态变量、广播、contentReceiver等的使用注意处理潜在的内存泄漏问题

广播注册的方式与区别

静态注册:在清单文件中声明广播,这种广播是常驻型广播,长期占用内存,占用CPU资源,但这种广播可以在app不运行的时候监听,例如开机广播
动态注册:在Application或其他组件中用代码动态声明的广播,非常驻型广播,广播的生命周期和组件绑定,但要在onDestroy的时候注销广播,否则容易造成内存泄漏

进程保活,避免service死亡

进程保活:可以使用AlarmManager或WorkManager定时启动activity,当进程死亡后拉起;使用前台服务来提高进程的优先级,提高进程的存活率
service保活:设置为前台服务提高优先级;在进程中轮询service是否死亡,死亡则重新启动;在onStartCommand中返回STICKY,当service被杀死后,系统会尽量复活粘性服务;onDestroy时发送一个自定义广播,收到广播重启service

怎么避免OOM,加载图片OOM

出现OOM一个很大的原因是因为内存泄漏,久而久之内存就会被占满从而出现OOM,代码中处理好ML的问题可以减少OOM出现的概率;避免一次性声明大量的对象或使用轻量级的对象;按需使用弱引用,使得发送GC的时候能够释放更多的内存
OOM还会出现在加载比较大图片的情况下,比如加载多张大图片到UI中,不进行处理的话,图片就会直接加载到内存中,容易发生OOM,解决方法是加载图片之前,先对图片的大小进行估计,从而判断是否需要进行图片压缩,而且不在使用中的图片可以考虑释放内存,需要用的时候重新加载

GC

Java有自动回收机制,即GC(Garbage Collection),当jvm判断一个对象已经“无用”了,就会释放其内存;是否“无用”jvm依靠一种引用链的机制判断(弱引用除外,弱引用无论如何都会被回收)

只要这个对象在GC Root的引用链中的话,这个对象就是“有用”,反之为“无用”

GC Root有如下: 正在运行的线程、静态变量、native中调用的方法、栈帧中的局部变量等

8ML的发生就是一个对象其实已经是无用的了,但是缺由于某种原因还存在于GC Root的引用链中,jvm判断为“有用”,这时候就不会回收该对象从而发生内存泄漏

Fragment与Fragment、Activity之间的通信

Fragment:Fragment之间是不能直接通信的,需要通过宿主Activity为桥梁通信
Activity:Activity可以在添加Fragment的时候使用Bundle给Fragment传递数据;可以使用FragmentManager的方法findFragmentById和findFragmentByTag来得到Fragment实例来传递数据
Fragment可以通过在onAttach回调中获取实现了自定义接口的Activity对象从而调用接口的方法进行向Activity传输数据;也可以使用getActivity获取宿主Activity的实例;共用viewmodel也可以实现通信。

RecyclerView和ListView的区别

RecyclerView可以实现ListView的显示效果,同时也可以实现瀑布流的效果;也可以设置滚动的方向
RecyclerView的item复用不用手动实现,已经封装好了(viewHolder) RecyclerView可以实现局部刷新
需要使用动画的情况下,RecyclerView的性能比ListView好,而且RecyclerView提供了使用动画的API
单纯显示列表数据两者区别不大

Glide框架的优缺点

优点:加载的生命周期与activity的生命周期绑定、储存的图片内存占用较小、多媒体缓存、可以设置优先级加载、支持okhttp和volley获取网络图片

缺点:因为格式的问题,显示的图片清晰度不足,但可以设置不同的格式

常见网络请求框架的比较

volley: google公司推出的一款轻量级的异步网络请求框架

优点是封装性好,使用门槛低,框架小,封装了ImageLoader
缺点是不能用于上传大数据

okhttp:

优点是性能好、封装好了同步异步、线程池、错误处理等,API使用起来很方便
缺点是实际使用的时候一般需要再封装一层以提高便捷性

retrofit: 基于okhttp的网络请求框架

对okhttp的进一步封装使得有更强的易用性,比如使用大量注解以减少代码量等,跟Rxjava有很好的融合性,同时也继承了okhttp的高性能
缺点是使用门槛较高

设计模式

单例模式:

单例模式是指某个对象在全局只存在唯一的一个实例,这样的设计模式能避免一些内存占用较大的对象被频繁创建,能在全局中提供一个唯一的实例(多用于管理类)
做法是将类构造方法私有化,然后在类中声明一个该类的对象并向外提供获取该对象的方法(一般是getInstance),该方法被调用时,先判断内部类对象是否为空,为空则创建一个实例赋值给该对象并返回,不为空则直接返回该对象
单例模式的实现方法有:枚举实现,单锁式,双锁式,加载初始式、静态内部对象式

建造者模式:

建造者模式能够将构建具有复杂属性的对象的过程变成链式调用,使得构建对象更加清晰明了
做法是在对象中定义一个静态内部类Builder,定义一套跟外部类属性完全相同的属性,并定义一系列的设置方法,方法的返回都是this(实现链式调用)
最后定义一个build方法,用Builder中的属性构建外部对象并返回

观察者模式:

观察者模式旨在响应,即被观察者发生变化是会即时通知观察者(可以是多个观察者)

策略模式:

策略模式强调多个具有相同功能但实现不同的逻辑应该讲功能抽象成接口
例如同一个功能支付,却有支付宝、微信、银联卡等不同的具体实现逻辑,这时候应该讲支付功能抽象成一个接口,不同的支付方式实现这个接口并定义具体的支付逻辑
好处是方便对不同实现逻辑的增删改,面对接口编程,对修改关闭,对拓展开放
但只适用于程序掌握全部所有的逻辑的情况下

工厂模式:

工厂模式是一种创建对象的设计模式,该设计模式识具体的构建逻辑不会暴露,相当于你需要一台汽车,你去工厂提车但并不需要知道这汽车是怎么造出来的
做法是定义一个接口对象(比如车),实现多个子类,子类里是具体的构建方法(红色的车、柴油车、汽油车等的具体生产的方法),接着创建一个能根据具体需要创建对象的工厂类(汽车厂),使用工厂(向工厂提要求,比如我要一台汽油车),工厂根据要求选择相应的子类(汽油车的生产方法),构建一个接口对象返回(工厂交付一台车)

由于文章的篇幅原因,面试题的分享就到这里

其实最重要的就是一句话,问问你自己:

你现在所拥有的技术层次真的有信心步入更高阶的程序员当中吗?

近段时间我这里整理了一份完整的《2022年 Android 中高级面试题汇总》; 这份资料包含了Java和Android两大部分,由于篇幅原因,这里只展示部分知识点, 希望这份系统化的技术体系对大家有一个方向参考

有需要的朋友可以点击文末小卡片

完整目录如下:

《2022年 Android 中高级面试题汇总》

由于篇幅有限,仅展示部分内容

第一章 Java 基础

第一节 静态内部类和非静态内部类的比较

1.1 静态内部类和非静态内部类的区别

1.2 扩展:内部类都有哪些?

1.3 同部内部类

1.4 匿名内部类:是一种没有炎名的内部类

第二节 多态的理解与应用

2.1 多态概述

2.2 多态中成员的持点

2.3 instanceof关桩字

2.4 多态的转型

2.5 多态案例

第三节 java 方法的多态性理解

3.1 什么是java的多态

3.2 远行时多态3.3代码理解

3.4 深一点

3.5 再深一点

3.6 最后一个炼习

第四节 java中接口和选承的区别

第五节 线程池的好处,详解,单例(绝对好记)

5.1 线程池的好处

5.2 线程池的详解

5.3 线程池的单例

第二章 Android 基础

第一节 Activity 知识点(必问)

1.1 Activity 启动过程全解析

1.2 启动模式以及使用场景

1.3 onSavelnstanceStatelJBonRestorelnstar

1.4onConfigurationChanged使用以及问题解决

第二节 Fragment 知识点

2.1 Fragment的通信问题,新建Fragment为何不

2.2 为什么官方推荐Fragment.setArguments(B

2.3 Androidx下Fragment懒加载的新实现

2.4 Fragment全解析系列(一):那些年深过的

2.5 Google-Fragment 概览

2.6 Google -与其他 Fragment 通信

第三节 Service 知识点

3.1 Handle 知识点(必问)

3.2 Android 主线程阻塞处理及优化

3.3深入聊聊Android消息机制中的消息队列的

3.4深入理解MessageQueue

3.5 你真的懂Handler.postDelayed(的原理吗?

3.6 Handler.postDelayed0是如何精确延迟指成

3.7 Handler 延迟消息执行机制,会阻塞吗?

第四节Intent知识点

4.1 Android 跨进程传递大内存数据

4.2 数据存健

最后我想说:

技术是无止境的,你需要对自己提交的每一行代码、使用的每一个工具负责,不断挖掘其底层原理,才能使自己的技术升华到更高的层面

Android 架构师之路还很漫长,与君共勉

猜你喜欢

转载自blog.csdn.net/m0_70748845/article/details/125647560