Kotlin ContentProvider使用方法详解

目录
  • ContentProvider提供者
  • contentResolver获取短信数据
  • ContentObserver监控短信的到来
  • 小结

android的四大组件,已经介绍了两个,这一节介绍ContentProvider。前面的广播可以进行 app内的通讯,如果需要进行app之间的通讯,在android 中使用的是ContentProviderContentProvider 也分为三种,一,作为数据的存储和查询,也就是别人来调用你ContentProvider。二,调用者ContentResolver ,用来调用插入和查询数据。三,观察者ContentObserver ,比如监控短信的变化。

ContentProvider提供者

ContentProvider 提供者作为一个母体,用来通过数据的查询和插入,这样做的好处是,让每个服务都相互独立,而且有可以像外部提供相应的接口。比如通讯录,短信息等。他们作为一种服务,根据用户的权限来提供特有的服务。

这里我们也建立一个ContentProvider ,用户可以来调用,提供查询和插入的功能。我们用sqlite对数据进行存储和查询。

    inner class DBHelper(context:Context,name:String,
                         factory:SQLiteDatabase.CursorFactory?,version:Int):SQLiteOpenHelper(context,name,factory, version){
        override fun onCreate(_db: SQLiteDatabase?) {
            var sql:String = "CREATE TABLE " + DATUM_TABLE_NAME +
                    " (" + "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
                    Constants.TEXT+
                    " VARCHAR(20)" + ")"
            _db?.execSQL(sql)
        }
        override fun onUpgrade(_db: SQLiteDatabase?, p1: Int, p2: Int) {
            var sql:String = "DROP TABLE IF EXISTS " + DATUM_TABLE_NAME
            _db?.execSQL(sql)
            onCreate(_db)
        }
    }

创建 ContentProvider

class DataProvider : ContentProvider() 

实现两个接口 queryinsert

    override fun query(
        uri: Uri,
        p: Array<out String>?,
        s: String?,
        args: Array<out String>?,
        sort: String?
    ): Cursor? {
        val qb = SQLiteQueryBuilder()
        qb.tables = DATUM_TABLE_NAME
        qb.projectionMap = projMap
        var s1 = s
        if (sUriMatcher.match(uri) != DATUM) {
            if (sUriMatcher.match(uri) == DATUM_ID)
                s1 = s + "_id = " + uri?.lastPathSegment
            else
                throw IllegalArgumentException("Unknown URI " + uri)
        }
        val db = dbHelper?.readableDatabase
        val c = qb.query(db, p, s1, args, null, null, sort)
        c.setNotificationUri(context?.contentResolver ?: null, uri)
        return c
    }

insert 接口

   override fun insert(uri: Uri, cv: ContentValues?): Uri? {
        var m:Int = sUriMatcher.match(uri).toInt()
        m = 1
        if (m != 1){
            throw IllegalArgumentException("Unknown URI " + uri)
        }
        val v: ContentValues
        if (cv != null)
            v = ContentValues(cv)
        else
            v = ContentValues()
        val db = dbHelper?.writableDatabase
        val rId = db?.insert(DATUM_TABLE_NAME, Constants.TEXT, v)
        if (rId != null) {
            if (rId > 0) {
                val uri = ContentUris.withAppendedId(Constants.URL, rId)
                context?.contentResolver?.notifyChange(uri, null)
                return uri
            }
        } else {
            throw SQLException("Failed to insert row into " + uri)
        }
        return null
    }

如何调用呢?

        var textView = findViewById<TextView>(R.id.textView)
        var btn = findViewById<Button>(R.id.btn)
        // Inserting data into content provider
        val tuple = ContentValues()
        tuple.put(Constants.TEXT, Constants.TEXT_DATA)
        contentResolver.insert(Constants.URL, tuple)
        // Reading from content provider
        val cols = arrayOf(Constants.ID, Constants.TEXT)
        val u = Constants.URL
        val c = contentResolver.query(u, cols, null, null, null)
        if (c!!.moveToLast())
            textView.text = "Data read from content provider: " +
                    c!!.getString(c.getColumnIndex(Constants.TEXT))
        else
            textView.text = "Access denied"

AndroidManifest.xml 上 添加:

        <provider
            android:name="com.kotlin.kotlin_start_ch16.DataProvider"
            android:authorities="com.kotlin.kotlin_start_ch16.provider"
            android:exported="true"
            android:multiprocess="true"/>

