Android中高级面试(三):架构组件与性能优化实战

55 阅读4分钟

原文:xuanhu.info/projects/it…

Android中高级面试(三):架构组件与性能优化实战

🔍 一、ViewModel 的生存周期控制机制

1.1 核心设计思想


// ViewModelProvider 初始化示例

val viewModel = ViewModelProvider(

this,

object : ViewModelProvider.Factory {

override fun <T : ViewModel> create(modelClass: Class<T>): T {

return MyViewModel(repository) as T

}

}

).get(MyViewModel::class.java)


// ViewModelStore 关键源码(简化版)

public class ViewModelStore {

private final HashMap<String, ViewModel> mMap = new HashMap<>();

  


public final void put(String key, ViewModel viewModel) {

ViewModel oldViewModel = mMap.put(key, viewModel);

if (oldViewModel != null) {

oldViewModel.onCleared(); // 触发旧ViewModel清理

}

}

}

📌 设计要点

  1. ViewModelStoreOwner接口(如Activity/Fragment)持有ViewModelStore实例

  2. 屏幕旋转时Activity重建但ViewModelStore被保留

  3. onCleared()触发时机:当宿主永久销毁时(非配置变更)

1.2 生命周期感知原理


sequenceDiagram

participant Activity

participant ViewModelStore

participant ViewModel

Activity->>ViewModelStore: onRetainNonConfigurationInstance()

ViewModelStore-->>Activity: 保存ViewModelStore引用

Activity->>ViewModel: 销毁(配置不变)

ViewModelStore->>ViewModel: 保留实例

Activity->>ViewModelStore: 重建后获取实例

⚡ 二、LiveData 的响应式编程实践

2.1 事件总线替代方案


class EventLiveData<T> : MutableLiveData<T>() {

private val pendingMap = ConcurrentHashMap<Int, Boolean>()

  


@MainThread

override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {

val wrapper = ObserverWrapper(observer)

super.observe(owner, wrapper)

}

  


inner class ObserverWrapper(val observer: Observer<in T>) : Observer<T> {

override fun onChanged(t: T?) {

if (pendingMap.hashCode() == false) return

observer.onChanged(t)

}

}

}

🚀 解决痛点

  • 避免粘性事件导致的重复触发

  • 线程安全的观察者管理

2.2 结合Kotlin Flow的高级用法


fun <T> LiveData<T>.asFlow(): Flow<T> = callbackFlow {

val observer = Observer<T> { value ->

trySend(value).isSuccess // 将LiveData值发送到Flow

}

observeForever(observer)

awaitClose { removeObserver(observer) }

}

  


// 使用示例

viewModel.data.asFlow()

.filter { it.isValid() }

.map { it.transform() }

.launchIn(viewModelScope)

💾 三、Room数据库的进阶优化

3.1 索引优化实战


@Entity(indices = [Index(value = ["last_name", "address"], unique = true)])

data class User(

@PrimaryKey val id: Int,

@ColumnInfo(name = "first_name") val firstName: String?,

@ColumnInfo(name = "last_name") val lastName: String?,

@ColumnInfo(name = "address") val address: String?

)

  


// 多表联合查询优化

@Query("SELECT * FROM user INNER JOIN book ON user.id = book.user_id WHERE book.type = :type")

fun getUsersWithBooks(type: BookType): Flowable<List<UserWithBooks>>

3.2 数据库迁移策略


val MIGRATION_1_2 = object : Migration(1, 2) {

override fun migrate(database: SupportSQLiteDatabase) {

// 添加新表

database.execSQL("CREATE TABLE IF NOT EXISTS `address` (`id` INTEGER PRIMARY KEY, `street` TEXT)")

// 修改旧表结构

database.execSQL("ALTER TABLE user ADD COLUMN phone TEXT DEFAULT ''")

}

}

  


Room.databaseBuilder(context, AppDatabase::class.java, "sample.db")

.addMigrations(MIGRATION_1_2)

.addCallback(object : RoomDatabase.Callback() {

override fun onCreate(db: SupportSQLiteDatabase) {

// 初始化数据

}

})

.build()

🧪 四、内存泄漏检测与治理

4.1 LeakCanary 2.0定制化


class CustomLeakCanary : AbstractLeakCanary() {

override fun onLeakFound(heapAnalysis: HeapAnalysis) {

// 自定义泄漏上报逻辑

FirebaseCrashlytics.getInstance().log("Memory leak detected: ${heapAnalysis.signature}")

}

}

  


// 配置示例

