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

Kotlin中跨Activity的不同Fragment间数据共享问题

跨Activity的Fragment间数据共享解决方案

针对你描述的场景——MainActivity下的三个Fragment(Home/Cart/User),点击HomeFragment的产品跳转到独立Activity的ProductDetailFragment,点击「加入购物车」后同步更新CartFragment的列表——以下是几种更可靠的解决方案,替代当前的SharedPreferences临时方案:

一、推荐方案:Application级ViewModel + LiveData

之前你用LiveData失败,大概率是因为使用了Activity级ViewModel,不同Activity的ViewModel实例相互独立,导致跨Activity无法共享数据。改用Application作为ViewModel的宿主,就能实现全局共享:

1. 创建全局CartViewModel

class CartViewModel(application: Application) : AndroidViewModel(application) {
    // 维护购物车中的产品slug列表(避免重复添加)
    private val _cartSlugs = MutableLiveData<MutableList<String>>(mutableListOf())
    val cartSlugs: LiveData<MutableList<String>> = _cartSlugs

    // 添加产品到购物车
    fun addToCart(slug: String) {
        val currentList = _cartSlugs.value ?: mutableListOf()
        if (!currentList.contains(slug)) {
            currentList.add(slug)
            _cartSlugs.postValue(currentList) // 线程安全更新数据
        }
    }

    // 可选:移除产品方法
    fun removeFromCart(slug: String) {
        val currentList = _cartSlugs.value ?: mutableListOf()
        currentList.remove(slug)
        _cartSlugs.postValue(currentList)
    }
}

2. 在ProductDetailFragment中调用添加逻辑

class ProductDetailFragment : Fragment() {
    // 获取Application级别的ViewModel实例
    private val cartViewModel: CartViewModel by viewModels({ requireActivity().application })

    // 「加入购物车」按钮点击事件
    private fun handleAddToCart(slug: String) {
        cartViewModel.addToCart(slug)
        Toast.makeText(context, "已加入购物车", Toast.LENGTH_SHORT).show()
    }
}

3. 在CartFragment中监听数据变化并更新UI

class CartFragment : Fragment() {
    private val cartViewModel: CartViewModel by viewModels({ requireActivity().application })
    private lateinit var productAdapter: ProductAdapter
    private val productList = mutableListOf<Product>()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        initGridLayout()

        // 监听购物车slug列表变化,同步拉取产品详情
        cartViewModel.cartSlugs.observe(viewLifecycleOwner) { slugs ->
            productList.clear()
            slugs.forEach { slug ->
                lifecycleScope.launch {
                    try {
                        // 调用你的Retrofit接口获取产品详情
                        val product = yourProductApi.getProductBySlug(slug)
                        productList.add(product)
                        productAdapter.notifyItemInserted(productList.size - 1)
                    } catch (e: Exception) {
                        Log.e("CartFragment", "拉取产品失败: ${e.message}")
                    }
                }
            }
            // 显示空购物车状态(如果需要)
            emptyCartView.visibility = if (slugs.isEmpty()) View.VISIBLE else View.GONE
        }
    }

    private fun initGridLayout() {
        productAdapter = ProductAdapter(productList)
        recyclerView.apply {
            layoutManager = GridLayoutManager(context, 2)
            adapter = productAdapter
        }
    }
}

二、进阶方案:DataStore替换SharedPreferences

DataStore是Google官方推荐的SharedPreferences替代方案,解决了SP的主线程阻塞、数据一致性差等问题,且支持Flow异步观察数据变化:

1. 创建CartDataStore封装类

class CartDataStore(private val context: Context) {
    // 初始化DataStore
    private val Context.dataStore by preferencesDataStore(name = "cart_store")
    private val CART_SLUGS = stringSetPreferencesKey("cart_slugs")

    // 添加slug到购物车
    suspend fun addSlug(slug: String) {
        context.dataStore.edit { prefs ->
            val currentSlugs = prefs[CART_SLUGS] ?: emptySet()
            prefs[CART_SLUGS] = currentSlugs + slug
        }
    }

    // 获取购物车slug列表(返回Flow,支持实时监听)
    fun getCartSlugs(): Flow<Set<String>> {
        return context.dataStore.data
            .map { prefs -> prefs[CART_SLUGS] ?: emptySet() }
    }

    // 可选:移除slug方法
    suspend fun removeSlug(slug: String) {
        context.dataStore.edit { prefs ->
            val currentSlugs = prefs[CART_SLUGS] ?: emptySet()
            prefs[CART_SLUGS] = currentSlugs - slug
        }
    }
}

2. 在Application中初始化单例

class MyApp : Application() {
    lateinit var cartDataStore: CartDataStore
        private set

    override fun onCreate() {
        super.onCreate()
        cartDataStore = CartDataStore(this)
    }
}

3. 在ProductDetailFragment中使用

class ProductDetailFragment : Fragment() {
    private val cartDataStore by lazy {
        (requireContext().applicationContext as MyApp).cartDataStore
    }

    private fun handleAddToCart(slug: String) {
        lifecycleScope.launch {
            cartDataStore.addSlug(slug)
            Toast.makeText(context, "已加入购物车", Toast.LENGTH_SHORT).show()
        }
    }
}

4. 在CartFragment中监听数据

class CartFragment : Fragment() {
    private val cartDataStore by lazy {
        (requireContext().applicationContext as MyApp).cartDataStore
    }
    private lateinit var productAdapter: ProductAdapter
    private val productList = mutableListOf<Product>()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        initGridLayout()

        // 收集Flow数据变化
        lifecycleScope.launch {
            cartDataStore.getCartSlugs().collect { slugs ->
                productList.clear()
                slugs.forEach { slug ->
                    launch {
                        try {
                            val product = yourProductApi.getProductBySlug(slug)
                            productList.add(product)
                            productAdapter.notifyItemInserted(productList.size - 1)
                        } catch (e: Exception) {
                            Log.e("CartFragment", "拉取产品失败: ${e.message}")
                        }
                    }
                }
                emptyCartView.visibility = if (slugs.isEmpty()) View.VISIBLE else View.GONE
            }
        }
    }
}

方案对比

方案优点缺点
Application级ViewModel实现简单、实时响应、生命周期感知进程被杀后数据丢失(需结合持久化)
DataStore异步安全、持久化、类型安全代码量略多,需熟悉Flow协程
当前SharedPreferences上手快主线程阻塞、数据一致性差、易出现ANR

如果需要持久化ViewModel的数据,可以结合DataStore,在ViewModel初始化时从DataStore读取历史数据,更新LiveData,这样进程重启后购物车数据不会丢失。

内容的提问来源于stack exchange,提问作者Kaan Düzbastılar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 04:01:01