一:创建主界面增删改查

/**
 * @author zhiqiangRuan
 * @ClassName
 * @Date  2022/7/4
 */
class FiveActivity : BaseActivity(), View.OnClickListener {
    lateinit var addData: Button
    lateinit var deleteData: Button
    lateinit var queryData: Button
    lateinit var updataData: Button
    var bookId: String? = null
    override fun initView() {
        addData = findViewById<Button>(R.id.add_data)
        deleteData = findViewById<Button>(R.id.delete_data)
        queryData = findViewById<Button>(R.id.query_data)
        updataData = findViewById<Button>(R.id.update_data)
        addData.setOnClickListener(this)
        deleteData.setOnClickListener(this)
        queryData.setOnClickListener(this)
        updataData.setOnClickListener(this)
    }

    override fun initData() {
    }

    override fun getLayoutId(): Int {
        return R.layout.activity_five
    }

    override fun onClick(v: View?) {
        when (v?.id) {
            R.id.add_data -> {
                //添加数据
                val uri = Uri.parse("content://com.cnstrong.leke.helloworld.provider/book")
                val values = contentValuesOf(
                    "author" to "George Martin",
                    "price" to 22.85,
                    "pages" to 1040,
                    "name" to "A Clash of King"
                )
                val newUri = contentResolver.insert(uri, values)
                bookId = newUri?.pathSegments?.get(1)
            }
            /**
             * apply函数扩展了所有的泛型对象,在闭包范围内可以任意调用该对象的任意方法,并在最后返回该对象.

            主要的作用:是可以用来简化初始化对象的功能。
            特别需要注意的是apply函数中表示对象本身使用的是this关键字而不是it。*/
            R.id.query_data -> {
                //查询数据
                val uri = Uri.parse("content://com.cnstrong.leke.helloworld.provider/book")
                contentResolver.query(uri, null, null, null, null)?.apply {
                    while (moveToNext()) {
                        val name = getString(getColumnIndex("name"))
                        val author = getString(getColumnIndex("author"))
                        val pages = getInt(getColumnIndex("pages"))
                        val price = getDouble(getColumnIndex("price"))
                        Log.d("FiveActivity", "book name is $name")
                        Log.d("FiveActivity", "book author is $author")
                        Log.d("FiveActivity", "book pages is $pages")
                        Log.d("FiveActivity", "book price is $price")

                    }
                    close()

                }

            }

            R.id.update_data -> {
                //更新数据
                bookId?.let {
                    val uri = Uri.parse("content://com.cnstrong.leke.helloworld.provider/book/$it")
                    val values = contentValuesOf(
                         "price" to 24.05,
                        "pages" to 1216,
                        "name" to "A Storm of Swords"

                    )
                    contentResolver.update(uri,values,null,null)
                }
            }

            R.id.delete_data->{
                bookId?.let{
                    val uri = Uri.parse("content://com.cnstrong.leke.helloworld.provider/book/$it")
                    contentResolver.delete(uri,null,null)
                }

            }
        }
    }

}

image.png
二:Xml文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/add_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Add To Book" />

    <Button
        android:id="@+id/query_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Query From Book" />

    <Button
        android:id="@+id/update_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Update Book" />

    <Button
        android:id="@+id/delete_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Delete From Book" />



</LinearLayout>

三:自定义的MyProvider

package com.cnstrong.leke.helloworld

import android.content.ContentProvider
import android.content.ContentValues
import android.content.UriMatcher
import android.net.Uri
import java.lang.RuntimeException

/**
 * @author zhiqiangRuan
 * @ClassName 自定义ContentProvider
 * @Date  2022/7/4
 */
class MyProvider : ContentProvider() {

    private val bookDir = 0
    private val bookItem = 1

    private val categoryDir = 2
    private val categoryItem = 3

    /**
     * 每一个ContentProvider定义唯一标识URI  URI*/
    private var dbHelper: MySqliteDataHelper? = null

    private val authority = "com.cnstrong.leke.helloworld.provider"

