You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 03:34:55