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
}
AddressDao:
@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:
@Database(entities = [Address::class], version = 1)
abstract class Database : RoomDatabase() {
abstract fun AddressDao(): AddressDao
}
AddressActivity:
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) }})
}
}
Adapter:
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
}
}
From the above code I'm able delete a row at a moment but when I revisit the activity it shows that deleted row again
I want to know how can I delete a data which is stored in room using in onBindviewHolder
As per latest answer suggested by @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()
}
}
Adapter now:
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()
})
Now crashing with kotlin.UninitializedPropertyAccessException: lateinit property database has not been initialized
Really need help....
Follow my simple steps to solve your issue,
Step 1:
Check once CustomApplication
name mentioned or not in AndroidManifest.xml
,
<application
android:name=".CustomApplication"
otherwise you get this issue
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
Step 2:
Check your module level build.gradle
file
apply this changes
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
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"
otherwise you get this issue
java.lang.RuntimeException: cannot find implementation for com.example.myapplication.Database. Database_Impl does not exist
Step 3:
check your AddressDao
interface, add this function
@Delete
suspend fun deleteAddress(address: Address)
Step 4:
in AddressAdapter
class, add this listener,
interface ItemListener {
fun onItemClicked(address: Address, position: Int)
}
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;
}
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()
})
Step 5:
In AddressActivity
class, do this changes
Implement listener here,
class AddressActivity : AppCompatActivity(), AddressAdapter.ItemListener {
then override method
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)
}
}
here I used coroutine otherwise you can use AsycTask also
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'
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,
If you really want to execute in main UI thread, do this changes in your code
in AddressDao
interface,
@Delete
fun deleteAddress(address: Address)
in CustomApplication
class, add 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()
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With