如何借助Shared ViewModel在Android多Fragment间共享数据并同步至Firebase
1. 创建Shared ViewModel
定义一个继承自ViewModel的类,用MutableLiveData存储需要共享的用户数据,同时提供更新数据的方法:
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel class UserDataViewModel : ViewModel() { // 声明需要收集的用户数据字段 val userName = MutableLiveData<String>() val userEmail = MutableLiveData<String>() val userPhone = MutableLiveData<String>() // 更新数据的方法,供Fragment调用 fun updateName(name: String) { userName.value = name } fun updateEmail(email: String) { userEmail.value = email } fun updatePhone(phone: String) { userPhone.value = phone } }
2. 获取共享的ViewModel实例
核心是通过Activity级别的ViewModelProvider获取实例,确保所有隶属于该Activity的Fragment拿到同一个ViewModel对象:
在Fragment中获取:
class NameFragment : Fragment() { private lateinit var viewModel: UserDataViewModel override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { viewModel = ViewModelProvider(requireActivity())[UserDataViewModel::class.java] return inflater.inflate(R.layout.fragment_name, container, false) } }
在Activity中获取(用于统一监听或触发同步):
class MainActivity : AppCompatActivity() { private lateinit var viewModel: UserDataViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) viewModel = ViewModelProvider(this)[UserDataViewModel::class.java] } }
3. 在Fragment中收集输入并更新ViewModel
以收集姓名的Fragment为例,监听输入框变化,实时同步到ViewModel:
class NameFragment : Fragment() { private lateinit var viewModel: UserDataViewModel private lateinit var etName: EditText override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_name, container, false) etName = view.findViewById(R.id.et_name) viewModel = ViewModelProvider(requireActivity())[UserDataViewModel::class.java] // 监听输入框内容变化,更新ViewModel etName.addTextChangedListener(object : TextWatcher { override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} override fun afterTextChanged(s: Editable?) { s?.toString()?.let { viewModel.updateName(it) } } }) return view } }
其他收集邮箱、手机号的Fragment,按照同样逻辑监听输入并调用ViewModel对应的更新方法即可。
4. 将ViewModel数据同步到Firebase
在提交Fragment或Activity中,触发数据同步操作:
class SubmitFragment : Fragment() { private lateinit var viewModel: UserDataViewModel private lateinit var btnSubmit: Button private val db = FirebaseDatabase.getInstance().reference override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_submit, container, false) btnSubmit = view.findViewById(R.id.btn_submit) viewModel = ViewModelProvider(requireActivity())[UserDataViewModel::class.java] btnSubmit.setOnClickListener { // 从ViewModel获取所有数据 val name = viewModel.userName.value ?: "" val email = viewModel.userEmail.value ?: "" val phone = viewModel.userPhone.value ?: "" // 简单数据校验 if (name.isBlank() || email.isBlank() || phone.isBlank()) { Toast.makeText(context, "请填写完整信息", Toast.LENGTH_SHORT).show() return@setOnClickListener } // 封装数据为Map val userData = mapOf( "name" to name, "email" to email, "phone" to phone ) // 同步到Firebase数据库 db.child("users").push().setValue(userData) .addOnSuccessListener { Toast.makeText(context, "数据同步成功", Toast.LENGTH_SHORT).show() } .addOnFailureListener { e -> Toast.makeText(context, "同步失败:${e.message}", Toast.LENGTH_SHORT).show() } } return view } }
注意事项
- 生命周期安全:LiveData会自动感知Fragment的活跃状态,仅在Fragment可见时推送数据更新,避免内存泄漏。
- 配置变更兼容:ViewModel会在屏幕旋转等配置变更时保留数据,无需额外处理。
- Firebase权限:开发阶段可暂时设置公开读写权限,上线前必须配置安全规则限制访问。
内容的提问来源于stack exchange,提问作者Vivek M Fauzdar
相关产品推荐
相关产品推荐