LeakCanary.config = LeakCanary.config.copy(

dumpHeap = BuildConfig.DEBUG, // 仅Debug模式检测

retainedVisibleThreshold = 3, // 泄漏阈值

onHeapAnalyzedListener = CustomLeakCanary()

)

4.2 匿名内部类泄漏场景


// 错误示例:匿名Handler导致Activity泄漏

public class MainActivity extends Activity {

private final Handler handler = new Handler() {

@Override

public void handleMessage(Message msg) {

// 持有Activity隐式引用

}

};

}

  


// 修复方案:静态内部类+弱引用

private static class SafeHandler extends Handler {

private final WeakReference<Activity> mActivityRef;

  


SafeHandler(Activity activity) {

mActivityRef = new WeakReference<>(activity);

}

  


@Override

public void handleMessage(Message msg) {

Activity activity = mActivityRef.get();

if (activity == null || activity.isFinishing()) return;

// 安全操作

}

}

🚀 五、Kotlin协程在MVVM中的高阶应用

5.1 结构化并发实践


class ProductViewModel : ViewModel() {

private val _products = MutableStateFlow<List<Product>>(emptyList())

val products: StateFlow<List<Product>> = _products

  


init {

viewModelScope.launch(Dispatchers.IO + CoroutineExceptionHandler { _, e ->

Log.e("CoroutineError", e.message)

}) {

val productJob = async { fetchProducts() }

val promoJob = async { fetchPromotions() }

  


// 合并网络请求结果

_products.value = productJob.await()

.combinePromotions(promoJob.await())

}

}

  


private suspend fun fetchProducts() = withContext(Dispatchers.IO) {

repository.getProducts().map { it.toDomainModel() }

}

}

5.2 Flow状态管理策略


sealed interface UiState<out T> {

object Loading : UiState<Nothing>

data class Success<T>(val data: T) : UiState<T>

data class Error(val exception: Throwable) : UiState<Nothing>

}

  


fun <T> Flow<T>.asStateFlow(): StateFlow<UiState<T>> {

return this.map<T, UiState<T>> { UiState.Success(it) }

.onStart { emit(UiState.Loading) }

.catch { e -> emit(UiState.Error(e)) }

.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), UiState.Loading)

}

📊 六、性能优化监控体系

6.1 帧率监控方案


class FrameMonitor : Choreographer.FrameCallback {

private var lastFrameTime = 0L

private val frameInterval = 1000L / 60 // 16ms/帧

  


override fun doFrame(frameTimeNanos: Long) {

val currentTime = System.currentTimeMillis()

if (lastFrameTime > 0) {

val duration = currentTime - lastFrameTime

if (duration > frameInterval * 2) {

Log.w("FrameDrop", "丢帧 detected: ${duration - frameInterval}ms")

}

}

lastFrameTime = currentTime

Choreographer.getInstance().postFrameCallback(this)

}

}

  


// 在Application中启动

Choreographer.getInstance().postFrameCallback(FrameMonitor())

6.2 内存抖动检测


Debug.startAllocCounting(); // 开启分配计数

  


// 在关键操作后检测

void checkAllocations() {

long allocCount = Debug.getGlobalAllocCount();

long allocSize = Debug.getGlobalAllocSize();

if (allocCount > 1000 || allocSize > 102400) { // 阈值设置

Log.e("MemoryChurn", "内存抖动警告: " + allocCount + "次分配, " + allocSize + "字节");

}

Debug.resetAllocCount(); // 重置计数器

}

🌐 七、跨进程通信优化方案

7.1 Binder连接池设计


public class BinderPool {

private static final String TAG = "BinderPool";

private Context mContext;

private IBinderPool mBinderPool;

private static volatile BinderPool sInstance;

  


private BinderPool(Context context) {

mContext = context.getApplicationContext();

connectBinderPoolService();

}

  


private synchronized void connectBinderPoolService() {

Intent service = new Intent(mContext, BinderPoolService.class);

mContext.bindService(service, mConnection, Context.BIND_AUTO_CREATE);

}

  


public IBinder queryBinder(int binderCode) {

try {

return mBinderPool.queryBinder(binderCode);

} catch (RemoteException e) {

e.printStackTrace();

}

return null;

}

}

7.2 AIDL接口版本兼容方案


// 接口定义时预留扩展方法

interface IRemoteService {

void basicMethod(int param) throws RemoteException;

void apiVersion2() throws RemoteException; // V2新增

void apiVersion3() throws RemoteException; // V3新增

}

  


// 服务端实现