模拟插入数据后,对数据进行查询,并显示在textview上。

contentResolver获取短信数据

app获取短信需要相应的权限,首先要确认和申请权限。在AndroidManifest.xml 上添加,

<uses-permission android:name="android.permission.READ_SMS" />

这样还不够,需要进行权限的用户授权。

fun checkPermission():Boolean{
        var result = ContextCompat.checkSelfPermission(applicationContext,Manifest.permission.READ_SMS)
        return result==PackageManager.PERMISSION_GRANTED
    }
    fun requestPermission(i:Int){
        ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_SMS),i)
    }
    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    }

当用户确认以后,才可以进行短信的获取。

        if (!checkPermission()){
            requestPermission(123)
        }
        btn.setOnClickListener {
            val cols = arrayOf("_id","address","date","type","body")
            var c = contentResolver.query(Uri.parse("content://sms/"),cols,null,null, null)
            while (c!!.moveToNext()){
                var body=c.getString(4)
                textView.text = body
                var s = SmsInfo(c.getInt(0),c.getString(1),c.getLong(2),c.getString(4))
                sms.add(s)
            }
            var text:String = ""
            sms.forEach{
                text = text + it.address + "\n"
                text = text + it.info + "\n"
            }
            textView.text = text
        }

ContentObserver监控短信的到来

ContentObserver监控短信同样的需要相应的权限,可以看看上节的代码,要监控短信需要新建一个类继承ContentObserver,并进行注册:

            smsContentObserver = SmsContentObserver(this, Handler(Looper.getMainLooper()), conversationsHandler)
            //smsContentObserver = SmsContentObserver(this, Handler(Looper.getMainLooper()))
            smsContentObserver?.let {
                //it.start()
                contentResolver.registerContentObserver(Telephony.Sms.CONTENT_URI, true, it)
                contentResolver.registerContentObserver(Telephony.Mms.CONTENT_URI, true, it)
                contentResolver.registerContentObserver(Telephony.MmsSms.CONTENT_URI, true, it)
            }

收到短信后,对短信进行处理:

    private fun newSms() {
        val newSms: Map<Int, SmsObject> = smsDeleteDetector.newSms()
        newSms.forEach {
            if ((it.value._type).toInt() == Telephony.Sms.Inbox.MESSAGE_TYPE_INBOX) {
                logToastHelper.showLogMsg(
                    context,
                    "$tag Inbox ID:${it.value._id}  ThreadId:${it.value._threadId} ",
                    "SMS From ${it.value._address} : ${it.value._body}"
                )
            } else if (((it.value._type).toInt()) == Telephony.Sms.Inbox.MESSAGE_TYPE_SENT) {
                logToastHelper.showLogMsg(
                    context,
                    "$tag Outbox ID:${it.value._id}  ThreadId:${it.value._threadId}",
                    "SMS Sent To ${it.value._address} : ${it.value._body}"
                )
            }
        }
    }

小结

如果一步一步的进行安卓基础知识的学习,会觉得android的设计还是很有层次的,每一组组件都设计的比较完善,编程者用起来其实都会觉得比较简单的。

