2026年 Android基础面试题全面汇总(50题)

229 阅读22分钟

栏目录导航

[第 1 篇] Android基础面试题全面汇总(50题) 内容覆盖了 Java/Kotlin 基础Android 核心基础Flutter 基础网络/IM/音视频基础 以及 性能优化/工具基础

一、 Java & Kotlin 基础(10题)

1. Java 中 StringStringBuilderStringBuffer 的区别是什么?
  • 答案

    • String 是不可变类(final),每次修改都会生成新的 String 对象,频繁拼接效率低且消耗内存。

    • StringBuilder 是可变字符序列,非线程安全,性能最高,适用于单线程大量字符串拼接。

    • StringBuffer 同样是可变字符序列,内部方法使用了 synchronized 修饰,是线程安全的,但性能略低于 StringBuilder

2. Java 的强引用、软引用、弱引用和虚引用有什么区别?
  • 答案

    • 强引用 (StrongReference) :最常见的引用(如 Object obj = new Object())。只要强引用存在,GC 就绝不会回收该对象;当内存不足时宁可抛出 OOM。

    • 软引用 (SoftReference) :只有在系统内存不足(即将 OOM)时,GC 才会回收软引用对象。常用于缓存。

    • 弱引用 (WeakReference) :只要发生 GC,无论内存是否充足,弱引用对象都会被回收。常用于防止内存泄漏(如 Handler)。

    • 虚引用 (PhantomReference) :随时可能被回收,形同虚设,不能单独用来获取对象实例。必须配合 ReferenceQueue 使用,主要用来跟踪对象被垃圾回收的活动。

3. Java 集合框架中 HashMap 的底层实现原理及扩容机制是什么?
  • 答案

    • 底层实现:JDK 1.8 中为“数组 + 链表 + 红黑树”。当链表长度大于等于 8 且数组长度大于等于 64 时,链表会转为红黑树;当红黑树节点数降为 6 时又会退化为链表。

    • 扩容机制:默认初始容量为 16,加载因子为 0.75(即阈值 Threshold = 16 * 0.75 = 12)。当元素数量超过阈值时进行 2 倍扩容,扩容后需要重新计算元素下标(通过 hash & (newCap - 1) 快速定位)。

4. Kotlin 中 valvar 的区别?const valval 有什么区别?
  • 答案

    • val 定义只读变量(相当于 Java 中的 final 变量),仅能赋值一次;var 定义可变变量。

    • const val 声明编译期常量,必须在类顶层或 object/companion object 中声明,且只能是基本数据类型或 Stringval 是运行期只读属性,可以通过 getter 动态返回值。

5. Kotlin 的空安全机制是如何实现的??!!?: 各代表什么?
  • 答案

    • 空安全:Kotlin 在类型系统中区分了可空类型(如 String?)和不可空类型(如 String)。编译期会进行强类型检查,并在字节码级别插入 Intrinsics.checkNotNullParameter 方法校验。

    • 符号解释

      • ?:安全调用运算符,若对象为 null 则不执行后面的调用直接返回 null(如 str?.length)。

      • !!:非空断言运算符,强行将可空类型转成不可空类型,若对象为 null 则抛出 NullPointerException

      • ?::Elvis 运算符,若左侧表达式结果为 null,则返回右侧的值(如 str?.length ?: 0)。

6. Kotlin 中的 sealed class(密封类)有什么作用和特点?
  • 答案

    • 作用:表示一种受限的类继承结构,常用于定义 MVI/MVVM 架构中的 State 或 Intent。

    • 特点

      • 密封类的所有子类必须在编译期已知(同文件或同一包名下)。

      • 配合 when 表达式使用时,编译器能穷举所有子类分支,不需要写 else 分支。

      • 构造函数默认是 protectedprivate,无法在外部直接实例化。

7. 什么是 Kotlin 的扩展函数?它的底层实现原理是什么?
  • 答案

    • 定义:允许在不修改原类代码、不使用继承的情况下,为现有的类添加新的函数。

    • 底层原理:扩展函数本质上是静态方法(public static final),该方法的第一个参数就是被扩展的对象实例(即 this 接收者)。由于是静态解析,扩展函数不支持多态重写,其调用由编译期变量的静态类型决定。

