如何将JSON文件读取的数据传递至其他Composable函数或主Activity?
解决方案
下面提供几种实用方式,帮你在多个Composable组件或主Activity中共享quotes数据:
1. 状态提升(Jetpack Compose官方推荐)
把quotes的状态从MyScreen提升到父组件(比如MainActivity或上层Composable),通过回调传递加载完成的数据,再将数据作为参数分发给所有需要使用的子组件。这种方式遵循Composable的单向数据流原则,状态控制权统一在父组件。
修改后代码示例:
MainActivity
class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { // 将状态提升到这里管理 var quotes by remember { mutableStateOf<List<Quotes>>(emptyList()) } // 传递回调给MyScreen,接收加载完成的数据 MyScreen(context = this) { loadedQuotes -> quotes = loadedQuotes } // 其他需要使用quotes的Composable QuoteDisplayComposable(quotes = quotes) } } }
MyScreen.kt
@Composable fun MyScreen( context: Context, onQuotesLoaded: (List<Quotes>) -> Unit // 回调函数传递数据 ) { LaunchedEffect(context) { val loadedQuotes = readJsonFromAssets(context, "quotes.json") onQuotesLoaded(loadedQuotes) } } suspend fun readJsonFromAssets(context: Context, fileName: String): List<Quotes> { return withContext(Dispatchers.IO) { val jsonString = context.assets.open(fileName).bufferedReader().use { it.readText() } val gson = Gson() gson.fromJson(jsonString, Array<Quotes>::class.java).toList() } }
使用数据的子Composable
@Composable fun QuoteDisplayComposable(quotes: List<Quotes>) { if (quotes.isNotEmpty()) { Column { quotes.forEach { quote -> Text(text = quote.content, modifier = Modifier.padding(8.dp)) } } } else { Text(text = "加载中...") } }
2. 用ViewModel管理共享数据
ViewModel的生命周期独立于Composable重组,还能避免屏幕旋转等配置变更导致的数据丢失,适合在多个组件间共享数据。把数据加载逻辑放到ViewModel里,所有需要数据的组件直接获取ViewModel实例即可。
代码示例:
QuotesViewModel.kt
class QuotesViewModel : ViewModel() { // 用StateFlow存储数据,支持监听变化 private val _quotes = MutableStateFlow<List<Quotes>>(emptyList()) val quotes: StateFlow<List<Quotes>> = _quotes.asStateFlow() fun loadQuotes(context: Context) { viewModelScope.launch { val loadedQuotes = readJsonFromAssets(context, "quotes.json") _quotes.value = loadedQuotes } } } // 保留原有的读取函数 suspend fun readJsonFromAssets(context: Context, fileName: String): List<Quotes> { return withContext(Dispatchers.IO) { val jsonString = context.assets.open(fileName).bufferedReader().use { it.readText() } val gson = Gson() gson.fromJson(jsonString, Array<Quotes>::class.java).toList() } }
MyScreen.kt
@Composable fun MyScreen( context: Context, viewModel: QuotesViewModel = viewModel() // 获取ViewModel实例 ) { LaunchedEffect(context) { viewModel.loadQuotes(context) } }
其他Composable中使用
@Composable fun QuoteDisplayComposable(viewModel: QuotesViewModel = viewModel()) { // 收集StateFlow数据转为Composable状态 val quotes by viewModel.quotes.collectAsState() if (quotes.isNotEmpty()) { Column { quotes.forEach { quote -> Text(text = quote.content, modifier = Modifier.padding(8.dp)) } } } else { Text(text = "加载中...") } }
MainActivity中访问数据
class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val viewModel = ViewModelProvider(this)[QuotesViewModel::class.java] // 监听数据变化 lifecycleScope.launch { viewModel.quotes.collect { quotes -> Log.d("MainActivity", "已加载${quotes.size}条语录") } } setContent { MyScreen(context = this) QuoteDisplayComposable() } } }
3. 单例对象(仅适合简单小型项目)
如果是小型测试项目,可以用单例对象存储数据,但要注意线程安全和内存泄漏问题,不推荐在复杂项目中使用。
代码示例:
QuotesManager.kt
object QuotesManager { var quotes: List<Quotes> = emptyList() private set suspend fun loadQuotes(context: Context) { quotes = readJsonFromAssets(context, "quotes.json") } } // 读取函数不变 suspend fun readJsonFromAssets(context: Context, fileName: String): List<Quotes> { return withContext(Dispatchers.IO) { val jsonString = context.assets.open(fileName).bufferedReader().use { it.readText() } val gson = Gson() gson.fromJson(jsonString, Array<Quotes>::class.java).toList() } }
MyScreen.kt
@Composable fun MyScreen(context: Context) { LaunchedEffect(context) { QuotesManager.loadQuotes(context) } }
其他组件访问
// 其他Composable @Composable fun QuoteDisplayComposable() { val quotes = QuotesManager.quotes if (quotes.isNotEmpty()) { Column { quotes.forEach { quote -> Text(text = quote.content, modifier = Modifier.padding(8.dp)) } } } } // MainActivity中访问 class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { MyScreen(context = this) QuoteDisplayComposable() } lifecycleScope.launch { // 等待数据加载完成(实际项目建议用回调/Flow监听,不要用delay) delay(200) Log.d("MainActivity", "语录数量:${QuotesManager.quotes.size}") } } }
内容的提问来源于stack exchange,提问作者Raj
相关产品推荐
相关产品推荐

