提问者:小点点

Firebase回收器在MVVM体系结构中查看删除项目


我对回收者观点有奇怪的看法。

这是我的片段,具有回收器视图:

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
}

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

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

谢谢!


共1个答案

匿名用户

可能我应该调用适配器中的回调,调用存储库中的删除方法,然后当调用onChildRemove时,从回收器视图中删除项目?

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

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