我对回收者观点有奇怪的看法。
这是我的片段,具有回收器视图:
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会很棒)。
谢谢!
可能我应该调用适配器中的回调,调用存储库中的删除方法,然后当调用onChildRemove时,从回收器视图中删除项目?
这确实是这里的正常方法:您在数据库上执行操作,然后响应式更新您的应用程序状态和用户交互界面。这有时也称为CQRS:命令查询责任隔离。
另外一个好处是,当您添加子节点时,FirebaseSDK会立即为本地写入操作触发本地事件,例如onChildAdded
。这意味着您无需等待数据库响应,甚至在没有数据库连接时也可以正常工作。在数据库(通常是您的安全规则)拒绝写入的(不太常见的)情况下,SDK将触发所谓的对账事件,例如onChildRemove
,以确保您的UI可以从数据库中显示正确的状态。