【问题标题】:Firebase recycler view delete items in MVVM architectureFirebase 回收器视图删除 MVVM 架构中的项目
【发布时间】:2022-01-08 18:11:31
【问题描述】:

我在回收站视图中遇到了奇怪的情况。

这是我的片段,它有回收者视图:

class CarsListFragment : Fragment() {

    private var _binding: FragmentCarsListBinding? = null
    private val binding get() = _binding!!

    private lateinit var carsListViewModel: CarsListViewModel
    private lateinit var carsAdapter: CarsListAdapter

    private val swipeCallback: ItemTouchHelper.SimpleCallback =
        object: ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.RIGHT or ItemTouchHelper.LEFT) {
            override fun onMove(
                recyclerView: RecyclerView,
                viewHolder: RecyclerView.ViewHolder,
                target: RecyclerView.ViewHolder
            ): Boolean {
                return false
            }

            override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
                carsAdapter.deleteCar(viewHolder.adapterPosition)
            }
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        carsListViewModel = ViewModelProvider(requireActivity(),
            CarsListViewModelFactory(
                CarsListRepository()
            )
        ).get(CarsListViewModel::class.java)
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentCarsListBinding.inflate(inflater, container, false)

        binding.btnAddCar.setOnClickListener {
            findNavController().navigate(CarsListFragmentDirections.actionCarsListFragmentToAddCarFragment())
        }

        carsAdapter = CarsListAdapter(::adapterDeleteCarCallback)
        binding.rvCars.apply {
            layoutManager = LinearLayoutManager(requireContext())
            adapter = carsAdapter
        }.also {
            val itemTouchHelper = ItemTouchHelper(swipeCallback)
            itemTouchHelper.attachToRecyclerView(it)
        }

        observeCarsData()

        return binding.root
    }

    override fun onStart() {
        super.onStart()
        carsListViewModel.attachListener()
    }

    override fun onStop() {
        super.onStop()
        carsListViewModel.detachListener()
    }

    override fun onDestroy() {
        super.onDestroy()
        _binding = null
    }

    private fun observeCarsData() {
        carsListViewModel.addedCar.observe(viewLifecycleOwner, { data ->
            Log.d("CarsVM", "Car object added")
            Log.d("CarsVM", "Car: $data")
            data?.let {
                carsAdapter.addCar(it)
            }
        })
    }

    private fun adapterDeleteCarCallback(id: String) {
        carsListViewModel.removeCar(id)
    }

这是我的视图模型:

class CarsListViewModel(
    private val repository: CarsListRepository
): ViewModel() {

    val addedCar = repository.addedCar

    fun removeCar(id: String) = repository.removeCar(id)

    fun attachListener() = repository.addListener()

    fun detachListener() = repository.removeListener()

}

这是我的仓库:

object CarsListRepository {

    private val _firebaseAuth: FirebaseAuth by lazy { FirebaseAuth.getInstance() }
    private var _dbCarsListReference: DatabaseReference = FirebaseDatabase.getInstance().getReference("users")
        .child(_firebaseAuth.currentUser!!.uid)
        .child("cars")

    private var _addedCar =  MutableLiveData<Car>()
    val addedCar: LiveData<Car> get() = _addedCar

    private val userCarsListener = object: ChildEventListener {
        override fun onChildAdded(snapshot: DataSnapshot, previousChildName: String?) {
            Log.d("Repo", "added car. Response: ${snapshot}")
            snapshot.getValue(Car::class.java)?.let { car -> _addedCar.value = car }
        }

        override fun onChildChanged(snapshot: DataSnapshot, previousChildName: String?) {
            TODO("Not yet implemented")
        }

        override fun onChildRemoved(snapshot: DataSnapshot) {
            Log.d("Repo", "deleted car. Response: ${snapshot}")
        }

        override fun onChildMoved(snapshot: DataSnapshot, previousChildName: String?) {
            TODO("Not yet implemented")
        }

        override fun onCancelled(error: DatabaseError) {
            TODO("Not yet implemented")
        }
    }

    operator fun invoke(): CarsListRepository {
        return this
    }

    fun removeCar(carId: String) {
        Log.d("Repo", "Passed ID: $carId")
        _dbCarsListReference.child(carId).removeValue()
    }

    fun addListener() {
        Log.d("Repo", "Listener added")
        _dbCarsListReference.addChildEventListener(userCarsListener)
    }

    fun removeListener() {
        Log.d("Repo", "Listener removed")
        _dbCarsListReference.removeEventListener(userCarsListener)
    }

}

这是我的回收器视图适配器:

class CarsListAdapter(
    private val carDeleteCallback: (id: String) -> Unit
): RecyclerView.Adapter<CarsListAdapter.CarViewHolder>() {

    private val data = mutableListOf<Car>()

    class CarViewHolder(private val binding: ItemCarBinding): RecyclerView.ViewHolder(binding.root) {
        fun bind(car: Car) {
            binding.tvCarName.text = car.name
            binding.tvCarBrand.text = car.brand
            binding.tvCarModel.text = car.model
            binding.tvCarPlates.text = if(car.plates.isEmpty()) "----" else car.plates
        }
    }

    fun addCar(car: Car) {
        if(!data.contains(car)) {
            data.add(car)
            notifyItemInserted(data.size)
        }
    }

    fun deleteCar(position: Int) {
        carDeleteCallback(data[position].id)
        data.remove(data[position])
        notifyItemRemoved(position)
        notifyItemRangeChanged(position, itemCount)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CarViewHolder {
        val itemBinding = ItemCarBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return CarViewHolder(itemBinding)
    }

    override fun onBindViewHolder(holder: CarViewHolder, position: Int) {
        holder.bind(data[position])
    }

    override fun getItemCount(): Int = data.size
}

所以基本上我有回收器视图适配器,我在其中添加了用于使用滑动删除项目的项目触摸助手。问题是项目以奇怪的顺序呈现 - 当我导航到不同的片段然后再次进入这个片段时 - 顺序不同。不知道为什么......我也相信我应该使用一些不同的方法删除firebase中的项目。可能我应该在适配器中调用回调,在存储库中调用删除方法,然后在调用 onChildRemoved 时,从回收器视图中删除项目?

希望有人知道根据 MVVM 架构这种方法是否正确,或者是否有更好的方法(例如,git repos 会很棒)。

谢谢!

【问题讨论】:

标签: android firebase kotlin firebase-realtime-database android-recyclerview


【解决方案1】:

也许我应该在适配器中调用回调,在存储库中调用删除方法,然后在调用 onChildRemoved 时,从回收器视图中删除项目?

这确实是这里的正常方法:您在数据库上执行操作,然后反应性地更新您的应用程序状态和用户界面。这有时也称为CQRS:命令查询职责分离。

这里的另一个好处是,Firebase SDK 会立即触发本地事件以进行本地写入操作,例如当您添加子节点时 onChildAdded。这意味着您无需等待数据库响应,甚至在没有数据库连接的情况下也能正常工作。在数据库(通常是您的安全规则)拒绝写入的(不太常见的)情况下,SDK 将触发所谓的协调事件,例如 onChildRemoved,以确保您的 UI 可以显示来自数据库的正确状态。

【讨论】:

    猜你喜欢
    • 2017-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多