private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {

@Override

public void basicMethod(int param) {

// 基础实现

}

  


@Override

public void apiVersion2() throws RemoteException {

// V2功能实现

}

  


@Override

public void apiVersion3() throws RemoteException {

throw new RemoteException("Method not implemented"); // 未实现方法

}

};

📈 八、启动速度优化体系

8.1 异步初始化框架


object AppInitManager {

private val ioDispatcher = Dispatchers.IO.limitedParallelism(4)

private val tasks = mutableListOf<InitTask>()

  


fun addTask(task: InitTask) {

tasks.add(task)

}

  


fun start(scope: CoroutineScope) {

tasks.map { task ->

scope.launch(ioDispatcher) {

val start = SystemClock.uptimeMillis()

task.execute()

Log.d("InitTask", "${task.name} took ${SystemClock.uptimeMillis() - start}ms")

}

}

}

}

  


// 任务定义

abstract class InitTask(val name: String) {

abstract fun execute()

}

8.2 ClassLoader优化策略


// 自定义ClassLoader实现

public class HotClassLoader extends BaseDexClassLoader {

private final Map<String, Class<?>> loadedClasses = new ConcurrentHashMap<>();

  


public HotClassLoader(String dexPath, ClassLoader parent) {

super(dexPath, null, null, parent);

}

  


@Override

protected Class<?> findClass(String name) throws ClassNotFoundException {

Class<?> clazz = loadedClasses.get(name);

if (clazz != null) return clazz;

  


// 从Dex文件加载

clazz = super.findClass(name);

loadedClasses.put(name, clazz);

return clazz;

}

}

🧠 九、Jetpack Compose 性能调优

9.1 重组范围控制


@Composable

fun UserProfile(user: User) {

Column {

// 使用derivedStateOf减少重组

val username by remember { derivedStateOf { user.name.uppercase() } }

Text(text = username, modifier = Modifier.clickable { /*...*/ })

  


// 使用key控制列表项重组

LazyColumn {

items(users, key = { it.id }) { user ->

UserItem(user)

}

}

}

}

9.2 长列表优化技巧


@Composable

fun LargeList(items: List<Item>) {

LazyColumn {

itemsIndexed(

items = items,

key = { _, item -> item.id } // 关键:设置唯一key

) { index, item ->

if (index % 50 == 0) {

// 每50项添加一个StickyHeader

stickyHeader { SectionHeader(item.category) }

}

ItemRow(item)

}

}

}

🧩 十、动态化框架原理剖析

10.1 类加载双亲委派突破


public class HotFixClassLoader extends ClassLoader {

private final ClassLoader originClassLoader;

private final DexClassLoader patchClassLoader;

  


public HotFixClassLoader(ClassLoader parent, String dexPath) {

super(parent);

this.originClassLoader = parent;

this.patchClassLoader = new DexClassLoader(

dexPath, null, null, parent);

}

  


@Override

protected Class<?> findClass(String name) throws ClassNotFoundException {

try {

// 优先从补丁包加载

return patchClassLoader.loadClass(name);

} catch (ClassNotFoundException e) {

// 回退到原始ClassLoader

return originClassLoader.loadClass(name);

}

}

}

10.2 资源热更新方案


public class HotResource {

public static void inject(Activity activity, String apkPath) {

try {

// 获取AssetManager实例

AssetManager assetManager = AssetManager.class.newInstance();

Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);

addAssetPath.invoke(assetManager, apkPath);

  


// 替换Activity的Resources

Resources superRes = activity.getResources();

Resources newResources = new Resources(assetManager,

superRes.getDisplayMetrics(), superRes.getConfiguration());

Field field = activity.getClass().getDeclaredField("mResources");

field.setAccessible(true);

field.set(activity, newResources);

} catch (Exception e) {

e.printStackTrace();

}

}

}

🎯 总结

面试要点提炼

  1. 架构设计深度:理解Jetpack组件在MVVM中的角色分工及数据流向

  2. 性能优化闭环:从问题定位(内存泄漏/卡顿)到解决方案的完整链路

  3. 跨进程通信本质:掌握Binder机制及AIDL接口的版本演进策略

  4. 协程高阶应用:结构化并发在复杂业务场景下的最佳实践

  5. 动态化前沿技术:热修复与资源更新的底层原理及兼容性处理

💡 提示:面试中常考场景——当面试官询问“如何设计一个稳定的长任务管理框架”时,可结合ViewModel+CoroutineScope+SupervisorJob的设计模式,配合自定义异常处理策略进行阐述。

原文:xuanhu.info/projects/it…