Android库网络请求后向应用传数据及关闭Compose UI方法咨询
解决方案
核心思路
由于库内的someData和ViewModel是internal(仅库内可见),不能直接跨模块暴露给应用层。我们需要通过公开的结果类型+回调机制实现数据传递,同时利用Compose状态控制库UI的显示/隐藏。
1. 库模块:定义公开的跨模块通信类型
先在库内创建对外可见的结果封装类,用来中转内部数据,避免暴露internal成员:
// 库模块 - 公开的结果密封类,用于跨模块传递状态 sealed class LibraryRequestResult { data class Success(val id: String, val name: String) : LibraryRequestResult() data class Error(val errorMsg: String) : LibraryRequestResult() object Cancelled : LibraryRequestResult() } // 可选:也可以定义公开的数据类,代替拆字段传递 // data class PublicSomeData(val id: String, val name: String)
2. 库模块:内部ViewModel处理请求并发送结果
库内的internal ViewModel负责网络请求,用StateFlow管理内部结果状态:
// 库模块 - internal ViewModel,仅库内可访问 internal class LibraryViewModel : ViewModel() { private val _internalResult = MutableStateFlow<InternalResult>(InternalResult.Idle) val internalResult = _internalResult.asStateFlow() // 库内专用的结果密封类,internal修饰 internal sealed class InternalResult { object Idle : InternalResult() data class DataLoaded(val data: someData) : InternalResult() data class RequestFailed(val msg: String) : InternalResult() object UserCancelled : InternalResult() } // 发起网络请求(Retrofit+Moshi逻辑) fun startNetworkRequest() { viewModelScope.launch { try { val apiResponse = yourRetrofitService.fetchData() val parsedData = apiResponse.body() ?: throw IllegalStateException("空响应") _internalResult.value = InternalResult.DataLoaded(parsedData) } catch (e: Exception) { _internalResult.value = InternalResult.RequestFailed(e.message ?: "请求失败") } } } // 用户主动取消时调用 fun onCancel() { _internalResult.value = InternalResult.UserCancelled } }
3. 库模块:提供公开的Compose入口
封装库的UI和ViewModel逻辑,对外仅暴露一个接收结果回调的Composable函数:
// 库模块 - 公开的Compose入口,应用层通过这个函数启动库UI @Composable fun LibraryRequestUI(onResult: (LibraryRequestResult) -> Unit) { val libraryViewModel = viewModel<LibraryViewModel>() // 监听内部ViewModel的结果流,转换为公开类型后传给应用 LaunchedEffect(libraryViewModel) { libraryViewModel.internalResult.collect { internalState -> when (internalState) { is LibraryViewModel.InternalResult.DataLoaded -> { // 将internal的someData转换为公开结果 onResult(LibraryRequestResult.Success(internalState.data.id, internalState.data.name)) } is LibraryViewModel.InternalResult.RequestFailed -> { onResult(LibraryRequestResult.Error(internalState.msg)) } LibraryViewModel.InternalResult.UserCancelled -> { onResult(LibraryRequestResult.Cancelled) } else -> {} // 忽略Idle状态 } } } // 库的Compose UI实现 Column( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { Button(onClick = libraryViewModel::startNetworkRequest) { Text("发起请求") } Spacer(modifier = Modifier.height(16.dp)) Button(onClick = libraryViewModel::onCancel) { Text("取消") } } }
4. 应用模块:调用库并处理结果
应用层通过状态变量控制库UI的显示,在回调中接收结果、关闭库UI并传递给应用ViewModel:
// 应用模块 - 主界面Composable @Composable fun AppMainScreen() { var showLibraryUI by remember { mutableStateOf(false) } val appViewModel = viewModel<AppViewModel>() Column(modifier = Modifier.fillMaxSize(), padding = PaddingValues(16.dp)) { Button(onClick = { showLibraryUI = true }) { Text("启动库请求") } // 根据状态显示/隐藏库UI if (showLibraryUI) { LibraryRequestUI(onResult = { result -> // 关闭库UI showLibraryUI = false // 处理结果并传给应用ViewModel when (result) { is LibraryRequestResult.Success -> { appViewModel.processLibraryData(result.id, result.name) } is LibraryRequestResult.Error -> { appViewModel.showErrorToast(result.errorMsg) } LibraryRequestResult.Cancelled -> { // 处理用户取消逻辑 } } }) } } } // 应用模块 - 应用层ViewModel class AppViewModel : ViewModel() { fun processLibraryData(id: String, name: String) { // 业务逻辑:保存数据、更新UI状态等 } fun showErrorToast(msg: String) { // 错误提示逻辑 } }
关键说明
- 全程不暴露库内的
internal成员,保证模块封装性; - 用
StateFlow实现库内ViewModel的状态分发,结合LaunchedEffect在Compose中监听结果; - 应用层通过Boolean状态控制库UI的显示/隐藏,回调触发后自动关闭库界面。
内容的提问来源于stack exchange,提问作者tariqebadi
相关产品推荐
相关产品推荐

