整理使用RecyclerView控件在长按删除事件中的用法(使用Kotlin)

一、前言:
在最近的学习中,使用Recyclerview控件时,遇到需要长按删除的场景,在测试过程中,遇到各种崩溃,在这里总结一下:
在本博客汇中,使用了一个统计学生信息的demo,并且用到了SQLite,这样保证长按删除的同时数据库也能同步数据,先上一下长按删除的效果图:
在这里插入图片描述
二、代码分析:
长按删除item最重要的是要确保数据库的同步进行。
1.Student类代码:

class Student(val name: String, val gender: String, val age: Int) {
}

2.数据库代码:

package com.example.recyclerlongclickremove

import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.widget.Toast

class StudentBaseHelper(val context: Context, val name: String, val versin: Int) :
    SQLiteOpenHelper(context, name, null, versin) {

    private val createStockData = "create table $name (" +
            "id integer primary key autoincrement, " +
            "studentName text," +
            "gender text," +
            "age INTEGER)"

    /* 创建数据库 */
    override fun onCreate(db: SQLiteDatabase) {
        db.execSQL(createStockData)
        Toast.makeText(context, "Create $name succeeded", Toast.LENGTH_LONG).show()
    }

    /* 升级数据库 */
    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
        Toast.makeText(context, "upgrade $name succeeded", Toast.LENGTH_LONG).show()
        db.execSQL("drop table if exists $name")
        onCreate(db)
    }
}

这里面只实现了两个必须要覆写的函数;

3.数据库操作的封装代码:

package com.example.recyclerlongclickremove

import android.content.ContentValues
import android.content.Context

class StudentBaseControl(val context: Context, val name: String, val version: Int) {

    private var dbHelper = StudentBaseHelper(context, name, version)

    /* 创建数据库 */
    fun create(){
        dbHelper.writableDatabase
    }

    /* 添加数据 */
    fun addData(student: Student){
        val db = dbHelper.writableDatabase

        val value = ContentValues().apply {
            put("studentName", student.name)
            put("gender", student.gender)
            put("age", student.age)
        }
        db.insert(name, null, value)
    }

    /*
     * 遍历全局数据库
     */
    fun queryAllData(name: String) : ArrayList<Student>{
        val db = dbHelper.writableDatabase
        val dataList = ArrayList<Student>()

        /* 全局搜索 */
        val cursor = db.query(name, null,
            null, null, null,
            null, null, null)

        /* 遍历数据库 */
        if (cursor.moveToFirst()){
            do {
                val name = cursor.getString(cursor.getColumnIndex("studentName"))
                val gender = cursor.getString(cursor.getColumnIndex("gender"))
                val age = cursor.getString(cursor.getColumnIndex("age")).toInt()
                dataList.add(Student(name, gender, age))
            } while (cursor.moveToNext())
            cursor.close()
            return dataList
        }

        cursor.close()
        /* 如果未遍历到目标数据,则返回null */
        return dataList
    }

    /* 删除数据:根据学生姓名进行删除 */
    fun deleteData(studentName: String){
        val db = dbHelper.writableDatabase
        db.delete(name, "studentName = ?", arrayOf(studentName))
    }
}

create方法,创建数据库,直接操作SQLite;
addData方法,往数据库中添加item;
queryAllData方法,遍历数据库,这个方法的作用主要是用在Activity启动的时候检测是否创建了数据库;
deleteData方法,删除数据库中的数据;

4.RecyclerView的适配器:

package com.example.recyclerlongclickremove

import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import android.widget.Toast
import androidx.recyclerview.widget.RecyclerView

class StudentsAdapter(list: ArrayList<Student>):
    RecyclerView.Adapter <StudentsAdapter.ViewHolder>(){

    private var studentList = ArrayList<Student>()

    init {
        studentList = list
    }

    /* 用于获取最外层布局的及控件的实例 */
    inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view){
        val name : TextView = view.findViewById(R.id.name)
        val gender : TextView = view.findViewById(R.id.gender)
        val age : TextView = view.findViewById(R.id.age)
    }

    /* 加载student布局 */
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.student, parent, false)

        val viewHolder = ViewHolder(view)

        /* 最外层布局点击事件 */
        viewHolder.itemView.setOnClickListener {
            Toast.makeText(parent.context, "you click outer item!",
                Toast.LENGTH_SHORT).show()
        }

        /**
         *  长按监听:删除item
         */
        viewHolder.itemView.setOnLongClickListener {
            val position = viewHolder.adapterPosition
            /* 将长按item对应的学生姓名发送至MainActivity */
            Log.d("jiyi", "adapter remove:${studentList[position].name}")
            MainActivity.mainActivityTodo(
                MainActivity.HANDLELONGCLIECK,
                studentList[position].name)
            /* 在ArrayList中移除此股 */
            studentList.remove(studentList[position])
            /* 通知移除该item */
            notifyItemRemoved(position)
            /* 通知调制ArrayList顺序(此句删除也无影响) */
            notifyItemRangeChanged(position, studentList.size)
            false
        }

        return viewHolder //注意这里要返回viewHolder,因为有各种点击事件
    }

    /* 对RecyclerView滚入屏幕的子项数据赋值 */
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val student = studentList[position]
        holder.name.text = student.name
        holder.gender.text = student.gender
        holder.age.text = student.age.toString()
    }

    /* 返回数据源长度 */
    override fun getItemCount() = studentList.size
}

