如何使用房间从回收站视图中删除一行? [英] How do I remove a row from recyclerview using room?

查看:25
本文介绍了如何使用房间从回收站视图中删除一行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 room.im 删除一行 recyclerview.我正在滑动以删除特定行....

I'm trying to delete an row of recyclerview using room.im doing swipe to delete a particular row....

这是我的地址表-->

Here is my Address table-->

@Entity(tableName = "address")
 class Address {
@PrimaryKey(autoGenerate = true)
var id = 0

@ColumnInfo(name = "address")
var address: String? = null
 }

地址道:

@Dao
interface AddressDao {
@Insert
suspend fun addData(address: Address)

@Query("select * from address")
fun getAddressesWithChanges() :LiveData<MutableList<Address>>

@Query("SELECT EXISTS (SELECT 1 FROM address WHERE id=:id)")
suspend fun isAddressAdded(id: Int): Int

@Delete
suspend fun delete(address: Address)
  }

数据库:

@Database(entities = [Address::class], version = 1)
abstract class Database : RoomDatabase() {
abstract fun AddressDao(): AddressDao
 } 

地址活动:

class AddressActivity : AppCompatActivity() {
    private val adapter = AddressAdapter()

    private lateinit var data: LiveData<MutableList<Address>>

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.address)

        addbutton.findViewById<View>(R.id.addbutton).setOnClickListener {
            val intent = Intent(this, AddAddressActivity::class.java)
            startActivity(intent)
        }

        val recyclerView = findViewById<RecyclerView>(R.id.recyclerview)
        recyclerView.setHasFixedSize(true)
        recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
        recyclerView.adapter = adapter
        recyclerView.addItemDecoration(DividerItemDecorator(resources.getDrawable(R.drawable.divider)))
        recyclerView.addOnScrollListener(object :
            RecyclerView.OnScrollListener() {
            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                super.onScrollStateChanged(recyclerView, newState)
                Log.e("RecyclerView", "onScrollStateChanged")
            }

            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
            }
        })


        val application = application as CustomApplication
        data = application.database.AddressDao(). getAddressesWithChanges()
        data.observe(this, Observer { words1 ->
            // Update the cached copy of the words in the adapter.
            words1?.let { adapter.updateData(it) }})


    }
}

适配器:

class AddressAdapter: RecyclerSwipeAdapter<AddressAdapter.ViewHolder>() {
    private var addresses: MutableList<Address> = Collections.emptyList()
    lateinit var  Database:Database

    override fun onCreateViewHolder(viewGroup: ViewGroup, itemViewType: Int): ViewHolder =
        ViewHolder(LayoutInflater.from(viewGroup.context).inflate(R.layout.address_item, viewGroup, false))

    override fun getSwipeLayoutResourceId(position: Int): Int {
        return R.id.swipe;
    }

    override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
        val fl: Address = addresses[position]
        viewHolder.tv.setText(fl.address)
        viewHolder.swipelayout.setShowMode(SwipeLayout.ShowMode.PullOut)
        // Drag From Right

        // Drag From Right
        viewHolder.swipelayout.addDrag(
            SwipeLayout.DragEdge.Right,
            viewHolder.swipelayout.findViewById(R.id.bottom_wrapper)
        )
        // Handling different events when swiping
        viewHolder.swipelayout.addSwipeListener(object : SwipeLayout.SwipeListener {
            override fun onClose(layout: SwipeLayout) {
                //when the SurfaceView totally cover the BottomView.
            }

            override fun onUpdate(layout: SwipeLayout, leftOffset: Int, topOffset: Int) {
                //you are swiping.
            }

            override fun onStartOpen(layout: SwipeLayout) {}
            override fun onOpen(layout: SwipeLayout) {
            }

            override fun onStartClose(layout: SwipeLayout) {}
            override fun onHandRelease(
                layout: SwipeLayout,
                xvel: Float,
                yvel: Float
            ) {
            }
        })


        viewHolder.tvDelete.setOnClickListener(View.OnClickListener { view ->
            mItemManger.removeShownLayouts(viewHolder.swipelayout)
            addresses.removeAt(position)

           //What should i do here??????????????????????????
           // val address = Address()

           // Database.AddressDao().delete(address)
            notifyDataSetChanged()
            notifyItemRemoved(position)
            notifyItemRemoved(position)
            notifyItemRangeChanged(position, addresses.size)
            mItemManger.closeAllItems()
            Toast.makeText(
                view.context,
                "Deleted " + viewHolder.tv.getText().toString(),
                Toast.LENGTH_SHORT
            ).show()
        })


        // mItemManger is member in RecyclerSwipeAdapter Class


        // mItemManger is member in RecyclerSwipeAdapter Class
        mItemManger.bindView(viewHolder.itemView, position)
    }


    override fun getItemCount(): Int = addresses.size

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var tv: TextView
        val swipelayout: SwipeLayout
        val tvDelete:TextView



        init {
            tvDelete=itemView.findViewById(R.id.tvDelete)

            tv = itemView.findViewById(R.id.ftv_name)
            swipelayout=itemView.findViewById(R.id.swipe)

        }    }

    fun updateData(addresses:
                   MutableList<Address>) {
        this.addresses = addresses
        notifyDataSetChanged() // TODO: use ListAdapter if animations are needed
    }

}

从上面的代码中,我可以立即删除一行,但是当我重新访问活动时,它再次显示已删除的行

我想知道如何使用 onBindviewHolder

根据@quealegriamasalegre 建议的最新答案

这是我的自定义应用程序:--

Here is my CustomApplication:--

