Android SQLite 简单的使用步骤

Android开发过程中可以用SQLite储存结构化数据,如联系人信息之类的。

由于SQLite的操作API是相当底层的,因此开发者需要花费很多时间去手动处理SQL查询语句,一旦数据结构改变就得相应的更新SQL语句,这个过程非常耗时,也容易出现错误。
同时,开发者不得不写很多样板代码来转换SQL语句与数据对象。

现在Google比较推荐的做法就是用Room作为一个访问你数据中信息的抽象层,当然也可以使用一些ORM框架来帮组你处理数据库。

用数据库存储的步骤一般如下:

定义一个Schema和Contract

Schema是一个数据库如何组织的一个正式声明,在你创建数据库的SQL语句中可以反映出来。

一个Contract类是一个定义了URIs,tables和columns等常量的容器。

Contract类允许在同一个包中的所有其他类中使用相同的常量,也就是说你在任何一个位置修改column(列名),它都会在整个代码中传播。

在组织Contract类的时候,可以将那些对整个数据库可见的定义放在类的root 层,然后为每一个table创建一个内部类,每一个内部类列举了table中相应的列名column。


    object UserInfoContract {


        //实现BaseColumns接口可以继承一个_ID的主键,有利于Android Framework进行处理
        object UserInfoEntity : BaseColumns {

        const val TABLE_NAME = "user_info"

        const val TABLE_NAME_USERNAME = "username"

        const val TABLE_NAME_PASSWORD = "password"

        const val TABLE_NAME_LOGIN_TIME_LATEST = "login_time_latest"
    }


}

写创建数据库和删除数据库的SQL语句
const val SQL_CREATE_TABLE_USERINFO =
            """
            CREATE TABLE ${UserInfoEntity.TABLE_NAME} (
              ${BaseColumns._ID} INTEGER PRIMARY KEY,
              ${UserInfoEntity.TABLE_NAME_USERNAME} TEXT,
              ${UserInfoEntity.TABLE_NAME_PASSWORD} TEXT,
              ${UserInfoEntity.TABLE_NAME_LOGIN_TIME_LATEST} TEXT
            )
            """

    const val SQL_DELETE_TABLE_USERINFO =
            """
            DROP TABLE IF EXISTS ${UserInfoEntity.TABLE_NAME}
            """

继承SQLiteOpenHelper,自定义数据库创建,更新逻辑

这里会用到上一个步骤写好的SQL语句来创建,删除数据库

class UserInfoDbHelper(context: Context) : SQLiteOpenHelper(context, DB_NAME,null, DB_VERSION){

    companion object {
        val DB_NAME = "user-info"
        val DB_VERSION = 1
    }


    override fun onCreate(db: SQLiteDatabase) {
        db.execSQL(UserInfoContract.SQL_CREATE_TABLE_USERINFO)
    }

    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
        db.execSQL(UserInfoContract.SQL_DELETE_TABLE_USERINFO)
        onCreate(db)
    }


}
根据实际业务进行增删查检的操作

这里就一个登陆,注册的场景来写一下数据库的操作,主要就是注册和登陆的时候查询是否存在相关账户,如果注册的时候不存在则插入数据库,如果登陆的时候不存在则提示注册,如果登陆的时候查询到用户名与密码不能匹配上,则提示错误。

class LoginDbActivity : AppCompatActivity() {

    private lateinit var dbHelper: UserInfoDbHelper

    private val projection = arrayOf(
            BaseColumns._ID,
            UserInfoContract.UserInfoEntity.TABLE_NAME_USERNAME,
            UserInfoContract.UserInfoEntity.TABLE_NAME_PASSWORD,
            UserInfoContract.UserInfoEntity.TABLE_NAME_LOGIN_TIME_LATEST
    )


    private val sortOder = "${UserInfoContract.UserInfoEntity.TABLE_NAME_USERNAME} DESC"


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_login_db)
        title = "SQLite Demo"
        dbHelper = UserInfoDbHelper(this)
        handleClick()
    }

    private fun handleLogic(present: ((cursor: Cursor) -> Unit), absent: (() -> Unit)) {
        if (TextUtils.isEmpty(et_username.text) || TextUtils.isEmpty(et_password.text)) {
            toast("用户名或密码不能为空").show()
            return
        }

        val db = dbHelper.writableDatabase


        val selection = "${UserInfoContract.UserInfoEntity.TABLE_NAME_USERNAME} = ?"

        val selectionArgs = arrayOf(et_username.text.toString())


        doAsync {
            val cursor = db.query(
                    UserInfoContract.UserInfoEntity.TABLE_NAME,
                    projection,
                    selection,
                    selectionArgs,
                    null,
                    null,
                    sortOder
            )

            if (cursor == null || cursor.count == 0) {
                absent()

            } else {
                present(cursor)
            }

        }

    }


    private fun handleClick() {
        btn_login_db.onClick {
            handleLogic(
                    present = {
                        with(it) {
                            while (moveToNext()) {
                                val pwd = getString(getColumnIndexOrThrow(UserInfoContract.UserInfoEntity.TABLE_NAME_PASSWORD))
                                runOnUiThread {
                                    if (et_password.text.toString() == pwd) {
                                        toast("登录成功").show()
                                        finish()
                                    } else {
                                        toast("密码错误").show()
                                    }
                                }
                            }
                        }

                    },
                    absent = {
                        runOnUiThread {
                            toast("您的账号还没有注册,请先进行注册").show()
                        }

                    }
            )
        }


        btn_register_db.onClick {
            handleLogic(
                    present = {
                        runOnUiThread {
                            toast("您的账户已经存在,请直接登录").show()
                        }

                    },
                    absent = {
                        insertDb(dbHelper.readableDatabase)
                    }
            )

        }

    }

    private fun insertDb(db: SQLiteDatabase) {
        val values = ContentValues().apply {
            put(UserInfoContract.UserInfoEntity.TABLE_NAME_USERNAME, et_username.text.toString())
            put(UserInfoContract.UserInfoEntity.TABLE_NAME_PASSWORD, et_password.text.toString())
            put(UserInfoContract.UserInfoEntity.TABLE_NAME_LOGIN_TIME_LATEST, System.currentTimeMillis().toString())
        }

        db.insert(
                UserInfoContract.UserInfoEntity.TABLE_NAME,
                null,
                values
        )

        runOnUiThread {
            toast("注册成功").show()
        }

    }
}

从上面的操作可以知道,其实直接使用SQLite API操作数据库还是比较麻烦的,特别是当需要要更改数据库的Schema的时候,因此如果项目中右大量操作数据库的需求,建议使用稳定的框架。

源码及UI效果

源码

https://github.com/jiangkang/KTools

SQLite Demo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值