Android
Android 是一个基于 Linux 的开源操作系统,主要被设计用来操作触屏移动设备如智能手机和平板电脑。Android 最初由安迪·鲁宾等人开发,并于2007年由Google收购。随后,Google带领开放手机联盟(Open Handset Alliance)继续开发Android,并在2008年推出了第一款商用Android设备。

查看更多相关内容
Android中Binder机制的原理是什么,为什么使用Binder?Binder是Android系统中实现进程间通信(IPC)的核心机制,也是Android系统的特色之一。
### 为什么Android选择Binder
| 通信方式 | 优点 | 缺点 |
| ---------- | ------------ | ---------- |
| 管道 | 简单 | 单向通信,效率低 |
| Socket | 通用 | 开销大,速度慢 |
| 共享内存 | 速度快 | 同步复杂,安全性差 |
| **Binder** | **高效、安全、易用** | **学习曲线陡峭** |
### Binder的核心优势
1. **高效性**
* 只需一次内存拷贝(传统IPC需要两次)
* 基于C/S架构,通信效率高
2. **安全性**
* 内核层验证进程身份(UID/PID)
* 支持建立私有通道
3. **易用性**
* 封装了复杂的底层实现
* 提供AIDL等高级接口
### Binder的工作原理
#### 1. 核心组件
* **Binder驱动**:位于内核空间,管理Binder通信
* **ServiceManager**:管理所有系统服务的注册和查询
* **Client/Server**:通信的双方
#### 2. 内存映射机制
```
发送方进程 Binder驱动 接收方进程
| | |
| 数据 | 内存映射(MMAP) |
| -------------> | -----------------> |
| 用户空间 | 内核空间 | 用户空间
```
* 发送方数据拷贝到内核空间
* 接收方通过内存映射直接访问,无需再次拷贝
#### 3. 通信流程
```
1. Server注册服务 → ServiceManager
2. Client查询服务 → ServiceManager
3. Client获取Server的Binder代理
4. Client通过Binder代理调用Server方法
5. Binder驱动完成数据传递
```
### Binder在Android中的应用
#### ActivityManagerService (AMS)
* 管理Activity生命周期
* 进程调度
#### WindowManagerService (WMS)
* 窗口管理
* 屏幕显示
#### PackageManagerService (PMS)
* 应用包管理
* 权限管理
### AIDL(Android Interface Definition Language)
```java
// IRemoteService.aidl
interface IRemoteService {
int add(int a, int b);
String getMessage();
}
```
AIDL编译后自动生成:
* Stub:服务端实现
* Proxy:客户端代理
### 面试要点
* Binder是Android特有的IPC机制
* 理解一次拷贝的内存映射原理
* 掌握AIDL的基本使用方法
* Binder线程池默认16个线程
* 注意Binder通信的数据大小限制(1MB左右)
服务端 · 3月7日 19:50
Android四大组件是什么,它们各自的作用是什么?## Android四大组件详解
Android四大组件是Android应用开发的基础架构,包括:Activity、Service、BroadcastReceiver和ContentProvider。
### 1. Activity(活动)
- **作用**:负责用户界面的展示和交互
- **生命周期**:onCreate() → onStart() → onResume() → onPause() → onStop() → onDestroy()
- **使用场景**:每个可见的界面都是一个Activity
### 2. Service(服务)
- **作用**:在后台执行长时间运行操作,不提供用户界面
- **类型**:
- Started Service:通过startService()启动,即使启动组件被销毁也会继续运行
- Bound Service:通过bindService()启动,组件绑定后才能交互
- **使用场景**:音乐播放、文件下载、后台同步等
### 3. BroadcastReceiver(广播接收器)
- **作用**:监听和响应系统或应用的广播消息
- **注册方式**:
- 静态注册:在AndroidManifest.xml中声明
- 动态注册:在代码中通过registerReceiver()注册
- **使用场景**:监听网络状态变化、电量变化、开机启动等
### 4. ContentProvider(内容提供者)
- **作用**:在不同应用之间共享数据
- **特点**:提供统一的URI接口来访问数据
- **使用场景**:通讯录、媒体库等系统应用的数据共享
### 面试要点
- 四大组件都需要在AndroidManifest.xml中注册
- 理解各组件的生命周期和通信方式
- 掌握组件间的数据传递机制(Intent、Binder等)
服务端 · 3月7日 19:42
Android中Handler机制的工作原理是什么?Handler是Android中实现线程间通信的核心机制,用于在工作线程和主线程(UI线程)之间传递消息。
### Handler机制的核心组件
#### 1. Handler(处理器)
* **作用**:发送和处理消息
* **特点**:
* 绑定到创建它的线程的Looper
* 负责发送Message到MessageQueue
* 处理Looper分发的消息
#### 2. Looper(循环器)
* **作用**:消息循环,不断从MessageQueue取出消息
* **特点**:
* 每个线程只能有一个Looper
* 主线程默认已创建Looper
* 子线程需要手动调用Looper.prepare()和Looper.loop()
#### 3. MessageQueue(消息队列)
* **作用**:存储消息的队列
* **特点**:
* 先进先出(FIFO)
* 按时间排序(when字段)
* 底层使用单链表实现
#### 4. Message(消息)
* **作用**:携带数据和信息的载体
* **属性**:
* what:消息标识
* arg1/arg2:整型参数
* obj:对象参数
* callback:Runnable回调
### Handler工作流程
```
发送消息流程:
Handler.sendMessage() → MessageQueue.enqueueMessage() → 消息入队
处理消息流程:
Looper.loop() → MessageQueue.next() → Handler.dispatchMessage() → Handler.handleMessage()
```
### 代码示例
```java
// 主线程Handler
Handler mainHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
// 处理消息,更新UI
}
};
// 子线程Handler
new Thread(() -> {
Looper.prepare();
Handler threadHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// 处理消息
}
};
Looper.loop();
}).start();
```
### Handler内存泄漏问题
**原因**:
* 非静态内部类持有外部Activity引用
* 延迟消息导致Activity无法被回收
**解决方案**:
1. 使用静态内部类 + WeakReference
2. 在Activity销毁时移除所有消息
3. 使用Handler的removeCallbacksAndMessages(null)
### 面试要点
* 主线程Looper在ActivityThread.main()中创建
* Handler.post()和sendMessage()的区别
* Message.obtain()复用消息对象,避免内存分配
* IdleHandler在消息队列空闲时执行
服务端 · 3月7日 12:13
Android中Jetpack组件有哪些,它们的作用是什么?Jetpack是Google推出的一套Android开发组件库,旨在帮助开发者遵循最佳实践、减少样板代码,并编写可在各种Android版本和设备上一致运行的代码。
### Jetpack组件分类
#### 1. 架构组件(Architecture Components)
##### ViewModel
```kotlin
class MyViewModel : ViewModel() {
private val _data = MutableLiveData<String>()
val data: LiveData<String> = _data
fun loadData() {
// 配置变更时数据不会丢失
_data.value = "Loaded"
}
}
```
* **作用**:管理UI相关的数据,生命周期感知
* **特点**:配置变更(如旋转屏幕)时数据保留
##### LiveData
```kotlin
viewModel.data.observe(this) { value ->
// 自动处理生命周期,避免内存泄漏
textView.text = value
}
```
* **作用**:可观察的数据持有者,生命周期感知
* **特点**:自动清理,避免内存泄漏
##### Room
```kotlin
@Entity
data class User(@PrimaryKey val id: Int, val name: String)
@Dao
interface UserDao {
@Query("SELECT * FROM user")
fun getAll(): LiveData<List<User>>
@Insert
fun insert(user: User)
}
```
* **作用**:SQLite的抽象层,简化数据库操作
* **特点**:编译时SQL检查,支持LiveData返回
##### DataBinding
```xml
<TextView android:text="@{viewModel.userName}" />
```
* **作用**:将布局中的UI组件与数据源绑定
* **特点**:减少findViewById,自动更新UI
##### Navigation
```kotlin
// 管理Fragment跳转和返回栈
findNavController().navigate(R.id.action_detail)
```
* **作用**:管理应用内导航
* **特点**:可视化导航图,支持Deep Link
##### WorkManager
```kotlin
val workRequest = OneTimeWorkRequestBuilder<MyWorker>().build()
WorkManager.getInstance(context).enqueue(workRequest)
```
* **作用**:管理可延迟的后台任务
* **特点**:保证任务执行,支持约束条件
#### 2. UI组件
##### Fragment
* **作用**:模块化的UI组件
* **特点**:与Activity解耦,复用性强
##### RecyclerView
* **作用**:高效显示大量数据列表
* **特点**:ViewHolder模式,四级缓存
##### ViewPager2
* **作用**:页面滑动切换
* **特点**:基于RecyclerView,支持垂直滑动
#### 3. 基础组件
##### AppCompat
* **作用**:向后兼容支持
* **特点**:使用新特性同时兼容旧版本
##### Android KTX
```kotlin
// Kotlin扩展函数
sharedPreferences.edit {
putString("key", "value")
}
```
* **作用**:Kotlin友好的API扩展
* **特点**:简化代码,更符合Kotlin习惯
##### Multidex
* **作用**:突破65536方法数限制
* **特点**:自动分包处理
#### 4. 行为组件
##### DownloadManager
* **作用**:管理长时间下载任务
* **特点**:系统级服务,断点续传
##### Media & Media3
* **作用**:音频视频播放
* **特点**:统一的媒体播放API
##### Notifications
* **作用**:创建和管理通知
* **特点**:兼容各版本通知特性
##### Permissions
```kotlin
// 简化权限请求
requestPermissionLauncher.launch(Manifest.permission.CAMERA)
```
* **作用**:简化运行时权限处理
### Jetpack优势
| 优势 | 说明 |
| ---------- | ---------------- |
| **向后兼容** | 组件支持Android 5.0+ |
| **生命周期感知** | 自动管理生命周期,避免内存泄漏 |
| **减少样板代码** | 简化常见开发任务 |
| **一致性** | 统一的API设计 |
| **测试友好** | 组件可独立测试 |
### MVVM架构实践
```
View (Activity/Fragment)
↓ 观察
ViewModel
↓ 调用
Repository
↓ 获取数据
Data Source (Room/Network)
```
### 面试要点
* 理解ViewModel的生命周期范围
* 掌握LiveData的转换操作(map、switchMap)
* 了解Room的数据库迁移
* 理解DataBinding的双向绑定
* 掌握Navigation的Deep Link使用
服务端 · 3月7日 12:13
Android中View的绘制流程是怎样的?View的绘制流程是Android UI系统的核心,理解绘制机制对于自定义View和性能优化至关重要。
### View绘制的三个阶段
View的绘制流程遵循**Measure → Layout → Draw**三个阶段:
```
View绘制流程:
measure() → onMeasure() → 测量View宽高
↓
layout() → onLayout() → 确定View位置
↓
draw() → onDraw() → 绘制View内容
```
### 第一阶段:Measure(测量)
#### 测量目的
确定View的宽度和高度(measuredWidth/measuredHeight)。
#### MeasureSpec
MeasureSpec是父View对子View的尺寸要求,由**模式**和**尺寸**组成:
| 模式 | 值 | 含义 |
| ----------- | ---------- | ----------------------- |
| EXACTLY | 0x40000000 | 精确值,如match\_parent或具体数值 |
| AT\_MOST | 0x80000000 | 最大值,如wrap\_content |
| UNSPECIFIED | 0x00000000 | 无限制,如ScrollView中的子View |
#### 测量流程
```java
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
// 根据模式计算实际尺寸
int width = calculateWidth(widthMode, widthSize);
int height = calculateHeight(heightMeasureSpec);
setMeasuredDimension(width, height);
}
```
### 第二阶段:Layout(布局)
#### 布局目的
确定View在父容器中的位置(left, top, right, bottom)。
#### 布局流程
```java
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
// 遍历子View,确定每个子View的位置
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
child.layout(childLeft, childTop, childRight, childBottom);
}
}
```
### 第三阶段:Draw(绘制)
#### 绘制步骤
draw()方法包含6个步骤:
```java
public void draw(Canvas canvas) {
// 1. 绘制背景
drawBackground(canvas);
// 2. 保存画布状态
saveCount = canvas.getSaveCount();
// 3. 绘制内容(子类实现)
onDraw(canvas);
// 4. 绘制子View
dispatchDraw(canvas);
// 5. 绘制装饰(如滚动条)
onDrawForeground(canvas);
// 6. 恢复画布状态
canvas.restoreToCount(saveCount);
}
```
### ViewGroup的绘制特点
ViewGroup继承自View,但增加了子View管理:
1. **测量阶段**:遍历测量所有子View
2. **布局阶段**:确定子View的位置
3. **绘制阶段**:dispatchDraw()绘制所有子View
### 绘制优化技巧
#### 1. 减少重绘
```java
// 使用invalidate(Rect)局部重绘
invalidate(0, 0, 100, 100);
// 使用ViewStub延迟加载
<ViewStub android:id="@+id/stub" android:layout="@layout/view" />
```
#### 2. 避免过度绘制
* 移除不必要的背景
* 使用clipRect减少绘制区域
* 使用GPU Overdraw调试工具检测
#### 3. 使用硬件加速
```xml
<application android:hardwareAccelerated="true">
```
### 自定义View要点
```java
public class CustomView extends View {
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 处理wrap_content
if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.AT_MOST) {
setMeasuredDimension(defaultWidth, defaultHeight);
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 绘制自定义内容
canvas.drawCircle(cx, cy, radius, paint);
}
}
```
### 面试要点
* 理解MeasureSpec的三种模式
* 掌握requestLayout()和invalidate()的区别
* 了解绘制流程的触发时机
* 掌握自定义View的基本步骤
* 理解硬件加速和软件绘制的区别
服务端 · 3月7日 12:12
Android中内存泄漏的常见场景有哪些,如何检测和避免?内存泄漏是指程序中已分配的内存由于某种原因未释放或无法释放,导致可用内存逐渐减少,最终可能引发OOM(Out Of Memory)崩溃。
### 常见内存泄漏场景
#### 1. 静态变量持有Activity/Context引用
```java
public class Singleton {
private static Singleton instance;
private Context context;
private Singleton(Context context) {
this.context = context; // 泄漏!持有Activity引用
}
// 解决方案:使用ApplicationContext
private Singleton(Context context) {
this.context = context.getApplicationContext();
}
}
```
#### 2. 非静态内部类/匿名内部类
```java
public class MainActivity extends Activity {
private Handler handler = new Handler() { // 非静态内部类
@Override
public void handleMessage(Message msg) {
// 持有外部Activity引用
}
};
}
// 解决方案:使用静态内部类 + WeakReference
private static class MyHandler extends Handler {
private WeakReference<Activity> weakRef;
MyHandler(Activity activity) {
weakRef = new WeakReference<>(activity);
}
}
```
#### 3. 未取消注册的监听器和广播
```java
// 内存泄漏示例
registerReceiver(receiver, filter);
// 忘记在onDestroy中unregisterReceiver
// 解决方案
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);
}
```
#### 4. 资源未关闭
* 数据库Cursor未关闭
* IO流未关闭
* Bitmap未回收
#### 5. 集合中的对象引用
```java
static List<Activity> activityList = new ArrayList<>();
// 添加Activity但不移除
activityList.add(activity);
```
### 内存泄漏检测工具
#### 1. Android Studio Memory Profiler
* 实时监控内存分配
* 堆转储(Heap Dump)分析
* 查看对象引用链
#### 2. LeakCanary
```groovy
dependencies {
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.x'
}
```
* 自动检测内存泄漏
* 生成泄漏引用链
* 通知提示泄漏信息
#### 3. MAT(Memory Analyzer Tool)
* 分析hprof文件
* 查找支配树(Dominator Tree)
* 识别泄漏嫌疑对象
### 内存泄漏避免策略
#### 1. 使用ApplicationContext
```java
// 当不需要Activity特性时
Intent intent = new Intent(getApplicationContext(), Target.class);
```
#### 2. 及时释放资源
```java
@Override
protected void onDestroy() {
super.onDestroy();
// 移除Handler消息和回调
handler.removeCallbacksAndMessages(null);
// 取消网络请求
call.cancel();
// 注销监听器
sensorManager.unregisterListener(listener);
}
```
#### 3. 使用WeakReference
```java
private static class MyAsyncTask extends AsyncTask<Void, Void, Void> {
private WeakReference<Activity> weakActivity;
MyAsyncTask(Activity activity) {
weakActivity = new WeakReference<>(activity);
}
@Override
protected Void doInBackground(Void... voids) {
// 后台任务
return null;
}
@Override
protected void onPostExecute(Void result) {
Activity activity = weakActivity.get();
if (activity != null && !activity.isFinishing()) {
// 更新UI
}
}
}
```
#### 4. 使用Lifecycle组件
```java
class MyObserver implements DefaultLifecycleObserver {
@Override
public void onDestroy(LifecycleOwner owner) {
// 自动清理
}
}
```
### 面试要点
* 理解Java内存模型和GC机制
* 掌握引用类型:强引用、软引用、弱引用、虚引用
* 熟悉常见泄漏场景和解决方案
* 能够使用工具分析和定位泄漏
* 了解Android内存优化最佳实践
服务端 · 3月7日 12:12
Android中如何进行性能优化,有哪些常用工具?性能优化是Android开发的核心技能,涉及内存、UI、网络、电量等多个维度。
### 1. 内存优化
#### 内存泄漏检测
* **LeakCanary**:自动检测内存泄漏
* **Android Profiler**:实时监控内存分配
* **MAT**:分析hprof文件,查找支配树
#### 内存优化策略
```kotlin
// 1. 使用SparseArray替代HashMap<Integer, Object>
val sparseArray = SparseArray<String>()
// 2. 图片内存优化
val options = BitmapFactory.Options().apply {
inSampleSize = 2 // 缩放采样
inBitmap = reusableBitmap // Bitmap复用
}
// 3. 使用LRU缓存
val cache = LruCache<String, Bitmap>(maxMemory / 8)
```
#### 大图优化
* 使用inSampleSize压缩
* 使用WebP格式
* 使用图片加载库(Glide、Picasso、Coil)
### 2. UI渲染优化
#### 布局优化
```xml
<!-- 1. 减少布局层级 -->
<merge> <!-- 减少一层ViewGroup -->
<include> <!-- 复用布局 -->
<ViewStub> <!-- 延迟加载 -->
```
#### 避免过度绘制
```kotlin
// 1. 移除不必要的背景
window.setBackgroundDrawable(null)
// 2. 使用clipRect减少绘制区域
canvas.clipRect(left, top, right, bottom)
```
#### 列表优化
```kotlin
// RecyclerView优化
recyclerView.setHasFixedSize(true)
recyclerView.setItemViewCacheSize(20)
recyclerView.setRecycledViewPool(pool)
```
### 3. 网络优化
#### 请求优化
```kotlin
// 1. 使用连接池
okHttpClient.connectionPool(ConnectionPool(5, 5, TimeUnit.MINUTES))
// 2. 启用Gzip压缩
okHttpClient.addInterceptor(GzipInterceptor())
// 3. 合理设置超时
okHttpClient.connectTimeout(10, TimeUnit.SECONDS)
```
#### 数据缓存
```kotlin
// 1. 使用Cache-Control
@Headers("Cache-Control: max-age=3600")
// 2. 本地缓存策略
val cache = Cache(cacheDir, 10 * 1024 * 1024) // 10MB
```
### 4. 电量优化
#### Doze模式和App Standby
* 理解系统省电机制
* 使用高优先级FCM消息
* 批量处理后台任务
#### 后台任务优化
```kotlin
// 使用WorkManager替代后台Service
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresBatteryNotLow(true)
.build()
val workRequest = PeriodicWorkRequestBuilder<SyncWorker>(1, TimeUnit.HOURS)
.setConstraints(constraints)
.build()
```
#### 定位优化
```kotlin
// 使用平衡精度模式
locationRequest.priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY
// 及时移除定位更新
fusedLocationClient.removeLocationUpdates(callback)
```
### 5. 包体积优化
#### 资源优化
```groovy
android {
// 1. 移除无用资源
lintOptions {
checkReleaseBuilds false
}
// 2. 资源压缩
shrinkResources true
minifyEnabled true
// 3. 只保留特定语言
resConfigs "zh", "en"
}
```
#### 代码优化
```groovy
// 1. 使用ProGuard/R8混淆
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
// 2. 动态功能模块
android {
dynamicFeatures = [':feature1', ':feature2']
}
```
### 6. 启动优化
* 异步初始化
* 延迟加载非必要组件
* 使用SplashScreen API
### 7. 常用性能分析工具
| 工具 | 用途 | 使用场景 |
| --------------------- | ----------- | --------- |
| **Android Profiler** | CPU/内存/网络监控 | 实时监控应用性能 |
| **Systrace** | 系统级性能分析 | 分析帧率、启动时间 |
| **Layout Inspector** | 布局层级分析 | 优化布局嵌套 |
| **GPU Overdraw** | 过度绘制检测 | 优化绘制性能 |
| **LeakCanary** | 内存泄漏检测 | 开发阶段检测泄漏 |
| **StrictMode** | 违规检测 | 检测主线程IO等 |
| **Battery Historian** | 电量分析 | 分析电量消耗 |
### 8. Systrace使用示例
```bash
# 抓取trace
python systrace.py -a com.example -o trace.html sched gfx view
# 分析重点
# 1. 查看帧率(Frame)是否掉帧
# 2. 查看UI线程是否阻塞
# 3. 查看GC频率
```
### 9. 性能优化检查清单
* [ ] 使用Release模式测试性能
* [ ] 在低端设备上验证
* [ ] 监控线上性能数据
* [ ] 定期进行性能回归测试
* [ ] 建立性能基准指标
### 面试要点
* 掌握内存优化的常见方法
* 理解UI渲染原理和优化手段
* 熟悉各种性能分析工具的使用
* 了解电量优化的最佳实践
* 掌握APK瘦身的技术方案
服务端 · 3月7日 12:11
Android中热修复技术的原理是什么,有哪些主流方案?热修复(HotFix)是一种在不重新发布应用的情况下,动态修复线上Bug的技术方案。
### 热修复的核心原理
#### 1. 类加载机制
Android使用PathClassLoader和DexClassLoader加载类:
* **PathClassLoader**:加载已安装APK的dex文件
* **DexClassLoader**:加载任意路径的dex文件
#### 2. 热修复的基本思路
```
原理:让类加载器优先加载修复后的类,覆盖有问题的类
实现方式:
1. 将修复代码打包成dex文件
2. 通过反射插入到dexElements数组前面
3. 类加载时优先找到修复类
```
### 主流热修复方案对比
| 方案 | 原理 | 优点 | 缺点 | 代表 |
| --------------- | --------------- | --------- | --------- | ------------- |
| **底层替换** | 替换ArtMethod结构体 | 即时生效,无需重启 | 兼容性差,稳定性低 | AndFix、Sophix |
| **类加载** | 修改dexElements数组 | 稳定性高,兼容性好 | 需要重启生效 | Tinker、QZone |
| **Instant Run** | 自定义ClassLoader | 开发调试方便 | 仅适用于开发 | Google官方 |
### 详细方案分析
#### 1. Tinker(微信)
```
原理:
1. 生成新旧APK的差分包(patch.dex)
2. 下载patch.dex到本地
3. 合并patch.dex和原APK的dex
4. 重启后通过修改dexElements加载新dex
特点:
- 支持类、资源、so库替换
- 需要重启应用生效
- 差分包小,下载快
```
#### 2. Sophix(阿里云)
```
原理:
1. 底层替换方案:替换ArtMethod的入口
2. 类加载方案:作为兜底方案
特点:
- 即时生效,无需重启
- 支持方法级修复
- 收费方案,稳定性好
```
#### 3. Robust(美团)
```
原理:
1. 编译期在每个方法插入逻辑
2. 运行时通过路由跳转到修复类
特点:
- 即时生效
- 包体积增加少
- 需要提前插入代码
```
### 类加载方案实现细节
#### Dex插桩核心代码
```java
public class HotFix {
public static void patch(Context context, File patchDexFile) {
try {
// 获取PathClassLoader
ClassLoader classLoader = context.getClassLoader();
// 获取pathList字段
Object pathList = getField(classLoader, "pathList");
// 获取dexElements字段
Object[] dexElements = (Object[]) getField(pathList, "dexElements");
// 创建新的dexElements(包含patch.dex)
Object[] newElements = makeDexElements(patchDexFile);
// 合并数组:patch.dex在前
Object[] combined = (Object[]) Array.newInstance(
dexElements.getClass().getComponentType(),
newElements.length + dexElements.length
);
System.arraycopy(newElements, 0, combined, 0, newElements.length);
System.arraycopy(dexElements, 0, combined, newElements.length, dexElements.length);
// 替换dexElements
setField(pathList, "dexElements", combined);
} catch (Exception e) {
e.printStackTrace();
}
}
}
```
### 热修复的限制
#### 1. 无法修复的情况
* AndroidManifest.xml的修改
* 新增四大组件
* 资源ID变化导致的资源引用错误
* 部分ROM的兼容性限制
#### 2. 安全风险
* 代码注入风险
* 需要校验patch签名
* 传输过程需要加密
### 面试要点
* 理解类加载机制和双亲委托模型
* 掌握dexElements插桩原理
* 了解各方案的优缺点和适用场景
* 理解热修复的局限性和安全风险
* 熟悉Tinker、Sophix等主流方案
服务端 · 3月7日 12:11
Android中Activity的生命周期有哪些方法,分别在什么情况下触发?## Android Activity生命周期详解
Activity生命周期是Android面试的核心考点,理解生命周期对开发稳定的应用至关重要。
### 完整生命周期方法
#### 1. onCreate()
- **触发时机**:Activity首次创建时
- **作用**:初始化UI、恢复状态、设置布局
- **注意**:此时Activity尚未可见
#### 2. onStart()
- **触发时机**:Activity即将可见时
- **作用**:注册广播、启动动画等轻量级初始化
- **注意**:Activity还未获得焦点
#### 3. onResume()
- **触发时机**:Activity获得焦点,可以与用户交互
- **作用**:启动相机、定位等需要焦点的操作
- **注意**:此时Activity位于前台
#### 4. onPause()
- **触发时机**:Activity失去焦点,但仍部分可见
- **作用**:保存关键数据、停止动画、释放资源
- **注意**:执行要快,否则会阻塞下一个Activity显示
#### 5. onStop()
- **触发时机**:Activity完全不可见
- **作用**:释放资源、注销广播、停止定位
- **注意**:可能被系统回收
#### 6. onDestroy()
- **触发时机**:Activity被销毁前
- **作用**:最终清理工作
- **注意**:区分正常销毁和配置变更导致的重建
#### 7. onRestart()
- **触发时机**:Activity从停止状态重新启动
- **作用**:恢复停止前的状态
### 典型场景生命周期流程
| 场景 | 生命周期流程 |
|------|-------------|
| 首次启动 | onCreate → onStart → onResume |
| 跳转到其他Activity | onPause → onStop |
| 返回原Activity | onRestart → onStart → onResume |
| 按Home键 | onPause → onStop |
| 屏幕旋转 | onPause → onStop → onDestroy → onCreate → onStart → onResume |
| 系统回收 | 直接调用onDestroy,无回调 |
### 面试要点
- 在onCreate和onRestoreInstanceState中恢复数据
- onPause中不要执行耗时操作
- 使用ViewModel避免配置变更导致的数据丢失
服务端 · 3月6日 23:09
Android中ANR是什么,如何定位和解决ANR问题?## Android ANR详解
ANR(Application Not Responding)是Android系统中当应用程序在特定时间内无法响应用户输入或广播时的错误状态。
### ANR的触发条件
| 类型 | 触发条件 | 时间限制 |
|------|---------|---------|
| 输入事件ANR | 按键或触摸事件未响应 | 5秒 |
| BroadcastReceiver ANR | onReceive()执行超时 | 前台10秒,后台60秒 |
| Service ANR | Service生命周期方法执行超时 | 20秒 |
| ContentProvider ANR | ContentProvider操作超时 | 10秒 |
### ANR产生的原因
#### 1. 主线程耗时操作
- 网络请求在主线程执行
- 大量数据库操作
- 复杂的计算任务
- 加载大文件或图片
#### 2. 死锁
- 主线程等待子线程释放锁
- 子线程又等待主线程释放锁
#### 3. 内存不足
- 系统资源紧张
- 频繁GC导致卡顿
#### 4. Binder通信超时
- 跨进程调用超时
- 服务端进程无响应
### ANR的定位方法
#### 1. 查看Logcat日志
```
E/ActivityManager: ANR in com.example.app
E/ActivityManager: Reason: Input dispatching timed out
```
#### 2. 分析traces.txt文件
```
/data/anr/traces.txt
```
包含:
- 所有线程的堆栈信息
- ANR发生的时间点
- 阻塞的代码位置
#### 3. 使用Android Studio Profiler
- CPU Profiler查看主线程状态
- 识别耗时方法
#### 4. StrictMode检测
```java
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyLog()
.build());
```
### ANR的解决方案
#### 1. 异步处理耗时操作
```java
// 使用AsyncTask(已废弃,建议使用其他方式)
// 使用线程池
ExecutorService executor = Executors.newFixedThreadPool(4);
executor.execute(() -> {
// 耗时操作
});
// 使用Kotlin协程
lifecycleScope.launch(Dispatchers.IO) {
// 耗时操作
}
```
#### 2. 使用HandlerThread
```java
HandlerThread handlerThread = new HandlerThread("background");
handlerThread.start();
Handler backgroundHandler = new Handler(handlerThread.getLooper());
```
#### 3. 优化数据库操作
- 使用事务批量操作
- 建立合适的索引
- 避免主线程查询大量数据
#### 4. 避免死锁
- 统一锁的获取顺序
- 使用tryLock()替代lock()
- 减少锁的持有时间
### 面试要点
- ANR是系统保护机制,不是崩溃
- traces.txt是定位ANR的关键
- 主线程不能执行耗时操作
- 使用Systrace分析性能问题
- 关注卡顿监控和线上ANR收集
服务端 · 3月6日 23:09