class CustomApplication: Application() {
    lateinit var database: Database
        private set
    lateinit var addressDao: AddressDao
        private set

    override fun onCreate() {
        super.onCreate()

        this.database = Room.databaseBuilder<Database>(
            applicationContext,
            Database::class.java, "database"
        ).build()
        addressDao = database.AddressDao()

    }
}

现在适配器:

      viewHolder.tvDelete.setOnClickListener(View.OnClickListener { view ->
        mItemManger.removeShownLayouts(viewHolder.swipelayout)
        addresses.removeAt(position)

        val application = CustomApplication()

        application.database.AddressDao().deleteAddress(position)//here you delete from DB so its gone for good
        //notifyDataSetChanged() dont do this as it will reexecute onbindviewholder and skip a nice animation provided by android
        //notifyItemRemoved(position) execute only once


        notifyDataSetChanged()
        notifyItemRemoved(position)
        notifyItemRemoved(position)
        notifyItemRangeChanged(position, addresses.size)
        mItemManger.closeAllItems()
        Toast.makeText(
            view.context,
            "Deleted " + viewHolder.tv.getText().toString(),
            Toast.LENGTH_SHORT
        ).show()
    })

现在因 kotlin.UninitializedPropertyAccessException 崩溃:lateinit 属性数据库尚未初始化

真的需要帮助....

推荐答案

按照我的简单步骤来解决您的问题,

Follow my simple steps to solve your issue,

第 1 步:检查一次 CustomApplication 名称是否在 AndroidManifest.xml 中提及,

Step 1: Check once CustomApplication name mentioned or not in AndroidManifest.xml,

<application
    android:name=".CustomApplication"

否则你会遇到这个问题

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.myapplication/com.example.myapplication.AddressActivity}: java.lang.ClassCastException: android.app.Application cannot be cast to com.example.myapplication.CustomApplication

第 2 步:检查您的模块级别 build.gradle 文件

Step 2: Check your module level build.gradle file

应用此更改

apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'

检查依赖关系 -- 对于 Kotlin,使用 kapt 而不是 annotationProcessor

check dependencies -- For Kotlin use kapt instead of annotationProcessor

implementation "androidx.room:room-runtime:2.2.5"
kapt "androidx.room:room-compiler:2.2.5"

否则你会遇到这个问题

java.lang.RuntimeException: cannot find implementation for com.example.myapplication.Database. Database_Impl does not exist

第 3 步:检查你的AddressDao接口,添加这个功能

Step 3: check your AddressDao interface, add this function

 @Delete
 suspend fun deleteAddress(address: Address)

第 4 步:

AddressAdapter类中,添加这个监听器,

in AddressAdapter class, add this listener,

interface ItemListener {
    fun onItemClicked(address: Address, position: Int)
}

添加监听器变量和setListener函数

add listener variable and setListener function

private lateinit var listener: ItemListener

interface ItemListener {
    fun onItemClicked(address: Address, position: Int)
}

fun setListener(listener: ItemListener) {
    this.listener = listener;
}

然后在 tvDelete.setOnClickListener 方法中更新您的代码

then update your code in tvDelete.setOnClickListener method

    viewHolder.tvDelete.setOnClickListener(View.OnClickListener { view ->
        mItemManger.removeShownLayouts(viewHolder.swipelayout)
        addresses.removeAt(position)

        listener.onItemClicked(fl, position)
        
        notifyDataSetChanged()
     //   notifyItemRemoved(position)
     //   notifyItemRangeChanged(position, addresses.size)
        mItemManger.closeAllItems()
        Toast.makeText(
            view.context,
            "Deleted " + viewHolder.tv.getText().toString(),
            Toast.LENGTH_SHORT
        ).show()
    })

第 5 步:AddressActivity 类中,进行此更改

Step 5: In AddressActivity class, do this changes

在这里实现监听器,

class AddressActivity : AppCompatActivity(), AddressAdapter.ItemListener {

然后覆盖方法

override fun onItemClicked(address: Address, position: Int) {
    
}

然后为适配器设置监听器

then set listener for adapter

        recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
        recyclerView.adapter = adapter
        adapter.setListener(this)

然后在覆盖方法中更新代码

then update code in override method

override fun onItemClicked(address: Address, position: Int) {
    lifecycleScope.launch {
        val application = application as CustomApplication
        application.database.AddressDao().deleteAddress(address)
    }
}

这里我使用了协程,否则你也可以使用 AsycTask

here I used coroutine otherwise you can use AsycTask also

对于协程,在你的模块 build.gradle 文件中添加这个依赖项

for coroutine add this dependencies in your module build.gradle file

implementation "android.arch.lifecycle:extensions:1.1.1"
kapt "android.arch.lifecycle:compiler:1.1.1"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'

如果你在UI类中直接调用deleteAddress方法,就会出现这个问题

if you directly called deleteAddress method in UI class, you get this issue

java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.

所以在后台线程中使用这样的方法,

so use such methods in background thread,

如果您真的想在主 UI 线程中执行,请在代码中进行此更改

If you really want to execute in main UI thread, do this changes in your code

AddressDao接口中,

@Delete
fun deleteAddress(address: Address)

CustomApplication 类中,添加allowMainThreadQueries()

class CustomApplication : Application() {
    lateinit var database: Database
        private set
    lateinit var addressDao: AddressDao
        private set

    override fun onCreate() {
        super.onCreate()

        this.database = Room.databaseBuilder<Database>(
            applicationContext,
            Database::class.java, "database"
        ).allowMainThreadQueries().build()
        addressDao = database.AddressDao()
    }
}

这篇关于如何使用房间从回收站视图中删除一行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