赞
踩
ContentProvider 是 Android 的四大组件之一,有时候我们需要操作其他应用程序的一些数据,就会用到 ContentProvider,ContentProvider 本质上是一个中间者,真正 存储和操作数据 的数据源还是原来存储数据的方式,如数据库、文件或网络等。
ContentProvider 以相对安全的方式封装了数据并提供简易的处理机制和统一的访问接口供其他程序调用。它的底层采用了 Binder 机制来实现,ContentProvider 为应用间的数据交互提供了一个安全的环境:允许把自己的应用数据根据需求开放给 其他应用进行增删改查,而不用担心因为直接开放数据库权限而带来的安全问题。当然,ContentProvider不仅可以实现跨进程通信,也可实现进程内的通信。
在 Android 中,为一些常见的数据提供了默认的 ContentProvider,如通讯录等。
1.我们首先需要创建一个provider
这个uri填写你创建的那个文件夹的目录
步骤一:创建数据库类,并建立一个student表
- package com.example.provider;
-
- import android.content.Context;
- import android.database.sqlite.SQLiteDatabase;
- import android.database.sqlite.SQLiteOpenHelper;
- import android.widget.Button;
-
- import androidx.annotation.Nullable;
-
- public class MyDBhelper extends SQLiteOpenHelper {
-
- public MyDBhelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
- super(context,name ,null, version);
- }
-
- @Override
- public void onCreate(SQLiteDatabase sqLiteDatabase) {
- sqLiteDatabase.execSQL("create table student(" +
- "id integer primary key autoincrement," +
- "name varchar(20)," +
- "age interger)");
- }
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
-
- }
- }

步骤二:创建一个 MyContentProvider ,继承自 ContentProvider 抽象类。其中,在 onCreate() 方法中,先对数据库初始化,并往数据库中的student表中添加两条数据。
- package com.example.provider;
-
- import android.content.ContentProvider;
- import android.content.ContentValues;
- import android.database.Cursor;
- import android.net.Uri;
-
- public class MyContentProvider extends ContentProvider {
- public MyContentProvider() {
- }
-
-
-
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- return 0;
- }
-
- @Override
- public String getType(Uri uri) {
- return null;
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- System.out.println(uri+"====insert方法被调用====");
- System.out.println("values参数为:"+values);
- return null;
- }
-
- @Override
- public boolean onCreate() {
- System.out.println("====onCreate方法被调用====");
- return true;
- }
-
- @Override
- public Cursor query(Uri uri, String[] projection, String selection,
- String[] selectionArgs, String sortOrder) {
- System.out.println(uri+"===query方法被调用===");
- System.out.println("where参数为:"+"where");
- return null;
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String selection,
- String[] selectionArgs) {
- System.out.println(uri+"===update方法被调用===");
- System.out.println("where参数为:“where+”,values参数为:"+values);
- return 0;
- }
- }

步骤三:注册(一般建立的时候会自动注册,不过还是最好瞅一下有没有)
- <provider
- android:name=".MyContentProvider"
- android:authorities="com.example.provider"
- android:enabled="true"
- android:exported="true" >
- </provider>
步骤四:进程内使用 ContentResolver 操作 ContentProvider。
- private fun operateData() {
- val student = Uri.parse("content://com.example.provider/student")
-
- // 向 student 表插入一条数据
- contentResolver.insert(userUri, ContentValues().apply {
- put("id", 3)
- put("name", "chen")
- put("age","18")
- })
-
- // 查询 student 表数据
- val cursor = contentResolver.query(userUri, arrayOf("id", "name","age"), null, null, null)
- while (cursor!!.moveToNext()) {
- println("query user:" + cursor.getInt(0) + " " + cursor.getString(1))
- }
- // 主动关闭游标
- cursor.close()
- }
-

上面是一个app的操作,下面是两个app的跨进程使用
步骤一:创建数据库类,建表
- class DBHelper(
- context: Context
- ) : SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {
-
- override fun onCreate(db: SQLiteDatabase) {
- // 创建两个表格:用户表 和 职业表
- db.execSQL("CREATE TABLE IF NOT EXISTS $USER_TABLE_NAME(_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)")
- db.execSQL("CREATE TABLE IF NOT EXISTS $JOB_TABLE_NAME(_id INTEGER PRIMARY KEY AUTOINCREMENT, job TEXT)")
- }
-
- override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {}
-
- companion object {
- // 数据库名
- private const val DATABASE_NAME = "finch.db"
-
- // 表名
- const val USER_TABLE_NAME = "user"
- const val JOB_TABLE_NAME = "job"
-
- //数据库版本号
- private const val DATABASE_VERSION = 1
- }
- }