    /**UriMatcher本质上是一个文本过滤器,用在contentProvider中帮助我们过滤,分辨出查询者想要查询哪个数据表。*/
    private val uriMatcher by lazy {
        //常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码
        val mathcher = UriMatcher(UriMatcher.NO_MATCH)
        //如果match()方法匹配content://com.cnstrong.leke.helloworld.provider/book路径,返回匹配码为1
        mathcher.addURI(authority, "book", bookDir)
        //如果match()方法匹配content://com.cnstrong.leke.helloworld.provider/book/通配符 路径,返回匹配码为2
        mathcher.addURI(authority, "book/#", bookItem)

        mathcher.addURI(authority, "category", categoryDir)
        mathcher.addURI(authority, "category/#", categoryItem)
        mathcher
    }

    /**创建数据*/
    /**
     * override fun onCreate(): Boolean {
    dbHelper = context?.let {
    MySqliteDataHelper(it, "BookStore.db", 1)
    return true
    }
    return false

    ------------------------------
    这里用到了Kotlin let操作符
    obj.let{} 或obj?.let{}
    第一种写法,如果确定obj不为null,可以使用,
    第二种写法相当于java的非空判断,当obj不为空时,才执行大括号内的代码段,相对java的空判断来说简洁一些,值得使用。
    //在函数体内使用it替代object对象去访问其公有的属性和方法
    } */
    override fun onCreate() = context?.let {
       // MySqliteDataHelper(it, "BookStore.db", 1)
//要记住这个问题,自己写代码太不严谨了
 dbHelper=MySqliteDataHelper(it, "BookStore.db", 1)
        true
    } ?: false


    /**查询数据*/

    override fun query(
        uri: Uri,
        projection: Array<out String>?,
        selection: String?,
        selectionArgs: Array<out String>?,
        sortOrder: String?
    ) = dbHelper?.let {
        //查询数据
        val db = it.writableDatabase
        val cursor = when (uriMatcher.match(uri)) {
            bookDir -> db.query("Book", projection, selection, selectionArgs, null, null, sortOrder)
            bookItem -> {
                val bookId = uri.pathSegments[1]
                db.query("Book", projection, "id=?", arrayOf(bookId), null, null, sortOrder)
            }
            categoryDir -> db.query(
                "Category",
                projection,
                selection,
                selectionArgs,
                null,
                null,
                sortOrder
            )
            categoryItem -> {
                val categoryId = uri.pathSegments[1]
                db.query("Category", projection, "id=?", arrayOf(categoryId), null, null, sortOrder)
            }
            else->null
        }
        cursor

    }

    /**
     * 得到数据类型*/

    override fun getType(uri: Uri) = when (uriMatcher.match(uri)) {
        bookDir -> "vnd.android.cursor.dir/vnd.com.cnstrong.leke.helloworld.provider.book"
        bookItem -> "vnd.android.cursor.item/vnd.com.cnstrong.leke.helloworld.provider.book"
        categoryDir -> "vnd.android.cursor.dir/vnd.com.cnstrong.leke.helloworld.provider.category"
        categoryItem -> "vnd.android.cursor.item/vnd.com.cnstrong.leke.helloworld.provider.category"
        else -> null
    }

    /**插入数据
     *
     *  override fun insert(uri: Uri, values: ContentValues?): Uri? {
    //获取到SQLiteDatabase 对象
    val db = dbHelper?.writableDatabase
    val uriReturn = when (uriMatcher.match(uri)) {
    bookDir, bookItem -> {
    val newBookId = db?.insert("Book", null, values)
    Uri.parse("content://$authority/book/$newBookId")
    }
    categoryDir, categoryItem -> {
    val newCategoryId = db?.insert("Category", null, values)
    Uri.parse("content://$authority/category/$newCategoryId")
    }
    else -> null
    }
    return uriReturn


    }*/

    override fun insert(uri: Uri, values: ContentValues?) = dbHelper?.let {
        //获取到SQLiteDatabase 对象
        val db = it.writableDatabase
        val uriReturn = when (uriMatcher.match(uri)) {
            bookDir, bookItem -> {
                val newBookId = db.insert("Book", null, values)
                Uri.parse("content://$authority/book/$newBookId")
            }
            categoryDir, categoryItem -> {
                val newCategoryId = db.insert("Category", null, values)
                Uri.parse("content://$authority/category/$newCategoryId")
            }
            else ->null
        }
        uriReturn


    }

