Я использую RecyclerView для заполнения данными, которые выбираются в моей базе данных Room.Когда данные выбираются или удаляются из базы данных моей комнаты, RecyclerView обновляется автоматически.Я реализовал пролистывание для удаления и отмены в моем RecyclerView.Когда я пролистываю, я удаляю элемент в моей базе данных комнат, и RecyclerView обновляется автоматически.Однако, когда я нажимаю кнопку «Отменить», я снова вставляю элемент в базу данных Room, и элемент отображается в Recyclerview.Проблема здесь в том, что когда я восстанавливаю предмет, он восстанавливается в последней позиции.Я хочу, чтобы он восстанавливался в том положении, в котором он был удален, а не последний.
Мой код такой, как показано ниже:
фрагмент.xml
<androidx.recyclerview.widget.RecyclerView
android:id="@id/RecyclerView_fromFragmentToDo_Main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/Margin_Views_Small"
android:layout_marginBottom="?attr/actionBarSize"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
adapter.kt
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.th3pl4gu3.lifestyle.core.lifestyle.ToDo
import com.th3pl4gu3.lifestyle.databinding.CustomRecyclerviewListTodoBinding
class ToDoAdapter : ListAdapter<ToDo, ToDoAdapter.ViewHolder>(ToDoDiffCallback()) {
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val toDo = getItem(position)
holder.bind(toDo)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder.from(parent)
}
class ViewHolder private constructor(val binding: CustomRecyclerviewListTodoBinding): RecyclerView.ViewHolder(binding.root) {
fun bind(toDo: ToDo) {
binding.myToDo = toDo
binding.executePendingBindings()
}
companion object {
fun from(parent: ViewGroup): ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = CustomRecyclerviewListTodoBinding.inflate(layoutInflater, parent, false)
return ViewHolder(binding)
}
}
}
}
class ToDoDiffCallback: DiffUtil.ItemCallback<ToDo>() {
override fun areItemsTheSame(oldItem: ToDo, newItem: ToDo): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: ToDo, newItem: ToDo): Boolean {
return oldItem == newItem
}
}
viewmodel.kt
import android.app.Application
import androidx.lifecycle.*
import com.th3pl4gu3.lifestyle.core.lifestyle.ToDo
import com.th3pl4gu3.lifestyle.core.operations.Filter
import com.th3pl4gu3.lifestyle.core.operations.ToDoOperations
import com.th3pl4gu3.lifestyle.database.LifestyleDatabase
import com.th3pl4gu3.lifestyle.ui.enums.ToggleButtonStates
import kotlinx.coroutines.*
class ToDoViewModel(
val database: LifestyleDatabase,
application: Application) : AndroidViewModel(application) {
private var _viewModelJob = Job()
private val _uiScope = CoroutineScope(Dispatchers.Main + _viewModelJob)
//Current state of the toggle button (Current button checked)
var currentToggleButtonState = ToggleButtonStates.BUTTON_ACTIVE
//Fetch all to dos from database
private var _toDos = ToDoOperations.getAllOffline(database)
val toDosMediatorLiveData = MediatorLiveData<List<ToDo>>()
init {
//Update the list of the recyclerview on INIT
updateList(currentToggleButtonState)
}
/**
* Public functions that are accessible from the outside
**/
fun updateList(toggleButton: ToggleButtonStates) {
toDosMediatorLiveData.removeSource(_toDos)
when(toggleButton){
ToggleButtonStates.BUTTON_ALL ->{
currentToggleButtonState = ToggleButtonStates.BUTTON_ALL
toDosMediatorLiveData.addSource(_toDos){
toDosMediatorLiveData.value = it
}
}
ToggleButtonStates.BUTTON_ACTIVE ->{
currentToggleButtonState = ToggleButtonStates.BUTTON_ACTIVE
toDosMediatorLiveData.addSource(_toDos){
toDosMediatorLiveData.value = Filter<ToDo>(it).getActive()
}
}
ToggleButtonStates.BUTTON_COMPLETE ->{
currentToggleButtonState = ToggleButtonStates.BUTTON_COMPLETE
toDosMediatorLiveData.addSource(_toDos){
toDosMediatorLiveData.value = Filter<ToDo>(it).getCompleted()
}
}
}
}
fun insertItem(toDo: ToDo) {
_uiScope.launch {
insert(toDo)
}
}
fun markAsDeleted(toDo: ToDo) {
_uiScope.launch {
remove(toDo)
}
}
fun markItem(toDo: ToDo){
if(toDo.dateCompleted == null){
markAsCompleted(toDo)
}else{
markAsIncomplete(toDo)
}
}
/**
* Private functions for internal use ONLY
**/
private fun markAsCompleted(newToDo: ToDo) {
_uiScope.launch {
newToDo.markAsComplete()
update(newToDo)
}
}
private fun markAsIncomplete(newToDo: ToDo) {
_uiScope.launch {
newToDo.markAsIncomplete()
update(newToDo)
}
}
private suspend fun insert(toDo: ToDo) {
withContext(Dispatchers.IO) {
toDo.add(database)
}
}
private suspend fun remove(toDo: ToDo) {
withContext(Dispatchers.IO) {
toDo.delete(database)
}
}
private suspend fun update(newToDo: ToDo) {
withContext(Dispatchers.IO) {
newToDo.update(database)
}
}
/**
* Overridden functions
**/
override fun onCleared() {
super.onCleared()
//Clear the view model job when user leave
_viewModelJob.cancel()
}
}
фрагмент.kt
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.RelativeLayout
import android.widget.TextView
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.th3pl4gu3.lifestyle.R
import com.th3pl4gu3.lifestyle.ui.Utils.toast
import com.th3pl4gu3.lifestyle.database.LifestyleDatabase
import com.th3pl4gu3.lifestyle.databinding.FragmentToDoBinding
import com.th3pl4gu3.lifestyle.ui.Utils.action
import com.th3pl4gu3.lifestyle.ui.Utils.snackBar
import com.th3pl4gu3.lifestyle.ui.Utils.snackBarWithAction
import com.th3pl4gu3.lifestyle.ui.enums.ToggleButtonStates
import java.util.*
class FragmentToDo : Fragment() {
private lateinit var mBinding: FragmentToDoBinding
private lateinit var mToDoViewModel: ToDoViewModel
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
//Inflate the layout for this fragment
mBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_to_do, container, false)
//Configures the screen views (Eg. Title, appearance of top bar etc...)
configureScreenAppearance()
//Get the activity's application
val application = requireNotNull(this.activity).application
//Fetch the database
val dataSource = LifestyleDatabase.getInstance(application)
//Instantiate the view model factory
val viewModelFactory = ToDoViewModelFactory(dataSource, application)
//Instantiate the view model of this fragment
mToDoViewModel = ViewModelProviders.of(this, viewModelFactory).get(ToDoViewModel::class.java)
//Bind view model
mBinding.toDoViewModel = mToDoViewModel
//Instantiate the lifecycle owner
mBinding.lifecycleOwner = this
//RecyclerView's configuration
val adapter = ToDoAdapter()
mBinding.RecyclerViewFromFragmentToDoMain.adapter = adapter
mToDoViewModel.toDosMediatorLiveData.observe(viewLifecycleOwner, Observer {
it.let { x ->
//Update the UI and determine whether recyclerview should be visible or not
updateUI(x.isNotEmpty())
adapter.submitList(x)
}
})
//Swipe configurations
val swipeHandler = object : ToDoSwipeToCallback(requireContext()) {
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
val swipedToDo = (mBinding.RecyclerViewFromFragmentToDoMain.adapter as ToDoAdapter).currentList[viewHolder.adapterPosition]
val fab = requireActivity().findViewById<FloatingActionButton>(R.id.FAB_fromHomeActivity_BottomAppBarAttached)
val position = viewHolder.adapterPosition
when(direction){
ItemTouchHelper.LEFT -> {
mToDoViewModel.markItem(swipedToDo)
}
ItemTouchHelper.RIGHT -> {
mToDoViewModel.markAsDeleted(swipedToDo)
//Show Snackbar with 'Undo' action
requireActivity().findViewById<View>(android.R.id.content).snackBarWithAction(getString(R.string.Message_Exception_fromFragmentLifeStyleItems_ErrorWhileSwiping, swipedToDo.title), anchorView = fab){
action("Undo"){
mToDoViewModel.insertItem(swipedToDo)
//Restore Item
}
}
}
else ->{
requireContext().toast(getString(R.string.Message_Exception_fromFragmentLifeStyleItems_ErrorWhileSwiping))
}
}
}
}
val itemTouchHelper = ItemTouchHelper(swipeHandler)
itemTouchHelper.attachToRecyclerView(mBinding.RecyclerViewFromFragmentToDoMain)
return mBinding.root
}
/**
* Private functions for internal use ONLY
**/
private fun updateUI(recyclerViewVisible: Boolean){
if(recyclerViewVisible){
mBinding.RecyclerViewFromFragmentToDoMain.visibility = View.VISIBLE
mBinding.EmptyViewForRecyclerView.visibility = View.GONE
}else{
if(mToDoViewModel.currentToggleButtonState == ToggleButtonStates.BUTTON_COMPLETE){
mBinding.TextViewFromFragmentToDoEmptyView.text = getString(R.string.TextView_fromToDoFragment_Message_EmptyList_Completed)
}else if(mToDoViewModel.currentToggleButtonState == ToggleButtonStates.BUTTON_ACTIVE){
mBinding.TextViewFromFragmentToDoEmptyView.text = getString(R.string.TextView_fromToDoFragment_Message_EmptyList_Active)
}
mBinding.RecyclerViewFromFragmentToDoMain.visibility = View.GONE
mBinding.EmptyViewForRecyclerView.visibility = View.VISIBLE
}
}
private fun configureScreenAppearance(){
//Set title of fragment
val screenTitle = requireActivity().findViewById<TextView>(R.id.TextView_fromHomeActivity_Screen_Title)
screenTitle.text = getString(R.string.TextView_fromFragmentInHomeActivity_ScreenTitle_ToDo)
//Show Top Bar
val topBar = requireActivity().findViewById<RelativeLayout>(R.id.RelativeLayout_fromHomeActivity_TopBar)
topBar.visibility = View.VISIBLE
//Show Fab
val fab = requireActivity().findViewById<FloatingActionButton>(R.id.FAB_fromHomeActivity_BottomAppBarAttached)
fab.show()
}
}
Мне нужно восстановить предмет здесь:
ItemTouchHelper.RIGHT -> {
mToDoViewModel.markAsDeleted(swipedToDo)
//Show Snackbar with 'Undo' action
requireActivity().findViewById<View>(android.R.id.content).snackBarWithAction(getString(R.string.Message_Exception_fromFragmentLifeStyleItems_ErrorWhileSwiping, swipedToDo.title), anchorView = fab){
action("Undo"){
mToDoViewModel.insertItem(swipedToDo)
//Restore Item
}
}
}
IПопытка получить список, а затем сделать list.add (позиция, элемент), но это не работает.Может кто-нибудь помочь, пожалуйста?Благодаря.