Android内容提供器ContentProvider实现数据共享功能
ContentProvider
一、内容提供器介绍
内容提供器(ContentProvider)主要用于在不同的应用程序之间实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访问数据的安全性。
内容提供器可以选择只对哪一部分数据进行共享,从而保证我们程序中的隐私数据不会有泄漏的风险
二、内容提供器构成
1.使用方法
- 使用现有的内容提供器来读取和操作相应程序中的数据
- 创建自己的内容提供器给我们程序的数据提供外部访问接口
2.ContentResolver
程序通过ContentResolver类来访问ContentProvider*享的数据,通过Context中getContentResolver()方法来获取该类的实例
- insert() 用于添加数据
- update() 用于更新数据
- delete() 用于删除数据
- query() 用于查询数据
3.URI
-
authority
用于对不同的应用程序作区分,一般为了避免冲突,都会采用程序包名的方式来进行命名 -
path
用于对同一应用程序中不同的表作区分,通常添加到authority后面
内容URI标准格式写法"content://" + authority + path:
content://com.example.app.provider/table1
content://com.example.app.provider/table2/1
以路径结尾就表示期望访问表中所有数据,id结尾则表示访问表中拥有相应id的数据
有了URI后还需要将其解析为Uri对象
Uri uri = Uri.parse("content://com.example.app.provider/table1")
我们也可以用通配符来匹配内容URI
*:表示匹配任意长度的任意字符
#:表示匹配任意长度的数字
我们可以借助UriMatcher来匹配内容URI功能(映射)
public static final String AUTHORITY = "com.example.savetest.provider"; public static final int BOOK_DIR = 0; public static final int BOOK_ITEM = 1; public static final int CATEGORY_DIR = 2; public static final int CATEGORY_ITEM = 3; static { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(AUTHORITY, "book", BOOK_DIR); uriMatcher.addURI(AUTHORITY, "book/#", BOOK_ITEM); uriMatcher.addURI(AUTHORITY, "category", CATEGORY_DIR); uriMatcher.addURI(AUTHORITY, "category/#", CATEGORY_ITEM); } ... public Cursor query(Uri uri, ...) { switch ((uriMatcher.match(uri))){ case BOOK_DIR: // 查询Book表所有数据 break; case BOOK_ITEM: // 查询Book表单条数据 break; case CATEGORY_DIR: // 查询Category所有数据 break; case CATEGORY_ITEM: // 查询Category单条数据 break; default: break; } ... }
4.MIME格式
getType()方法用于获取Uri对象所对应的MIME类型,其中MIME格式有如下组成:
- 以vnd开头
- 如果URI以路径结尾,则接android.cursor.dir/ 如果以id结尾,则接 android.cursor.item/
- 最后接上vnd.< authority >.< path >
content://com.example.app.provider/table
对应MIME:vnd.android.cursor.dir/vnd.com.example.app.provider.table
5.ContentProvider
我们可以通过新建一个类去继承ContentProvider的方式来创建一个自己的内容提供器,我们需要重写以下6个方法
-
onCreate()
初始化时调用,返回true表示初始化成功,返回false表示失败 -
query()
查询数据,uri表示查询哪张表,projection表示查询哪些列,selection和selectionArgs用于约束查询哪些行,sortOrder用于对结果排序,查询结果存放在Cursor对象中返回 -
insert()
添加数据,uri确定添加到哪张表,values用于保存待添加的数据。添加完成后,返回一个表示该数据的URI -
update()
更新已有的数据。uri确定更新的表,values保存新数据,selection和selectionArgs用于约束更新哪些行,受影响的行数作为返回值返回 -
delete()
删除数据。uri确定删除的表,selection和selectionArgs用于约束删除哪些行,被删除的行数作为返回值返回 -
getType()
根据传输的内容URI来返回相应的MIME类型
三、具体实现
ContentProvider:
package com.example.savetest; import android.content.ContentProvider; import android.content.ContentValues; import android.content.UriMatcher; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; public class MyContentProvider extends ContentProvider { public static final int BOOK_DIR = 0; public static final int BOOK_ITEM = 1; public static final int CATEGORY_DIR = 2; public static final int CATEGORY_ITEM = 3; public static final String AUTHORITY = "com.example.savetest.provider"; private static UriMatcher uriMatcher; private MyDatabaseHelper dbHelper; static { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(AUTHORITY, "book", BOOK_DIR); uriMatcher.addURI(AUTHORITY, "book/#", BOOK_ITEM); uriMatcher.addURI(AUTHORITY, "category", CATEGORY_DIR); uriMatcher.addURI(AUTHORITY, "category/#", CATEGORY_ITEM); } public MyContentProvider() { } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { SQLiteDatabase db = dbHelper.getReadableDatabase(); int deletedRows = 0; switch ((uriMatcher.match(uri))){ case BOOK_DIR: deletedRows = db.delete("Book", selection, selectionArgs); break; case BOOK_ITEM: deletedRows = db.delete("Book", "id = ?", selectionArgs); break; case CATEGORY_DIR: deletedRows = db.delete("Category", selection, selectionArgs); break; case CATEGORY_ITEM: deletedRows = db.delete("Category", "id = ?", selectionArgs); break; default: break; } return deletedRows; } @Override public String getType(Uri uri) { switch ((uriMatcher.match(uri))){ case BOOK_DIR: return "vnd.android.cursor.dir/vnd.com.example.savetest.provider.Book"; case BOOK_ITEM: return "vnd.android.cursor.item/vnd.com.example.savetest.provider.Book"; case CATEGORY_DIR: return "vnd.android.cursor.dir/vnd.com.example.savetest.provider.Category"; case CATEGORY_ITEM: return "vnd.android.cursor.item/vnd.com.example.savetest.provider.Category"; default: break; } return null; } @Override public Uri insert(Uri uri, ContentValues values) { SQLiteDatabase db = dbHelper.getWritableDatabase(); Uri uriReturn = null; switch ((uriMatcher.match(uri))){ case BOOK_DIR: case BOOK_ITEM: long newBookId = db.insert("Book", null, values); uriReturn = Uri.parse("content://" + AUTHORITY + "/book/" + newBookId); break; case CATEGORY_DIR: case CATEGORY_ITEM: long newCategoryId = db.insert("CategoryId", null, values); uriReturn = Uri.parse("content://" + AUTHORITY + "/book/" + newCategoryId); break; default: break; } return uriReturn; } @Override public boolean onCreate() { dbHelper = new MyDatabaseHelper(getContext(), "BookStore.db", null, 1); return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteDatabase db = dbHelper.getReadableDatabase(); Cursor cursor = null; switch ((uriMatcher.match(uri))){ case BOOK_DIR: cursor = db.query("Book", projection, selection, selectionArgs, null, null, sortOrder); break; case BOOK_ITEM: cursor = db.query("Book", projection, "id = ?", selectionArgs, null, null, sortOrder); break; case CATEGORY_DIR: cursor = db.query("Category", projection, selection, selectionArgs, null, null, sortOrder); break; case CATEGORY_ITEM: cursor = db.query("Category", projection, "id = ?", selectionArgs, null, null, sortOrder); break; default: break; } return cursor; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { SQLiteDatabase db = dbHelper.getReadableDatabase(); int updateRows = 0; switch ((uriMatcher.match(uri))){ case BOOK_DIR: updateRows = db.update("Book", values, selection, selectionArgs); break; case BOOK_ITEM: updateRows = db.update("Book", values, "id = ?", selectionArgs); break; case CATEGORY_DIR: updateRows = db.update("Category", values, selection, selectionArgs); break; case CATEGORY_ITEM: updateRows = db.update("Book", values, "id = ?", selectionArgs); break; default: break; } return updateRows; } }
DatabaseHelper:
package com.example.savetest; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.widget.Toast; public class MyDatabaseHelper extends SQLiteOpenHelper { public static final String CREATE_BOOK = "create table Book (" + "id integer primary key autoincrement, " + "author text, " + "price real, " + "pages integer, " + "name text)"; public static final String CREATE_CATEGORY = "create table Category (" + "id integer primary key autoincrement, " + "category_name text, " + "category_code integer)"; private Context mContext; public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version){ super(context, name, factory, version); mContext = context; } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_BOOK); db.execSQL(CREATE_CATEGORY); Toast.makeText(mContext, "创建数据库表", Toast.LENGTH_SHORT).show(); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
MainActivity:
package com.example.savetest; import androidx.appcompat.app.AppCompatActivity; import android.content.ContentValues; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private MyDatabaseHelper dbHelper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); inputText = (EditText) findViewById(R.id.input_text); showText = (TextView) findViewById(R.id.show_text); // 创建数据库表 dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 1); sqlSave.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { SQLInsertData(); } }); sqlLoad.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { SQLSelectData(); } }); } // 使用SQL添加数据 public void SQLInsertData(){ SQLiteDatabase db = dbHelper.getWritableDatabase(); ContentValues values = new ContentValues(); values.put("name", "The Da Vinci Code"); values.put("author", "Dan Brown"); values.put("pages", 454); values.put("price", 16.96); db.insert("Book", null, values); values.clear(); values.put("name", "The Lost Symbol"); values.put("author", "Dan Brown"); values.put("pages", 510); values.put("price", 19.95); db.insert("Book", null, values); } // 使用SQL读取数据 public void SQLSelectData(){ SQLiteDatabase db = dbHelper.getWritableDatabase(); Cursor cursor = db.query("Book", null, null, null, null, null, null); Log.d(TAG, "SQLSelectData: "); if (cursor.moveToFirst()){ do { // 遍历Cursor对象,取出所有数据打印 String name = cursor.getString(cursor.getColumnIndex("name")); String author = cursor.getString(cursor.getColumnIndex("author")); int pages = cursor.getInt(cursor.getColumnIndex("pages")); double price = cursor.getDouble(cursor.getColumnIndex("price")); Log.d(TAG, "name: " + name); Log.d(TAG, "author: " + author); Log.d(TAG, "pages: " + pages); Log.d(TAG, "price: " + price); } while(cursor.moveToNext()); } cursor.close(); } }
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.savetest"> <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/AppTheme"> <provider android:name=".MyContentProvider" android:authorities="com.example.savetest.provider" android:enabled="true" android:exported="true"></provider> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
四、个人理解
- 将数据private化,让自己成为getter()、setter(),提供ContentResolver的CRUD方法给其他程序来读取数据
- 其他程序通过Uri访问数据库,本质是ContentResolver提供方法,然后通过ContentProvider去访问数据库
本文地址:https://blog.csdn.net/woshijuzizi/article/details/107726734