adapter的基本操作就不说了,我们主要看其中的长按监听删除item事件:
我们能将数据库中的数据显示到控件上,是使用了ArrayList的,而数据又是从数据库中来的,因此,在删除事件的处理上,这两个地方都要进行各自数据的删除Arraylist的删除操作就由adapter来完成,数据库的删除操作由MainActivity来完成,所以在代码中可以看到,这里借助了MainActivity提供的静态方法,将需要删除的学生名字给传递过去,当然,这里是为了方便,学生名字都没有重复,在实际开发中,你肯定有自己的数据删选准则,删除ArrayList就只需要调用remove就好了,notifyItemRemoved方法则是为了通知adapter,进行UI上的刷新,代码中还有一句notifyItemRangeChanged,我实测中发现这句有没有并没有什么区别,但网上有人说需要这句,所以我还是保留了,总的来说,adapter的主要操作是删除ArrayList中的数据,剩下的就交给MainActivity了;

5.MainAcrtivity的实现:

package com.example.recyclerlongclickremove

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.activity_main.*
import kotlin.concurrent.thread


/** 长按删除Flag */
internal var onLongClickFlag = false
/** 长按删除的股票代码 */
internal var removeStudentName = ""

class MainActivity : AppCompatActivity() {

    private var threadRun = true

    private var studentList = ArrayList<Student>()

    val databaseStudent = StudentBaseControl(this, "Student", 1)

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

        /*
         * 将当前活动赋值给静态对象
         */
        mainActivity = this

        /*
         * 如果数据库不存在:创建 + 添加初始数据
         */
        if (databaseStudent.queryAllData("Student").size == 0){
            /* 创建数据库 */
            databaseStudent.create()
            /*
             * 初始化student数据
             */
            initStudent()
            /* 添加数据 */
            for (i in 0 until (studentList.size)){
                databaseStudent.addData(studentList.get(index = i))
            }
        }
    }

    override fun onResume() {
        super.onResume()

        /*
         * 重新填充studentList数据,避免从其他activity回来之后数据有改变
         */
        studentList.clear()
        studentList = databaseStudent.queryAllData("Student")

        /* 获取layoutManager */
        val layoutManager = LinearLayoutManager(this)
        recyclerView.layoutManager = layoutManager

        /* 获取适配器 */
        val adapter = StudentsAdapter(studentList)
        recyclerView.adapter = adapter

        thread {
            while (threadRun){
                if (onLongClickFlag){
                    if (removeStudentName != ""){
                        /* 删除数据库中的对应数据,注意,这里不需要删除ArrayList里面的了,因为adapter中已经删除了 */
                        databaseStudent.deleteData(removeStudentName)
                    }
                    onLongClickFlag = false
                    removeStudentName = ""
                    Thread.sleep(200)
                }
            }
        }
    }

    /* 初始化StudentList */
    private fun initStudent(){
        repeat(1){
            studentList.add(Student("张三", "男", 27))
            studentList.add(Student("李四", "女", 28))
            studentList.add(Student("王五", "男", 29))
            studentList.add(Student("赵六", "女", 30))
            studentList.add(Student("郭七", "男", 31))
        }
    }

    /**
     *  MainActivity的单实例,用于供外部类调用的static方法等
     */
    companion object{

        const val HANDLELONGCLIECK = "handlelongclick"
        lateinit var  mainActivity : AppCompatActivity   //静态对象,用于适配器调用activity的相关操作

        /**
         * mainActivityTodo由外部类回调MainActivity操作
         * event:需要执行的操作
         * stockCode:响应控件对应的股票代码
         */
        @JvmStatic
        fun mainActivityTodo(event: String, studentName: String){
            when (event){
                /* 处理长按删除item事件 */
                HANDLELONGCLIECK -> {
                    onLongClickFlag = true
                    removeStudentName = studentName
                    Log.d("MainActivity", "remove student:$studentName")
                }
            }
        }
    }
}

为了方面监测用户是否是删除了item,在MainActivity中我跑了一个线程,如果确认有长按删除事件触发时,onLongClickFlag这个布尔值会置为true,那么,只需要这时调用deleteData删除数据库中的数据就可以了;

三、总结:
RecyclerView的长按删除事件调用setOnLongClickListener就可以了,只不过在实际中,一定要区别处理ArrayList和SQLite中的操作,不然很容易出现各种崩溃的问题。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值