    /**删除数据*/

    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?) =
        dbHelper?.let {
            //删除数据
            val db = it.writableDatabase
            val deleteRows = when (uriMatcher.match(uri)) {
                bookDir -> db.delete("Book", selection, selectionArgs)
                bookItem -> {
                    //筛选条件参数
                    val bookId = uri.pathSegments[1]
                    db.delete("Book", "id=?", arrayOf(bookId))
                }
                categoryDir -> db.delete("Category", selection, selectionArgs)
                categoryItem -> {
                    val categoryId = uri.pathSegments[1]
                    db.delete("Category", "id=?", arrayOf(categoryId))
                }
                else -> 0
            }
            deleteRows

        } ?: 0

    /**更新数据*/

    override fun update(
        uri: Uri,
        values: ContentValues?,
        selection: String?,
        selectionArgs: Array<out String>?
    ) = dbHelper?.let {
        val db = it.writableDatabase
        val updateRows = when (uriMatcher.match(uri)) {
            bookDir -> db.update("Book", values, selection, selectionArgs)
            bookItem -> {
                val bookId = uri.pathSegments[1]
                db.update("Book", values, "id=?", arrayOf(bookId))
            }
            categoryDir -> db.update("Category", values, selection, selectionArgs)
            categoryItem -> {
                val categoryId = uri.pathSegments[1]
                db.update("Category", values, "id=?", arrayOf(categoryId))
            }
            else -> 0
        }
        updateRows

    } ?: 0
}

四:MySqliteDataHelper 数据库创建的帮助类

package com.cnstrong.leke.helloworld

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

/**
 * @author zhiqiangRuan
 * @ClassName
 * kotlin 构造函数 参数
 * val context: Context 上下文
 * name: String  数据库名,库名 xxx.db
 * version: Int 版本号,用来数据库升级的
 * @Date  2022/7/4
 */
class MySqliteDataHelper(val context: Context, name: String, version: Int) :
    SQLiteOpenHelper(context, name, null, version) {

    private val book = "create table Book( " +
            "id integer primary key autoincrement," +
            "author text," +
            "price real," +
            "pages integer," +
            "name text)"


    private val category = "create table Category( " +
            "id integer primary key autoincrement," +
            "category_name text," +
            "category_code integer)"


    /**使用SQliteDatabase创建数据表
     *
     * 1.这个方法,第一次打开数据库时候才会走
     * 2.在清除数据之后再一次运行-->打开数据库,这个方法会走
     * 3.没有清除数据,不会走这个方法
     * 4.数据库升级的时候这个方法不会走
     * */
    override fun onCreate(db: SQLiteDatabase?) {
        db?.execSQL(book)
        db?.execSQL(category)
        Toast.makeText(context, "create books success", Toast.LENGTH_SHORT).show()

    }


    /**
     * 1.第一次创建数据库的时候,这个方法不会走
     *
     *2.清除数据再次运行(相当于第一次创建)这个方法不会走
     *
     * 3.数据库已经存在,而且版本升高的时候,这个方法才会调用*/
    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
        //根据版本号判断
        if (oldVersion <= 1) {
            db?.execSQL("alter table Book add column category_id")
        }
    }


    /**这个方法是数据库降级操作
     *
     * 1.新版本比旧版本低时候才会执行
     *
     * 2.如果不执行降级操作会抛出异常*/

    override fun onDowngrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
        super.onDowngrade(db, oldVersion, newVersion)
    }
}

五:MyProvider的AndroidManifest配置

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.cnstrong.leke.helloworld">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MyApplication"
        android:usesCleartextTraffic="true">
        <activity android:name=".FiveActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".FirstActivity" />
        <activity
            android:name=".ThirdActivity"
            android:screenOrientation="landscape" />

        <provider
            android:name=".MyProvider"
            android:authorities="com.cnstrong.leke.helloworld.provider"
            android:enabled="true"
            android:exported="true">

        </provider>
    </application>

</manifest>

六:遇到的问题
image.png

不知道什么原因,有大神知道吗,需要指导一下


Rocky_ruan
57 声望5 粉丝

不积跬步,无以至千里