Android 常见面试题
涵盖四大组件、性能优化、架构、Kotlin、Jetpack 等主流方向
一、四大组件
1. Activity 生命周期
onCreate → onStart → onResume → [运行中]
↓
onPause → onStop → onDestroy(完全退出)
onPause → onStop → onRestart → onStart(重新回到前台)
onPause → onResume(轻度遮挡,如弹窗)
常见考点:
- A 跳转 B:A.onPause → B.onCreate → B.onStart → B.onResume → A.onStop
- 按 Home:onPause → onStop
- 旋转屏幕:onPause → onStop → onDestroy → onCreate(可用
onSaveInstanceState保存数据)
2. Activity 启动模式(launchMode)
| 模式 | 说明 | 场景 |
|---|---|---|
| standard | 每次新建实例 | 默认 |
| singleTop | 栈顶已有则复用,回调 onNewIntent |
通知跳转详情页 |
| singleTask | 栈中已有则复用并清除其上所有 Activity | 首页、主界面 |
| singleInstance | 独占一个任务栈 | 来电界面、系统级页面 |
3. Service 两种启动方式的区别
| startService | bindService | |
|---|---|---|
| 生命周期 | 独立于调用者 | 与调用者绑定 |
| 通信 | 无直接通信 | 通过 IBinder 通信 |
| 停止方式 | stopService / stopSelf | 所有客户端 unbind 后自动销毁 |
| 场景 | 后台下载、音乐播放 | Activity 与 Service 双向通信 |
4. BroadcastReceiver 静态注册 vs 动态注册
| 静态注册(Manifest) | 动态注册(代码) | |
|---|---|---|
| 生命周期 | 常驻,APP 未启动也能收到 | 跟随组件生命周期 |
| 注意 | Android 8.0+ 限制隐式广播静态注册 | 需手动 unregisterReceiver |
| 场景 | 开机广播、安装广播 | 网络变化、电量变化 |
5. ContentProvider 的作用
- 跨进程共享数据(如通讯录、媒体库)
- 通过 URI 统一访问格式:
content://authority/path/id - 底层基于 Binder IPC
二、Handler / 消息机制
6. Handler 消息机制原理
Handler → sendMessage → MessageQueue(链表)
↓
Looper.loop() 轮询
↓
Handler.dispatchMessage → handleMessage
核心类:
Handler:发送和处理消息Message:消息载体(what / obj / arg1 / arg2)MessageQueue:优先级队列,按when排序Looper:轮询 MessageQueue,每个线程最多一个
主线程为什么不会因为 Looper.loop() 阻塞 ANR?
主线程的 Looper 通过 epoll 机制进入休眠,有消息时才唤醒,不占用 CPU,ANR 是因为主线程消息处理超时(5s),不是因为 loop() 本身。
7. Handler 内存泄漏原因及解决
原因: 非静态内部类 Handler 持有外部 Activity 的引用,如果 Message 还在队列中,Activity 无法被 GC。
解决:
kotlin
// 使用静态内部类 + WeakReference
class MyHandler(activity: WeakReference<MainActivity>) : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
activity.get()?.let {
// 处理消息
}
}
}
// onDestroy 时移除消息
override fun onDestroy() {
super.onDestroy()
handler.removeCallbacksAndMessages(null)
}
三、View 体系
8. View 的绘制流程
measure(测量宽高)→ layout(确定位置)→ draw(绘制内容)
onMeasure:通过 MeasureSpec 计算宽高onLayout:ViewGroup 负责摆放子 View 位置onDraw:实际绘制,使用 Canvas
MeasureSpec 三种模式:
EXACTLY:确定大小(match_parent 或具体 dp)AT_MOST:最大不超过(wrap_content)UNSPECIFIED:不限制(ScrollView 内的子 View)
9. View 事件分发机制
Activity.dispatchTouchEvent
→ ViewGroup.dispatchTouchEvent
→ ViewGroup.onInterceptTouchEvent(是否拦截)
→ View.dispatchTouchEvent
→ View.onTouchEvent(处理)
返回值含义:
true:消费事件,不再向下/向上传递false:不消费,继续传递
解决滑动冲突:
- 外部拦截法:在 ViewGroup 的
onInterceptTouchEvent中判断 - 内部拦截法:在 View 中调用
requestDisallowInterceptTouchEvent
10. RecyclerView 缓存机制
RecyclerView 有 4 级缓存:
| 缓存层级 | 名称 | 说明 |
|---|---|---|
| 第一级 | Scrap | 屏幕内可见的 View,不需要重新绑定 |
| 第二级 | CacheViews | 默认 2 个,滑出屏幕的 View,不需要重新绑定 |
| 第三级 | ViewCacheExtension | 自定义缓存(很少用) |
| 第四级 | RecycledViewPool | 按 viewType 缓存,需要重新绑定数据 |
与 ListView 的区别:
- RecyclerView 强制使用 ViewHolder
- 支持多种布局管理器(LinearLayout / Grid / Staggered)
- 支持局部刷新(notifyItemChanged)
- 默认支持 Item 动画
四、内存 & 性能优化
11. 内存泄漏常见场景
| 场景 | 解决方案 |
|---|---|
| 静态变量持有 Context | 使用 ApplicationContext 或及时置空 |
| 非静态内部类(Handler/AsyncTask) | 改为静态内部类 + WeakReference |
| 注册未注销(BroadcastReceiver / EventBus) | onDestroy 中注销 |
| 资源未关闭(Cursor / IO流) | 用完 close() |
| 单例持有 Activity | 改为持有 ApplicationContext |
| Bitmap 未回收 | recycle() 或使用 Glide/Picasso 管理 |
检测工具: LeakCanary、Android Studio Memory Profiler
12. ANR 是什么,如何避免
ANR 触发条件:
- 主线程 5 秒内未响应输入事件
- BroadcastReceiver 10 秒内未完成
- Service 前台 20 秒 / 后台 200 秒
避免方法:
- 耗时操作放子线程(网络、IO、数据库)
- 使用 AsyncTask / Coroutine / RxJava
StrictMode检测主线程耗时操作
查看 ANR 日志: /data/anr/traces.txt
13. OOM 的原因及解决
常见原因:
- Bitmap 加载过大图片
- 内存泄漏积累
- 大量对象分配
解决:
kotlin
// Bitmap 压缩采样
val options = BitmapFactory.Options().apply {
inJustDecodeBounds = true
BitmapFactory.decodeFile(path, this)
inSampleSize = calculateInSampleSize(this, reqWidth, reqHeight)
inJustDecodeBounds = false
}
val bitmap = BitmapFactory.decodeFile(path, options)
// 使用 inBitmap 复用内存
options.inBitmap = reusableBitmap
14. 启动优化
冷启动 / 温启动 / 热启动:
- 冷启动:进程不存在,从零开始(最慢)
- 温启动:进程存在但 Activity 被销毁
- 热启动:进程和 Activity 都存在(最快)
优化方向:
- Application.onCreate() 中的初始化延迟或异步化(子线程/IdleHandler)
- 避免 Activity.onCreate() 中耗时操作
- 主题设置
windowBackground避免白屏/黑屏 - 使用 App Startup 库管理依赖初始化顺序
15. 卡顿优化
- 主线程避免 IO / 大量计算
- 布局层级不超过 5 层,用 ConstraintLayout 减少嵌套
- RecyclerView:使用
DiffUtil替代notifyDataSetChanged - 使用
ViewStub延迟加载不常用 View - 图片加载使用 Glide / Coil(自动处理缓存和生命周期)
- 使用
Systrace/Perfetto分析掉帧原因
五、进程间通信(IPC)
16. Android IPC 方式
| 方式 | 说明 | 场景 |
|---|---|---|
| Binder | Android 专有,高效安全 | AIDL、系统服务 |
| AIDL | 基于 Binder,定义接口 | 跨进程服务调用 |
| Messenger | 基于 AIDL,串行处理消息 | 简单跨进程通信 |
| ContentProvider | 基于 Binder,统一数据访问 | 跨 APP 共享数据 |
| 广播 | 系统级消息传递 | 全局事件通知 |
| 文件/SharedPreferences | 共享存储 | 简单数据共享 |
| Socket | 网络通信 | 跨设备或本地通信 |
17. Binder 原理简述
传统 IPC(socket / pipe)需要两次数据拷贝:用户空间 → 内核空间 → 用户空间
Binder 只需一次拷贝 :通过 mmap 将内核空间与目标进程用户空间映射同一块内存,发送方拷贝一次即可。
六、Kotlin 特性
18. Kotlin 协程
kotlin
// 启动协程
viewModelScope.launch {
val result = withContext(Dispatchers.IO) {
// 耗时操作
fetchData()
}
// 回到主线程更新 UI
updateUI(result)
}
// 并发执行
viewModelScope.launch {
val deferred1 = async(Dispatchers.IO) { fetchUser() }
val deferred2 = async(Dispatchers.IO) { fetchOrders() }
val user = deferred1.await()
val orders = deferred2.await()
}
调度器:
Dispatchers.Main:主线程,更新 UIDispatchers.IO:IO 密集型(网络、数据库)Dispatchers.Default:CPU 密集型(排序、计算)
19. Kotlin 常用特性
kotlin
// 空安全
val name: String? = null
val len = name?.length ?: 0 // Elvis 操作符
val len2 = name!!.length // 强制非空(可能 NPE)
// 扩展函数
fun String.isEmail(): Boolean = contains("@")
// 数据类(自动生成 equals/hashCode/copy/toString)
data class User(val name: String, val age: Int)
// 密封类(限制继承)
sealed class Result {
data class Success(val data: String) : Result()
data class Error(val msg: String) : Result()
}
// 委托属性
val viewModel: MyViewModel by viewModels()
var name: String by Delegates.observable("") { _, old, new ->
println("$old → $new")
}
// 内联函数
inline fun <reified T> Gson.fromJson(json: String): T =
fromJson(json, T::class.java)
七、Jetpack 组件
20. ViewModel
- 存储 UI 相关数据,在配置变更(旋转)时存活
- 不持有 View 引用,避免内存泄漏
- 通过
LiveData/StateFlow向 UI 层暴露数据
kotlin
class UserViewModel : ViewModel() {
private val _user = MutableLiveData<User>()
val user: LiveData<User> = _user
fun loadUser(id: String) {
viewModelScope.launch {
_user.value = repository.getUser(id)
}
}
}
21. LiveData vs StateFlow / SharedFlow
| LiveData | StateFlow | SharedFlow | |
|---|---|---|---|
| 粘性事件 | 是 | 是 | 可配置 |
| 生命周期感知 | 是(自带) | 需 repeatOnLifecycle |
需 repeatOnLifecycle |
| 初始值 | 无 | 必须有 | 无 |
| 适用场景 | UI 状态 | UI 状态 | 一次性事件(Toast) |
22. Room 数据库
kotlin
// Entity
@Entity(tableName = "users")
data class UserEntity(
@PrimaryKey val id: String,
val name: String,
val age: Int
)
// DAO
@Dao
interface UserDao {
@Query("SELECT * FROM users")
fun getAll(): Flow<List<UserEntity>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(user: UserEntity)
@Delete
suspend fun delete(user: UserEntity)
}
// Database
@Database(entities = [UserEntity::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
23. Navigation 组件
- 统一管理 Fragment 跳转,避免 FragmentManager 手动操作
NavController.navigate(R.id.action_home_to_detail)- 支持 Safe Args(类型安全传参)
- 支持 Deep Link
八、架构设计
24. MVC / MVP / MVVM 区别
| MVC | MVP | MVVM | |
|---|---|---|---|
| View 与逻辑耦合 | 高 | 低 | 低 |
| 可测试性 | 差 | 好 | 好 |
| 双向绑定 | 无 | 无 | 有(DataBinding) |
| Android 推荐 | 否 | 一般 | 推荐 |
MVVM 在 Android 中:
- View = Activity / Fragment
- ViewModel = ViewModel
- Model = Repository + 数据源
25. Repository 模式
View → ViewModel → Repository → (RemoteDataSource / LocalDataSource)
↓ ↓
Retrofit Room
Repository 负责数据来源决策(优先缓存?先请求网络?),ViewModel 不关心数据从哪来。
九、网络
26. Retrofit + OkHttp 原理
OkHttp 核心:
- 拦截器链(Interceptor Chain):LoggingInterceptor → CacheInterceptor → ConnectInterceptor → CallServerInterceptor
- 连接池复用(减少 TCP 握手开销)
- 支持 HTTP/2
Retrofit 核心:
- 动态代理:通过注解生成 HTTP 请求
- Converter:Gson / Moshi 解析响应体
- CallAdapter:适配 RxJava / Coroutine
kotlin
interface ApiService {
@GET("users/{id}")
suspend fun getUser(@Path("id") id: String): User
@POST("login")
suspend fun login(@Body request: LoginRequest): LoginResponse
}
27. 图片加载框架(Glide)
Glide 缓存机制:
- 活动缓存(ActiveResources):当前正在展示的图片
- 内存缓存(LruCache):最近使用的图片
- 磁盘缓存(DiskLruCache):本地文件
kotlin
Glide.with(context)
.load(url)
.placeholder(R.drawable.loading)
.error(R.drawable.error)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(imageView)
十、安全 & 其他
28. Android 安全机制
- 沙箱机制:每个 APP 运行在独立进程,分配唯一 UID
- 权限机制:dangerous 权限需运行时申请(Android 6.0+)
- 签名验证:APK 必须签名,更新时签名需一致
- ProGuard / R8:代码混淆,防止反编译
29. 序列化:Serializable vs Parcelable
| Serializable | Parcelable | |
|---|---|---|
| 实现方式 | Java 反射,自动 | 手动实现(或 @Parcelize) |
| 性能 | 慢(产生大量临时对象) | 快(直接读写内存) |
| 使用场景 | 数据持久化、网络传输 | Intent / Bundle 传递 |
| Android 推荐 | 否 | 是 |
kotlin
@Parcelize
data class User(val name: String, val age: Int) : Parcelable
30. APK 体积优化
- 开启
minifyEnabled = true(代码混淆 + 删除无用代码) - 开启
shrinkResources = true(删除无用资源) - 使用
WebP替代 PNG - 动态下发资源(插件化 / 按需下载)
abiFilters只保留必要 ABI(如只保留 arm64-v8a)- 使用 Android App Bundle(AAB)按需分发
共 30 题,涵盖:四大组件 / Handler / View 体系 / 性能优化 / IPC / Kotlin / Jetpack / 架构 / 网络 / 安全