附录C Android面试题库¶
Android开发面试常见问题汇总
1. Kotlin基础¶
Q1: Kotlin中的val和var有什么区别?¶
答案: - val:不可变变量,类似于Java的final,只能赋值一次 - var:可变变量,可以多次赋值
Q2: Kotlin的空安全机制是如何工作的?¶
答案: Kotlin通过类型系统区分可空和非空类型: - String:非空类型,不能为null - String?:可空类型,可以为null
var nullable: String? = null // 可为null
var nonNull: String = "value" // 不可为null
// 安全调用
val length = nullable?.length // null时返回null
// Elvis操作符
val len = nullable?.length ?: 0 // null时使用默认值
// 非空断言(谨慎使用)
val risky = nullable!!.length // null时抛出NPE
Q3: 什么是数据类(data class)?¶
答案: 数据类是Kotlin中用于存储数据的特殊类,编译器自动生成: - equals()/hashCode() - toString() - copy() - componentN()(解构函数)
data class User(val id: String, val name: String, val age: Int)
val user = User("1", "Alice", 25)
val copy = user.copy(name = "Bob")
val (id, name, age) = user // 解构
Q4: Kotlin协程是什么?¶
答案: 协程是轻量级线程,用于简化异步编程:
// 启动协程
val job = viewModelScope.launch { /* 后台任务 */ }
// 异步返回结果
val deferred = viewModelScope.async { fetchData() }
val result = deferred.await()
// Flow响应式流
flow {
emit(1)
emit(2)
}.collect { value -> println(value) }
2. Android基础¶
Q5: Activity的生命周期有哪些?¶
答案:
onCreate() → onStart() → onResume() → [运行中]
↓
[运行中] ← onResume() ← onRestart() ← onPause()
↓
onStop()
↓
onDestroy()
Q6: Android中的四大组件是什么?¶
答案: 1. Activity:用户界面组件 2. Service:后台服务组件 3. BroadcastReceiver:广播接收器 4. ContentProvider:内容提供器
Q7: Handler机制原理是什么?¶
答案: Handler用于线程间通信,核心组件: - Handler:发送和处理消息 - Looper:消息循环器 - MessageQueue:消息队列 - Message:消息对象
// 创建Handler
val handler = Handler(Looper.getMainLooper()) {
// 处理消息
true
}
// 发送消息
handler.sendMessage(Message.obtain())
handler.post { /* 任务 */ }
Q8: Android中的存储方式有哪些?¶
答案: | 方式 | 特点 | 适用场景 | |------|------|----------| | SharedPreferences | 键值对,轻量 | 简单配置 | | DataStore | 类型安全,异步 | 替代SharedPreferences | | Room | SQLite封装,类型安全 | 结构化数据 | | 文件存储 | 原始文件 | 大文件、缓存 | | MMKV | 高性能键值对 | 高频读写 |
3. Jetpack组件¶
Q9: ViewModel的作用是什么?¶
答案: ViewModel用于: - 管理UI相关数据 - 在配置变更时保持数据 - 分离业务逻辑和UI
class MyViewModel : ViewModel() {
private val _data = MutableLiveData<String>()
val data: LiveData<String> = _data
fun loadData() {
viewModelScope.launch {
_data.value = fetchData()
}
}
}
Q10: LiveData和StateFlow的区别?¶
答案: | 特性 | LiveData | StateFlow | |------|----------|-----------| | 生命周期感知 | ✅ 自动 | ❌ 需手动 | | 初始值 | ❌ 无 | ✅ 必须有 | | 状态重放 | ❌ 无 | ✅ 最新值 | | 线程 | 主线程 | 任意线程 | | 协程支持 | 有限 | 原生支持 |
Q11: Room数据库如何使用?¶
答案:
@Entity
data class User(@PrimaryKey val id: String, val name: String)
@Dao
interface UserDao { // interface定义类型契约
@Query("SELECT * FROM user")
fun getAll(): Flow<List<User>>
@Insert
suspend fun insert(user: User)
}
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
Q12: WorkManager的作用是什么?¶
答案: WorkManager用于执行可延迟的后台任务,特点: - 保证任务执行 - 支持约束条件(网络、电量等) - 支持链式任务 - 兼容各种Android版本
val workRequest = OneTimeWorkRequestBuilder<MyWorker>()
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
)
.build()
WorkManager.getInstance(context).enqueue(workRequest)
4. Jetpack Compose¶
Q13: Compose中的重组(Recomposition)是什么?¶
答案: 重组是指Composable函数在状态变化时重新执行以更新UI: - 自动触发 - 可跳过未变化的组件 - 使用remember缓存计算
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) }
Button(onClick = { count++ }) {
Text("Count: $count") // count变化时重组
}
}
Q14: 如何在Compose中管理状态?¶
答案:
// 本地状态
var text by remember { mutableStateOf("") }
// 状态提升
@Composable
fun Parent() {
var text by remember { mutableStateOf("") }
Child(text = text, onTextChange = { text = it })
}
// ViewModel状态
@HiltViewModel
class MyViewModel : ViewModel() {
private val _uiState = MutableStateFlow(UiState())
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
}
Q15: Compose中的副作用有哪些?¶
答案:
// LaunchedEffect:在协程中执行副作用
LaunchedEffect(key) {
// 在key变化时执行
}
// SideEffect:每次重组成功时执行
SideEffect {
// 同步到外部系统
}
// DisposableEffect:需要清理的副作用
DisposableEffect(key) {
// 初始化
onDispose {
// 清理
}
}
5. 架构设计¶
Q16: MVVM架构的优势是什么?¶
答案: - 分离关注点:UI、业务逻辑、数据分离 - 可测试性:ViewModel可独立测试 - 可维护性:代码结构清晰 - 生命周期安全:ViewModel自动处理生命周期
View (UI Layer)
↓
ViewModel (Presentation Layer)
↓
Repository (Data Layer)
↓
DataSource (Network/Local)
Q17: 依赖注入是什么?为什么要使用?¶
答案: 依赖注入(DI)是将依赖从外部传入,而不是在内部创建:
优点: - 解耦组件 - 便于测试(可替换Mock) - 单例管理 - 生命周期管理
// Hilt示例
@HiltViewModel
class MyViewModel @Inject constructor(
private val repository: MyRepository
) : ViewModel()
Q18: 单例模式在Android中的实现方式?¶
答案:
// Kotlin object(推荐)
object DatabaseHelper {
fun query() { }
}
// 伴生对象
class Manager private constructor() {
companion object {
@Volatile
private var instance: Manager? = null
fun getInstance() = instance ?: synchronized(this) { // synchronized同步锁,保证线程安全
instance ?: Manager().also { instance = it }
}
}
}
// Hilt单例
@Singleton
class Repository @Inject constructor()
6. 性能优化¶
Q19: 如何优化RecyclerView/List性能?¶
答案:
// 1. 使用ViewHolder模式
// 2. 设置固定大小
recyclerView.setHasFixedSize(true)
// 3. 使用合适的LayoutManager
// 4. 分页加载
// 5. 图片懒加载
// 6. 缓存复用
Q20: 内存泄漏的常见原因及解决方案?¶
答案: | 原因 | 解决方案 | |------|----------| | 静态引用Activity | 使用WeakReference | | 未注销监听器 | 在onDestroy中注销 | | 匿名内部类 | 使用静态内部类 | | Handler延迟消息 | 使用静态Handler + WeakReference | | 资源未释放 | 及时关闭Cursor、Bitmap等 |
Q21: 如何优化应用启动速度?¶
答案: 1. 延迟初始化非必要SDK 2. 使用SplashScreen API 3. 减少Application.onCreate工作量 4. 使用Profile Installer 5. 优化主题背景(windowBackground)
7. Flutter¶
Q22: Flutter中的Widget是什么?¶
答案: Widget是Flutter UI的基本构建块: - StatelessWidget:无状态,不可变 - StatefulWidget:有状态,可更新
// StatelessWidget
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Text('Hello');
}
}
// StatefulWidget
class Counter extends StatefulWidget {
@override
_CounterState createState() => _CounterState();
}
class _CounterState extends State<Counter> {
int count = 0;
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () => setState(() => count++),
child: Text('$count'),
);
}
}
Q23: Flutter中的状态管理方案有哪些?¶
答案: | 方案 | 特点 | 适用场景 | |------|------|----------| | setState | 简单 | 简单页面 | | Provider | 轻量 | 中小型应用 | | Riverpod | 安全 | 中大型应用 | | Bloc | 规范 | 大型复杂应用 | | GetX | 简洁 | 快速开发 |
Q24: Flutter如何实现与原生通信?¶
答案:
// Flutter端
const platform = MethodChannel('com.example/channel');
Future<void> callNative() async {
final result = await platform.invokeMethod('methodName', {'key': 'value'});
}
// Android端
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "com.example/channel")
.setMethodCallHandler { call, result ->
when (call.method) {
"methodName" -> {
val value = call.argument<String>("key")
result.success("Response")
}
}
}
8. 其他¶
Q25: Android中的ANR是什么?如何避免?¶
答案: ANR(Application Not Responding)是应用无响应错误。
避免方法: - 主线程不执行耗时操作(>5秒) - 使用协程/线程处理后台任务 - BroadcastReceiver中不执行耗时操作(>10秒) - 使用WorkManager处理后台任务
Q26: 如何保证Android应用的安全性?¶
答案: 1. 使用HTTPS通信 2. 证书固定(SSL Pinning) 3. 敏感数据加密存储(EncryptedSharedPreferences/Keystore) 4. 代码混淆(ProGuard/R8) 5. 签名校验 6. 防Root/防调试