Android Jetpack Compose:如何实现Composable的继承复用?
解决方案:Compose代码复用与顶层函数最佳实践
一、屏幕Composable的复用思路(替代继承)
Jetpack Compose基于函数式设计,不支持通过类继承复用Composable,但可以通过「组合」「提取通用逻辑」「规范接口」的方式实现复用:
1. 提取通用屏幕模板
把所有屏幕共有的结构(比如Scaffold、内边距、主题包裹)封装成基础Composable,其他屏幕直接组合调用:
@Composable fun BaseScreen( modifier: Modifier = Modifier, topBar: @Composable () -> Unit = {}, bottomBar: @Composable () -> Unit = {}, content: @Composable () -> Unit ) { Scaffold( modifier = modifier, topBar = topBar, bottomBar = bottomBar ) { paddingValues -> Box(modifier = Modifier.padding(paddingValues)) { content() } } }
然后在具体屏幕中使用:
@Composable fun Screen1(modifier: Modifier = Modifier) { BaseScreen(modifier = modifier) { Text(text = "hi") } } @Preview(showBackground = true) @Composable fun Screen1Preview() { Scanner1Theme { Screen1() } }
2. 封装通用状态/副作用逻辑
如果多个屏幕需要相同的状态处理(比如加载状态、权限判断),提取成独立的Composable:
@Composable fun ScreenWithLoading( isLoading: Boolean, content: @Composable () -> Unit ) { if (isLoading) { CircularProgressIndicator(modifier = Modifier.align(Alignment.Center)) } else { content() } }
在屏幕中直接组合:
@Composable fun Screen1(modifier: Modifier = Modifier, viewModel: Screen1ViewModel = viewModel()) { BaseScreen(modifier = modifier) { ScreenWithLoading(isLoading = viewModel.isLoading.value) { Text(text = "hi") } } }
3. 用接口统一屏幕规范
如果需要统一管理屏幕的元数据(路由、标题),可以定义接口:
interface ScreenSpec { val route: String val title: String @Composable fun Content(modifier: Modifier = Modifier) } object Screen1 : ScreenSpec { override val route = "screen1" override val title = "Screen 1" @Composable override fun Content(modifier: Modifier) { BaseScreen(modifier) { Text(text = title) } } }
导航或调用时直接使用Screen1.route和Screen1.Content(),统一管理所有屏幕属性。
二、SystemBroadcastReceiver这类顶层Composable的优化
你写的SystemBroadcastReceiver是Compose推荐的通用副作用封装方式(顶层函数),完全符合设计规范,还可以做以下优化:
1. 支持多Action监听
扩展成可同时监听多个系统广播:
@Composable fun SystemBroadcastReceiver( systemActions: List<String>, onSystemEvent: (intent: Intent?) -> Unit ) { val context = LocalContext.current val currentOnSystemEvent by rememberUpdatedState(onSystemEvent) DisposableEffect(context, systemActions) { val intentFilter = IntentFilter().apply { systemActions.forEach { addAction(it) } } val broadcast = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { currentOnSystemEvent(intent) } } context.registerReceiver(broadcast, intentFilter) onDispose { context.unregisterReceiver(broadcast) } } }
2. 封装特定场景的接收器
针对具体业务场景封装更易用的上层Composable,比如监听网络变化:
@Composable fun NetworkChangeReceiver(onNetworkChanged: (Boolean) -> Unit) { SystemBroadcastReceiver( systemActions = listOf(ConnectivityManager.CONNECTIVITY_ACTION) ) { intent -> val isConnected = intent?.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false)?.not() ?: false onNetworkChanged(isConnected) } }
在屏幕中调用时更简洁:
@Composable fun Screen1(modifier: Modifier = Modifier) { var isOnline by remember { mutableStateOf(true) } NetworkChangeReceiver { isConnected -> isOnline = isConnected } BaseScreen(modifier) { Text(text = if (isOnline) "Online" else "Offline") } }
内容的提问来源于stack exchange,提问作者Phillip Garza
相关产品推荐
相关产品推荐