8. Kotlin 中的 applyletrunalsowith 作用域函数有什么区别?
  • 答案

    • let:上下文对象是 it,返回值是 Lambda 表达式的最后一行。常用于空校验和链式调用。

    • apply:上下文对象是 this,返回值是 对象本身。常用于对象的初始化和属性配置。

    • run:上下文对象是 this,返回值是 Lambda 表达式的最后一行。

    • also:上下文对象是 it,返回值是 对象本身。常用于附加操作(如打印日志)。

    • with:非扩展函数,接受对象作为参数,上下文对象是 this,返回值是 Lambda 表达式的最后一行。

9. 什么是 Kotlin 协程?它和线程有什么区别?
  • 答案

    • 定义:协程可以看作是“轻量级的线程”,本质上是由用户态调度的并发编程框架,运行在 JVM 线程之上。

    • 区别

      • 线程是操作系统调度的 CPU 最小单位,切换成本高(需保存内核上下文);协程由用户态代码(协程调度器)控制,切换开销极小。

      • 协程通过“挂起(suspend)”与“恢复(resume)”机制实现非阻塞式异步编程,不会阻塞底层绑定的线程。

10. Java/Kotlin 中的线程同步机制有哪些?(从 synchronizedReentrantLock
  • 答案

    • synchronized:Java 内置关键字,基于 JVM Monitor(监视器)实现。支持偏向锁、轻量级锁、重量级锁的锁升级过程;支持自动加锁与解锁。

    • ReentrantLock:基于 AQS(AbstractQueuedSynchronizer)实现的重入锁,灵活性高于 synchronized。支持公平锁与非公平锁、可中断响应、超时获取锁以及配合 Condition 实现多路等待/通知机制。

    • Kotlin 中还可以使用并发包的 Atomic 原子类、协程中的 Mutex(互斥锁,挂起而非阻塞线程)以及 Channel/Flow 通信机制。

二、 Android 核心基础(15题)

11. 简述 Activity 的生命周期及异常重建流程。
  • 答案

    • 正常生命周期onCreate() -> onStart() -> onResume() -> [运行中] -> onPause() -> onStop() -> onDestroy()

    • 异常重建:当配置变更(如屏幕旋转)或系统内存不足导致 Activity 被杀时,系统会回调 onSaveInstanceState(Bundle) 保存数据。重新创建时,会依次执行 onCreate(Bundle)onRestoreInstanceState(Bundle),可以将 Bundle 中的状态恢复。

12. Fragment 的生命周期是怎样的?addreplace 有何区别?
  • 答案

    • 生命周期onAttach -> onCreate -> onCreateView -> onViewCreated -> onActivityCreated -> onStart -> onResume -> onPause -> onStop -> onDestroyView -> onDestroy -> onDetach

    • 区别

      • add():将 Fragment 叠加添加到容器中,原 Fragment 依然存活,UI 也处于可见/隐藏状态,生命周期不会销毁。

      • replace():先将容器中的现有 Fragment 全部移除(依次触发 onDestroyViewonDetach),再添加新的 Fragment。

13. Service 有哪两种启动方式?它们的生命周期和应用场景有什么不同?
  • 答案

    • startService()

      • 生命周期:onCreate() -> onStartCommand() -> [运行] -> onDestroy()

      • 特点:与调用者生命周期无解耦,调用者退出后 Service 依然后台运行。用于执行不需要交互的后台任务(如后台文件下载)。

    • bindService()

      • 生命周期:onCreate() -> onBind() -> [通信] -> onUnbind() -> onDestroy()

      • 特点:与调用者绑定,调用者退出时自动解绑,可获取 IBinder 进行跨进程/本地通信。

14. 简述 Android 事件分发机制的三大核心方法及分发顺序。
  • 答案

    • 三大核心方法

      1. dispatchTouchEvent(MotionEvent ev):负责事件的分发。

      2. onInterceptTouchEvent(MotionEvent ev):ViewGroup 独有,负责事件的拦截(返回 true 表示拦截)。

      3. onTouchEvent(MotionEvent ev):负责事件的处理(返回 true 表示消耗该事件)。

    • 分发顺序:Activity -> PhoneWindow -> DecorView -> ViewGroup -> View。下发时自上而下询问是否拦截,若无人拦截并到达最底层的 View 且 onTouchEvent 返回 false,则事件向上回溯冒泡交由上层 ViewGroup/Activity 处理。

15. 请详细解释 Android Handler 消息机制(Handler, Looper, MessageQueue, Message)。
  • 答案

    • Message:消息载体,内部持有 target(Handler 引用)和 callback

    • MessageQueue:消息队列,基于单链表结构按执行时间(when)排序存储 Message。

    • Looper:消息循环器,每个线程最多一个。通过 Looper.loop() 死循环调用 MessageQueue.next() 取出消息,并将 Message 交给其 target(Handler)的 dispatchMessage() 分发处理。

    • Handler:消息的发起者与处理者,负责通过 sendMessage() 将 Message 入队到 MessageQueue,并在 handleMessage() 中回调处理消息。

16. View 的绘制流程包含哪三个主要阶段?各自的作用是什么?
  • 答案

    • onMeasure(int widthMeasureSpec, int heightMeasureSpec) :测量 View 的宽高尺寸。基于父容器传入的 MeasureSpec(EXACTLY, AT_MOST, UNSPECIFIED)计算自身的宽高。

    • onLayout(boolean changed, int left, int top, int right, int bottom) :确定 View 在父容器中的最终位置(摆放坐标)。

    • onDraw(Canvas canvas) :将 View 绘制到屏幕上。通常依次绘制背景、内容(onDraw)、子 View(dispatchDraw)和装饰(如滚动条)。

17. 什么是 View 的 invalidate()requestLayout()?它们有什么区别?
  • 答案

    • invalidate():触发 View 的重绘(重走 onDraw()),不会重新触发 onMeasure()onLayout()。适用于仅修改了背景颜色、文本内容等不改变大小和位置的情况。

    • requestLayout():触发 View 重新测量和布局(重走 onMeasure() -> onLayout() -> onDraw()),适用于 View 的尺寸、外边距或隐藏状态改变时。

18. Android 中的 RemoteViews 适用于什么场景?其工作原理是什么?
  • 答案

    • 应用场景:常用于通知栏 Notification 和桌面小组件 AppWidget。

    • 原理:RemoteViews 实现了 Parcelable 接口,可以在跨进程(IPC)中传输。它并不是真正的 View,而是一套 UI 描述指令。底层通过 Binder 将描述传递给系统服务(如 NotificationManagerService),由系统服务在自己的进程解析并在指定的 View 层次树上应用这些绘制操作。

19. 简述 Context 的体系结构,Activity、Service 和 Application 的 Context 有何区别?
  • 答案

    • 体系结构Context 为抽象基类,ContextImpl 是其具体实现类;ContextWrapper 为包装类,ApplicationService 继承自 ContextWrapperContextThemeWrapper 继承自 ContextWrapperActivity 继承自 ContextThemeWrapper

    • 区别

      • Activity 含有 Theme(主题)信息,适用于 UI 弹出(对话框)、启动 Activity 等操作。

      • ServiceApplication 没有 Theme 资源,不能直接用于弹出 Dialog 或依赖 Theme 的 View 渲染。启动 Activity 时通常需要加 FLAG_ACTIVITY_NEW_TASK 标记。

20. Android 四大组件在 AndroidManifest.xml 中注册的意义是什么?
  • 答案

    • 清单文件是 AMS(ActivityManagerService)及系统解析 APK 的清单。

    • 注册组件可以让系统 AMS 知道该应用暴露了哪些组件、权限要求、启动模式及 IntentFilter 过滤规则。未在 Manifest 中注册的 Activity 启动时会被 AMS 校验拒绝,抛出 ActivityNotFoundException

21. Android 中的 ParcelableSerializable 序列化接口有何区别?
  • 答案

    • Serializable:Java 原生接口,基于反射实现,序列化过程中产生大量临时对象并伴随频繁磁盘 I/O,效率较低。

    • Parcelable:Android 特有接口,内存型序列化,将对象打散存储到内存块(Parcel)中,高效且适用于 Binder IPC 跨进程传输,但编写繁琐(Kotlin 中可用 @Parcelize 简化)。

22. 什么是 ComponentActivity、FragmentActivity 和 AppCompatActivity?
  • 答案

    • ComponentActivity:Jetpack 的基础 Activity 类,实现了 LifecycleOwnerViewModelStoreOwnerSavedStateRegistryOwner 等基础能力。

    • FragmentActivity:继承自 ComponentActivity,增加了对原生 Fragment 兼容与调度的支持。

    • AppCompatActivity:继承自 FragmentActivity,向下兼容旧版本 Android 的 Material 设计风格、ActionBar 以及 AppCompat 系列控件。

23. Jetpack ViewModel 的作用是什么?为什么屏幕旋转时它不会销毁?
  • 答案

    • 作用:负责存放和管理 UI 相关的数据,实现 UI 与数据解耦,并自动感知的生命周期。

    • 屏幕旋转不销毁原理:屏幕旋转导致 Activity 销毁重建时,系统在销毁前通过 ViewModelStore 将 ViewModel 实例留存(存储在 NonConfigurationInstances 中)。Activity 重建后,从新的 ViewModelStore 中通过相同的 Key 取出之前的 ViewModel 实例。只有当 Activity 真正 finish 时,才会调用 ViewModel.onCleared() 释放资源。

24. LiveData 和 StateFlow 有什么区别?
  • 答案

    • LiveData:Android 架构组件,UI 感知(生命周期感知),只在 Observer 处于 STARTED/RESUMED 状态时发送更新,主要在 Android 主线程(UI 线程)使用。

    • StateFlow:Kotlin 协程生态提供的响应式数据流,属于热流,无 Android 平台依赖(纯 Kotlin);必须有初始值,始终保留最新状态;支持丰富的协程操作符(如 mapfilter 等),需结合 repeatOnLifecycle 在 Android UI 中安全监听。

25. 什么是 Android 组件化开发?组件化与模块化的区别是什么?
  • 答案

    • 模块化:侧重于按照业务(如用户模块、商品模块)或功能(如网络库、图片库)将代码结构拆分为不同 module,但最终仍编译在一个大工程中,模块间可能存在直接依赖。

    • 组件化:在模块化的基础上进一步彻底解耦。每个组件不仅是独立的 module,且可以作为单独的 App 运行调试(通过切换 isApp 标记);组件之间不能直接依赖,必须通过路由(如 ARouter、WMRouter)或接口下沉的方式实现跨组件调用与通信。

三、 Flutter 基础(10题)

26. 简述 Flutter 的三棵树(Widget、Element、RenderObject)架构及作用。
  • 答案

    • Widget 树:配置文件,轻量级、不可变(Immutable),用于描述 UI 的配置信息(如颜色、布局属性)。

    • Element 树:Widget 与 RenderObject 之间的桥梁,持有 Widget 和 RenderObject 的引用,管理 Lifecycle。Element 树是可变的,当 Widget 更新时,通过 Diff 算法复用 Element。

    • RenderObject 树:真正负责布局(Layout)和绘制(Paint)的实体对象,开销较大,仅与 render 类的 Widget 对应。

27. Flutter 中 StatelessWidgetStatefulWidget 的区别及生命周期。
  • 答案

    • 区别StatelessWidget 适用于不可变状态的静态 UI;StatefulWidget 拥有可变的 State 对象,可以通过 setState() 触发 UI 刷新。

    • StatefulWidget 生命周期createState() -> initState() -> didChangeDependencies() -> build() -> didUpdateWidget()(父组件重构时)-> deactivate() -> dispose()

28. Flutter 中的 MethodChannelEventChannelBasicMessageChannel 有何区别?
  • 答案

    • MethodChannel:用于一次性方法调用(双向),通常由 Dart 发起请求,原生端返回异步结果。

    • EventChannel:用于数据流传输(单向,原生 -> Dart),通常用于原生端向 Dart 端持续推送事件(如传感器数据、网络状态变动、音视频进度等)。

    • BasicMessageChannel:用于连续的双向消息传递,支持自定义编解码器(如 String、JSON、二进制)。

29. Flutter 中的 SetState 局部刷新机制及 Keys 的作用是什么?
  • 答案

    • 局部刷新setState() 会将当前 State 标记为 dirty,并在下一个帧调度中重新触发该 State 的 build()。为了避免大面积重构,可以将需要刷新的控件抽取成独立的 StatefulWidget 或使用 ValueNotifier/Builder 包装。

    • Keys 的作用:在 Widget 树发生结构变化(如列表项增删、排序)时,帮助 Flutter 识别 Element 与 Widget 的对应关系,保证状态(State)能正确保留和绑定到对应的 Widget 上。

30. 简单对比 GetX 和 Riverpod 两种状态管理框架的特点。
  • 答案

    • GetX:高集成度、易上手,采用响应式(Rx)/单例驱动;内置路由管理、国际化、依赖注入等功能;缺点是隐式依赖较多、解耦不够彻底。

    • Riverpod:基于 Provider 升级重构,编译期安全,完全脱离了 BuildContext 树限制;支持代码生成(Riverpod Generator),状态声明式且易于测试,架构设计更符合现代 Dart 标准。

31. Flutter 中的 FutureIsolate 是什么?它们有什么区别?
  • 答案

    • Future:基于 Dart 异步事件循环(Event Loop)机制实现的非阻塞任务,依然运行在同一个单线程(Main Isolate)中。适用于网络请求、文件 I/O 等异步等待。

    • Isolate:Dart 的多线程实现模型。每个 Isolate 都有独立孤立的内存空间和事件循环,Isolate 之间不共享内存,只能通过消息传递(ReceivePort/SendPort)通信。适用于耗时的计算密集型任务(如大 JSON 解析、图像处理)。

32. Flutter 的布局模型约束传递原则是什么?(Constraints go down, Sizes go up, Parents set positions)
  • 答案

    • Constraints go down:父节点向子节点传递约束条件(最小/最大宽高)。

    • Sizes go up:子节点根据父节点给出的约束,计算出自身的尺寸(Size)并汇报给父节点。

    • Parents set positions:父节点根据子节点的尺寸,决定子节点在自己坐标系中的位置(Position)。

33. Flutter 如何处理原生平台的权限申请(如 Camera、Microphone)?
  • 答案

    • 通常使用插件 permission_handler

    • 在 Android 端的 AndroidManifest.xml 和 iOS 端的 Info.plist 中声明静态权限。

    • 在 Dart 端通过 Permission.camera.request() 动态发起请求,并根据返回状态(granteddeniedpermanentlyDenied)进行后续业务跳转或弹窗引导。

34. Flutter 中 ListView.builder 的优化原理是什么?
  • 答案

    • ListView.builder 使用了懒加载(Lazy Loading)机制。

    • 它不会一次性渲染列表中所有子 Widget,而是根据视口(Viewport)大小和预加载区域(cacheExtent),仅对当前可见及邻近的少量子 Widget 进行构建与渲染;超出可见范围的 Element/RenderObject 会被回收复用,极大降低内存开销。

35. 什么是 Flutter 引擎(Engine)和 Dart VM?
  • 答案

    • Flutter Engine:纯 C/C++ 实现的高性能渲染引擎,包含 Skia/Impeller 图形渲染库、Text 文本排版引擎、Dart 运行时以及 Platform Channels 底层支持,负责将 Widget 绘制指令渲染为屏幕像素。

    • Dart VM:Dart 语言的虚拟机/运行时环境,在 Debug 模式下提供 JIT(即时编译)实现 Hot Reload,在 Release 模式下通过 AOT(预先编译)编译成机器码以获得极致性能。

四、 网络通信、IM & 音视频基础(8题)

36. TCP 协议中的“三次握手”和“四次挥手”过程分别是什么?
  • 答案

    • 三次握手(建立连接)

      1. 客户端发送 SYN,进入 SYN_SENT 状态。

      2. 服务端收到后回复 SYN + ACK,进入 SYN_RCVD 状态。

      3. 客户端收到后回复 ACK,进入 ESTABLISHED 状态,连接建立。

    • 四次挥手(断开连接)

      1. 客户端发送 FIN,进入 FIN_WAIT_1 状态。

      2. 服务端收到后回复 ACK,进入 CLOSE_WAIT 状态。

      3. 服务端处理完剩余数据后,发送 FIN,进入 LAST_ACK 状态。

      4. 客户端收到后回复 ACK,进入 TIME_WAIT 状态,等待 2MSL 后彻底关闭;服务端收到 ACK 后直接关闭。

37. WebSocket 协议与 HTTP 协议有什么区别和联系?
  • 答案

    • 联系:WebSocket 借用 HTTP 协议的 101 Status Code(Switching Protocols)完成初始握手升级。

    • 区别

      • HTTP 是无状态、单向请求-响应式协议(客户端发起,服务端被动响应)。

      • WebSocket 是全双工通信协议,一旦握手建立后,客户端和服务端可以随时互相推送数据,头部开销小,适合高频实时交互(如 IM、直播弹幕)。

38. 什么是 Netty?它相比传统 Java Bio/Nio 有什么优势?
  • 答案

    • 定义:Netty 是一个基于 NIO(非阻塞 I/O)的高性能异步事件驱动的网络通信框架。

    • 优势

      • 封装了原生 Java NIO 繁琐且易出错的 API(如 Selector、ByteBuffer 读写切换)。

      • 解决了原生 NIO 的 Epoll 空轮询 Bug。

      • 自定义了高性能的 ByteBuf 内存缓冲区(支持池化和零拷贝 Zero-Copy)。

      • 提供了丰富的编解码器(如 Protobuf、LengthFieldBasedFrameDecoder)和灵活的责任链管道(ChannelPipeline)。

39. IM 系统中“心跳机制”的作用是什么?
  • 答案

    • 维持 TCP/WebSocket 长连接的存活,防止因移动网络运营商 NAT 映射超时(NAT 穿透失效)导致连接被切断。

    • 及时探测网络异常断开(如假死、断网、突发无信号)。当客户端或服务端在指定时间内未收到对方的心跳回应时,能主动触发重连或清理失效连接。

40. 什么是音视频的 RTMP、HTTP-FLV 和 HLS 协议?
  • 答案

    • RTMP:基于 TCP 的私有实时消息协议,延迟极低(1-3秒),常用于直播推流;缺点是浏览器原生支持差,需借助 Flash 或 WASM。

    • HTTP-FLV:将 RTMP 封装成 FLV 流通过 HTTP 协议传输,延迟低(1-3秒),防火墙穿透性好,常用于国内直播拉流

    • HLS:Apple 主导的基于 HTTP 的切片流协议(M3U8 索引文件 + TS 切片文件),兼容性极好(iOS/Android 原生支持),但延迟较高(10-30秒),常用于点播或对延迟不敏感的直播

41. 音视频开发中的硬解码与软解码有何区别?
  • 答案

    • 软解码:使用 CPU 运行纯软件算法(如 FFmpeg)解析音视频帧。优点是兼容性强、支持格式广;缺点是 CPU 占用高、发热严重、耗电量大。

    • 硬解码:调用系统底层专属的硬件解码芯片(如 Android MediaCodec、iOS VideoToolbox)进行解码。优点是速度极快、CPU 占用极低、省电;缺点是不同芯片厂商兼容性存在差异。

42. 简单介绍播放器框架 ijkplayer 与 ExoPlayer 的区别。
  • 答案

    • ijkplayer:Bilibili 开源的基于 FFmpeg 的跨平台(Android/iOS)播放器,底层 C/C++ 占比高,对软解和自定义封装协议(如 FLV/RTMP)支持极佳,但社区停更较久。

    • ExoPlayer:Google 官方主导的 Android 端纯 Java/Kotlin 级可扩展播放器,深度集成 Android 系统硬解,支持 DASH、SmoothStreaming 等现代流媒体协议,扩展性极强,是 Android 官方推荐的标准播放库。

43. 简述 Protobuf 数据格式相比 JSON/XML 的优势。
  • 答案

    • 体积更小:采用二进制编码(Varint、ZigZag 等变长编码技术),去除格式化标签和冗余空格,体积仅为 JSON 的 1/3~1/10。

    • 解析速度更快:序列化/反序列化不需要复杂的文本解析过程,直接按字节索引偏移提取数据。

    • 强类型约束:通过 .proto 描述文件自动生成各语言代码,编译期防范类型不一致风险。

五、 性能优化与故障排查基础(7题)

44. 什么是 Android 中的 OOM(OutOfMemoryError)?常见的诱发原因有哪些?
  • 答案

    • 定义:当应用向 JVM/Android 系统申请的内存超过了当前进程分配的上限(heapsize),且 GC 无法回收足够空间时,抛出 OOM 异常。

    • 常见原因

      1. 大图/未压缩图片的直接加载( Bitmap 占用大量 Java 堆或 Native 内存)。

      2. 长期内存泄漏(如 Static 变量持有了 Activity Context、Handler 未移除消息、单例持有了 Activity)。

      3. 线程创建过多(超过系统进程线程上限)。

45. 什么是 ANR(Application Not Responding)?触发 ANR 的超时阈值分别是多少?
  • 答案

    • 定义:应用主线程(UI 线程)在特定时间内未响应用户输入或未完成系统回调,导致系统弹出“应用无响应”提示框。

    • 超时阈值

      • KeyDispatching Timeout(按键/触摸事件):5 秒。

      • Service:前台 Service 20 秒,后台 Service 200 秒。

      • BroadcastReceiver:前台广播 10 秒,后台广播 60 秒。

      • ContentProvider:Publish 超时 10 秒。

46. 简述 Android 内存泄漏的含义,并举出 3 个常见的内存泄漏场景。
  • 答案

    • 含义:生命周期较短的对象已经不再使用,但由于被生命周期更长的对象持有了强引用,导致 GC 无法正常回收该对象,使其长期驻留在内存中。

    • 常见场景

      1. 静态变量持有 Context:如静态单例持有了 Activity 的 Context。

      2. 非静态内部类/匿名内部类:如 Handler、Runnable、AsyncTask 默认持有外部 Activity 的引用,若延迟任务未执行完 Activity 就 finish,会导致 leak。

      3. 资源未注销/未关闭:如 RxJava 未 dispose()、EventBus 未 unregister()、Cursor/FileStream 未 close()

47. Android 官方推荐的 Profiler 工具有哪些分析模块?各自有什么作用?
  • 答案

    • CPU Profiler:跟踪 CPU 使用率、分析线程状态,并通过 System Trace / Callstack 追踪方法耗时与卡顿。

    • Memory Profiler:实时监控堆内存分配(Heap Dump),抓取内存快照分析内存泄漏与对象数量。

    • Network Profiler:监控 HTTP/HTTPS 及 Socket 的网络请求数据量、耗时及响应流。

    • Energy Profiler:分析应用对设备电量(CPU、GPS、蓝牙等)的消耗。

48. 解释什么是过度绘制(Overdraw)?如何排查与解决?
  • 答案

    • 概念:屏幕上的某个像素在同一帧内被重复绘制了多次。

    • 排查方法:在 Android 开发者选项中开启“调试 GPU 过度绘制(Show GPU Overdraw)”,观察屏幕颜色(无色 < 蓝 < 绿 < 淡红 < 深红)。

    • 优化方案

      1. 移除不必要的控件背景色(如 Activity/Layout 重复设背景)。

      2. 扁平化布局层级,减少 ConstraintLayout 或 nested view 的过度嵌套。

      3. 自定义 View 中使用 canvas.clipRect() 剪裁出非重叠区域再绘制。

49. LeakCanary 的工作原理是什么?
  • 答案

    • LeakCanary 在 Activity/Fragment 销毁时(如 onDestroy),使用 WeakReference 弱引用关联该实例,并将弱引用注册到 ReferenceQueue(引用队列)中。

    • 主动触发一次垃圾回收(GC),若对象被正常 GC,其对应的弱引用会被加入到 ReferenceQueue

    • 延迟一段时间(通常 5 秒)后检查 ReferenceQueue,若队列中没有该弱引用,说明该对象依然存活(发生内存泄漏),随后触发 Heap Dump 生成 .hprof 文件并通过 Shark 库解析引用链,定位泄漏源头。

50. 什么是 Android 中的卡顿(Jank)?它的基本定义是什么?
  • 答案

    • 定义:Android 系统要求屏幕刷新率通常为 60Hz(即每 16.6ms 刷新一帧)或 90Hz/120Hz。如果应用在主线程中执行了耗时操作(如复杂 UI 测量、主线程 I/O、大量对象创建),导致丢帧(Frames Drop),系统无法在规定时间(16.6ms)内准备好 Surface 缓冲区供 SurfaceFlinger 合成,就会造成画面停顿,即产生“卡顿(Jank)”。

栏目录导航

最后,祝愿每一位正在备战面试的 Android 开发者:

  • 能够在反复的梳理与思考中打破瓶颈,将知识真正融会贯通;
  • 在接下来的每一场面试中发挥出色、对答如流,展现出自己最出色的技术硬实力;
  • 拨云见日,顺利斩获心仪的大厂与中高级职位 Offer,在移动开发的技术道路上披荆斩棘、一路高歌!