Android面试题

本文探讨了Android面试中常见的核心问题,包括ArrayList与LinkedList的性能对比,Java基础数据类型,Activity的完整生命周期,线程安全的数据结构,以及在Android系统中至关重要的Looper和AMS。此外,还涉及到了进程间通信的多种方式和View的绘制流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数据结构

ArrayList和LinkedList的区别

ArrayList:

  • 底层实现:基于数组实现,支持快速随机访问。
  • 性能特点:随机访问元素的时间复杂度为O(1);在末尾添加或删除元素的时间复杂度为O(1)(平均情况),但如果数组需要动态扩容,则时间复杂度可能为O(n);在中间插入或删除元素的时间复杂度为O(n),因为需要移动元素。
  • 适用场景:适合需要频繁随机访问元素,或者在末尾频繁添加或删除元素的场景。

LinkedList:

  • 底层实现:基于双向链表实现,不支持随机访问。
  • 性能特点:随机访问元素的时间复杂度为O(n),需要从头或尾遍历;在链表中任意位置插入或删除元素的时间复杂度为O(1),因为只需要修改指针,不需要移动元素。
  • 适用场景:适合需要频繁在链表中间插入或删除元素的场景。

SparseArray的原理与应用

  • 原理:
    • SparseArray 是 Android 提供的一种优化过的数组实现,它使用两个数组(keys和values)来分别存储键和值,通过线性查找来实现键值对的存储和查找。
    • 相比于 HashMap,SparseArray避免了自动装箱和拆箱操作,以及哈希冲突带来的开销,在键为整数的情况下,性能更优。
  • 优势:
    • 内存占用:SparseArray 的内存占用比 HashMap 更低,因为它避免了 HashMap 的哈希表和桶结构。
    • 性能:在整数键值对的场景下,SparseArray 的查找、插入和删除操作速度更快。
  • 实际场景:在 Android 中,频繁使用整数作为键值对的场景,如存储资源 ID 与对应的资源对象的映射关系时,使用 SparseArray 可以提高性能。

Android View

View的绘制过程

在Android中,视图(View)的绘制过程是一个复杂且有序的过程,主要包括三个阶段:测量(Measure)、布局(Layout) 和 绘制(Draw)。以下是这三个阶段的详细解释以及它们在视图绘制中的作用:

1. 测量(Measure)阶段

目的:确定视图的大小。

  • 核心方法:measure(int widthMeasureSpec, int heightMeasureSpec)。
    输入参数:widthMeasureSpec 和 heightMeasureSpec,这两个参数是父视图传递给子视图的,用于指定子视图的大小约束。
  • 输出结果:通过调用setMeasuredDimension(int measuredWidth, int measuredHeight)方法,记录视图的测量宽度和高度。

测量过程:

  • 自上而下:从顶层的ViewGroup开始,递归地测量所有子视图。
  • 测量模式:
    • MeasureSpec.EXACTLY:父视图指定了一个确切的大小,子视图必须使用这个大小。
    • MeasureSpec.AT_MOST:父视图指定了一个最大值,子视图的大小不能超过这个值。
    • MeasureSpec.UNSPECIFIED:父视图没有指定任何约束,子视图可以根据自己的需求选择大小。

自定义测量逻辑:

如果需要自定义测量逻辑,可以在自定义视图中重写onMeasure(int widthMeasureSpec, int heightMeasureSpec)方法。

2. 布局(Layout)阶段

目的:确定视图在父视图中的位置。

  • 核心方法:layout(int l, int t, int r, int b)。
  • 输入参数:l(左边界)、t(上边界)、r(右边界)、b(下边界),这四个参数定义了视图在父视图中的位置。
  • 输出结果:通过调用setFrame(int l, int t, int r, int b)方法,设置视图的最终位置和大小。

布局过程:

  • 自上而下:从顶层的ViewGroup开始,递归地布局所有子视图。
  • 布局顺序:父视图根据子视图的测量结果和布局参数,确定子视图的位置。

自定义布局逻辑:
如果需要自定义布局逻辑,可以在自定义视图中重写onLayout(boolean changed, int l, int t, int r, int b)方法。

3. 绘制(Draw)阶段

目的:将视图绘制到屏幕上。

  • 核心方法:draw(Canvas canvas)。
  • 输入参数:Canvas对象,用于绘制视图的内容。
  • 输出结果:视图的内容被绘制到屏幕上。

绘制过程:

  • 自上而下:从顶层的ViewGroup开始,递归地绘制所有子视图。
  • 绘制顺序:父视图先绘制自己的背景,然后绘制子视图,最后绘制自己的前景。

绘制步骤:

  • 绘制背景:调用drawBackground()方法。
  • 绘制边框:调用drawScrollbars()方法。
  • 绘制内容:调用onDraw()方法,开发者可以在这里自定义绘制逻辑。
  • 绘制子视图:递归调用子视图的draw()方法。
  • 绘制前景:调用drawForeground()方法。

自定义绘制逻辑:
如果需要自定义绘制逻辑,可以在自定义视图中重写onDraw(Canvas canvas)方法。

性能优化建议

  • 避免过度绘制:尽量减少不必要的绘制操作,例如避免在onDraw()中执行复杂的计算或绘制。
  • 使用硬件加速:在支持的设备上,启用硬件加速可以提高绘制性能。
  • 合理使用视图:避免过多嵌套的ViewGroup,减少布局复杂度。
  • 缓存视图:对于复杂的自定义视图,可以使用View.draw()方法将视图绘制到Bitmap中进行缓存,以减少重复绘制的开销。

通过理解Android视图的绘制过程,可以更好地优化视图的性能,提升应用的用户体验。

Framework

Lopper

https://blog.youkuaiyun.com/runrun117/article/details/79514422

AMS

https://blog.youkuaiyun.com/caohang103215/article/details/79597260

基础概念

Java基本数据类型

  1. 整数类型,byte、int、short、long。
  2. 浮点型,float、double。
  3. 字符型,char。
  4. 布尔型,boolean。

Activity的生命周期

  1. onCreate()
  2. onStart()
  3. onResume()
  4. onRestart()
  5. onPause()
  6. onStop()
  7. onDestory()
跳转页面Activity的生命周期
  1. 打开页面A
    A.onCreate()->A.onStart()->A.onResume()
  2. 由页面A到页面B
    A.onPause->B.onCreate()->B.onStart()->B.onResume()->A.onStop()
  3. 由页面B返回页面A
    B.onPause()->A.onRestart()->A.onStart()->A.onResume->B.onStop()->B.onDestory()

线程安全的数据结构

https://blog.youkuaiyun.com/hellwhj/article/details/76576933
https://blog.youkuaiyun.com/u014482758/article/details/50669483

进程间的通信

  1. 管道
  2. 信号
  3. 消息队列
  4. 信号量
  5. 共享内存
  6. 套接字

参考

https://blog.youkuaiyun.com/huangqili1314/article/details/79448187

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值