到此这篇关于Kotlin ContentProvider使用方法详解的文章就介绍到这了,更多相关Kotlin ContentProvider内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Kotlin ContentProvider使用方法介绍

    目录 1.注册ContentProvider 2.内容URI 内容URI的标准格式 通配符 3.创建自己的ContentProvider 4.访问其他程序中的数据 1.注册ContentProvider 右击com.example.myapplication包->New->Other->Content Provider.会弹出窗口 点击finish,完成创建ContentProvider类,这时你可以在注册代码中看到 <provider android:name=".My

  • Kotlin ContentProvider使用方法详解

    目录 ContentProvider提供者 contentResolver获取短信数据 ContentObserver监控短信的到来 小结 android的四大组件,已经介绍了两个,这一节介绍ContentProvider.前面的广播可以进行 app内的通讯,如果需要进行app之间的通讯,在android 中使用的是ContentProvider.ContentProvider 也分为三种,一,作为数据的存储和查询,也就是别人来调用你ContentProvider.二,调用者ContentRes

  • Kotlin全局捕捉协程异常方法详解

    单个异常捕捉 val handler = CoroutineExceptionHandler { coroutineContext, throwable -> Log.d(TAG, "onCreate: handler${throwable}") } Log.d(TAG, "onCreate:1") findViewById<Button>(R.id.button).also { it.setOnClickListener { GlobalScop

  • Kotlin 单例实例详解

    Kotlin 单例实例详解 单例的实现方法,可以通过同伴对象,或者 lazy. 示例: class Hello private constructor() { companion object { val instance = Hello() } } 通过 lazy 实现 class Hello private constructor() { private object Holder { val INSTANCE = Hello() } companion object { val insta

  • Android中ContentProvider和ContentResolver详解

    Android中ContentProvider和ContentResolver详解 在Android中,我们的应用有的时候需要对外提供数据接口,可以有如下几种方法: 1)AIDL 2)Broadcast 3)ContentProvider. 使用AIDL需要我们编写AIDL接口以及实现,而且对方也要有相应的接口描述,有点麻烦:使用Broadcast,我们不需要任何接口描述,只要协议文档就可以了,但是有点不好就是,这种方式不直接而且是异步的:使用ContentProvider我们不需要接口描述,只

  • Android 中ContentProvider的实例详解

    Android 中ContentProvider的实例详解 Content Provider 的简单介绍: * Android中的Content Provider 机制可支持在多个应用中存储和读取数据.这也是跨应用 共享数据的唯一方式.在Android系统中,没有一个公共的内存区域,供多个应用共享存储数据: * Android 提供了一些主要数据类型的ContentProvider ,比如:音频.视频.图片和私人通讯录等: 在android.provider 包下面找到一些android提供的C

  • Kotlin null的处理详解

    Kotlin null的处理详解 NullPointerException,俗称NPE,不管菜鸟还是老鸟们,都是不可避免,经常遇到的一个异常,解释起来很简单,就"空指针"三个字.总是在一次不小心,而掉进这个陷阱里.Kotlin 的设计目标就是希望消除代码中 null 引用带来的危险, 也就是所谓的造成十亿美元损失的大错误. NPE的原因 尽管Kotlin希望消除代码中的NPE,我们总是不小心,总会不小心又掉进NPE的陷阱,下面是可能NPE的原因: 明确调用 throw NullPoin

  • Kotlin 的注解类详解及实例

    Kotlin 的注解类详解及实例 注解声明 注解是将元数据附加到代码的方法.要声明注解,请将 annotation 修饰符放在类的前面: annotation class Fancy 注解的附加属性可以通过用元注解标注注解类来指定: @Target 指定可以用 该注解标注的元素的可能的类型(类.函数.属性.表达式等): @Retention 指定该注解是否 存储在编译后的 class 文件中,以及它在运行时能否通过反射可见 (默认都是 true): @Repeatable 允许 在单个元素上多次

  • Android 使用View Binding的方法详解

    前言 Android Studio稳定版发布了3.6版本,带来了一些新变化:首先外观,启动页变了,logo改了,更显现代化:增加Multi Preview功能,能同时预览多个尺寸屏幕的显示效果:模拟器支持多屏:也终于支持全新的视图绑定组件View Binding:等. 之前我们与视图交互的方式有findViewById.kotlin中引入Android Kotlin Extensions后直接通过id进行访问.前者模板化严重,重复代码多:后者最为方便.现在有了新的选择–View Binding,

  • Android 通过代码安装 APK的方法详解

    在 APK 开发中,通过 Java 代码来打开系统的安装程序以安装 APK 并不是什么难事,一般的 Android 系统都有开放这一功能. 但随着 Android系统版本的迭代,其对于权限的把控越来越严格,或者说是变得越来越注重安全性.这就导致了以前可以通过很简单的几行代码就能实现的功能,现在要复杂很多. 对于通过代码打开系统安装程序这一功能的限制,其分水岭在 Android7.0,即 Android N 上.通常在 Android N以上的系统使用一种做法,以下则使用另一种做法. 传统的通过代

  • kotlin之闭包案例详解

    闭包,函数式编程福音 先了解函数式编程(Functional Programming) 概念:它属于"结构化编程"的一种,主要思想是把运算过程尽量写成一系列嵌套的函数调用.函数式编程语言最重要的基础是λ运算(Lambda表达式),λ运算的函数可以接受函数当做参数或返回值. 对比函数式编程与面向对象编程 面向对象编程(Object-oriented programming,缩写OOP) 面向对象编程是一种具有对象概念的程序编程范型,它可能包含数据.属性.方法.它将对象作为程序的基本单元,

随机推荐