步骤二:创建一个 MyContentProvider ,继承自 ContentProvider 抽象类。其中,在 onCreate() 方法中,先对数据库初始化,并往数据库中的 user 表和 job 表分别添加两条数据。
- class MyContentProvider : ContentProvider() {
- private lateinit var mDbHelper: DBHelper
- private lateinit var db: SQLiteDatabase
-
- private val mMatcher: UriMatcher by lazy {
- val matcher = UriMatcher(UriMatcher.NO_MATCH)
- matcher.addURI(AUTHORITY, "user", User_Code)
- matcher.addURI(AUTHORITY, "job", Job_Code)
- matcher
- }
-
- override fun onCreate(): Boolean {
- mDbHelper = DBHelper(context!!)
- db = mDbHelper.writableDatabase
- // 初始化两个表的数据 (先清空两个表,再各加入一个记录)
- db.execSQL("delete from user")
- db.execSQL("insert into user values(1,'yang');")
- db.execSQL("insert into user values(2,'zhang');")
- db.execSQL("delete from job")
- db.execSQL("insert into job values(1,'Android');")
- db.execSQL("insert into job values(2,'iOS');")
- return true
- }
-
- override fun insert(uri: Uri, values: ContentValues?): Uri {
- val table = getTableName(uri)
- db.insert(table, null, values)
- // 通知外部调用者数据发生变化
- context?.contentResolver?.notifyChange(uri, null)
- return uri
- }
-
- override fun query(
- uri: Uri, projection: Array<String>?, selection: String?,
- selectionArgs: Array<String>?, sortOrder: String?
- ): Cursor? {
- val table = getTableName(uri)
- return db.query(table, projection, selection, selectionArgs, null, null, sortOrder, null)
- }
-
- override fun update(
- uri: Uri, values: ContentValues?, selection: String?,
- selectionArgs: Array<String>?
- ): Int {
- return 0
- }
-
- override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
- return 0
- }
-
- override fun getType(uri: Uri): String? {
- return null
- }
-
- private fun getTableName(uri: Uri): String? {
- var tableName: String? = null
- when (mMatcher.match(uri)) {
- User_Code -> tableName = DBHelper.USER_TABLE_NAME
- Job_Code -> tableName = DBHelper.JOB_TABLE_NAME
- }
- return tableName
- }
-
- companion object {
- private const val AUTHORITY = "com.yang.provider.myprovider"
- const val User_Code = 1
- const val Job_Code = 2
- }
- }

步骤三:在 androidManifest.xml 中注册 MyContentProvider
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="xxx.xxxx">
- <!--声明使用 MyContentProvider 的通信的权限 (开放所有权限) -->
- <permission
- android:name="com.yang.provider.myprovider.PROVIDER"
- android:protectionLevel="normal" />
- <!--声明使用 MyContentProvider 的通信的权限 (开放读权限) -->
- <permission
- android:name="com.yang.provider.myprovider.Read"
- android:protectionLevel="normal" />
- <!--声明使用 MyContentProvider 的通信的权限 (开放写权限) -->
- <permission
- android:name="com.yang.provider.myprovider.Write"
- android:protectionLevel="normal" />
-
- <application>
- <!--通过 android:permission、readPermission、writePermission 等属性定义 MyContentProvider 的通信权限-->
- <provider
- android:name=".MyContentProvider"
- android:authorities="com.yang.provider.myprovider"
- android:exported="true"
- android:permission="com.yang.provider.myprovider.PROVIDER"
- // android:readPermission="com.yang.provider.myprovider.Read"
- // android:writePermission="com.yang.provider.myprovider.Write"
- />
-
- </application>
- </manifest>

第二个app中
步骤一:声明访问进行 1 中的 ContentProvider 所需要的权限
<uses-permission android:name="com.yang.provider.myprovider.PROVIDER" />
步骤二:使用 ContentResolver 操作 进程 1 的 ContentProvider。
- private fun operateData() {
- val userUri = Uri.parse("content://com.yang.provider.myprovider/user")
- val jobUri = Uri.parse("content://com.yang.provider.myprovider/job")
-
- // 对 user 表进行操作
- contentResolver.insert(userUri, ContentValues().apply {
- put("_id", 4)
- put("name", "huang")
- })
-
- val cursor = contentResolver.query(userUri, arrayOf("_id", "name"), null, null, null)
- while (cursor!!.moveToNext()) {
- println("ipc query user:" + cursor.getInt(0) + " " + cursor.getString(1))
- }
- cursor.close()
-
- // 对 job 表进行操作
- contentResolver.insert(jobUri, ContentValues().apply {
- put("_id", 4)
- put("job", "algorithm")
- })
-
- val cursor2 = contentResolver.query(jobUri, arrayOf("_id", "job"), null, null, null)
- while (cursor2!!.moveToNext()) {
- println("ipc query job:" + cursor2.getInt(0) + " " + cursor2.getString(1))
- }
- cursor2.close()
- }
-
- // 执行 operateData() 方法,输出结果如下:
- I/System.out: ipc query user:1 yang
- I/System.out: ipc query user:2 zhang
- I/System.out: ipc query user:4 huang
- I/System.out: ipc query job:1 Android
- I/System.out: ipc query job:2 iOS
- I/System.out: ipc query job:4 algorithm

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。