在Android Studio中如何实现contentprovider实验+SQLite数据库(保姆级教程)

简介: 目录 一.本章要学习的内容 二.代码部分 (一)创建项目 (二)项目结构 (三)MainActivity (四)ContentActivity (五)PersonDBOpenHelper (六)PersonPro

目录

一.本章要学习的内容

二.代码部分

(一)创建项目

(二)项目结构

(三)MainActivity

(四)ContentActivity

(五)PersonDBOpenHelper

(六)PersonProvider

(七)SQLActivity

(八)activity_main.xml

(九)contentlayout.xml

(十)sqllayout.xml

(十一)strings.xml

(十二)AndroidManifest.xml

三.运行部分

[(一)打开Device Manager](#(一)打开Device Manager)

(二)选择上次创建的虚拟机

(三)运行

(四)运行结果

四.ContentProvider

前言

(一)ContentProvider基础介绍

[1.1 简介](#1.1 简介)

[1.2 作用](#1.2 作用)

[1.3 实现原理](#1.3 实现原理)

(二)具体使用

[2.1 统一资源标识符(URI)](#2.1 统一资源标识符(URI))

[2.2 MIME数据类型](#2.2 MIME数据类型)

[2.2.1 MIME类型组成](#2.2.1 MIME类型组成)

[2.2.2 常见的MIME类型](#2.2.2 常见的MIME类型)

[2.2.3 ContentProvider根据 URI 返回MIME类型](#2.2.3 ContentProvider根据 URI 返回MIME类型)

[2.2.4 类型分类](#2.2.4 类型分类)

[2.3 ContentProvider三剑客](#2.3 ContentProvider三剑客)

[2.4 辅助工具类](#2.4 辅助工具类)

(三)总结

一.本章要学习的内容

掌握如何在Android 开发中使用 SQLite 数据库

熟悉设计数据库表结构的方法与步骤

理解contentprovider的使用方法及流程,理解ContentProvider、Resolver、Uri、Urimatcher等的原理。

1、实现contentprovider和contentresolver通过uri的调用;

2、实现contentprovider对数据库sqlite的功能:增、删、改、查;

3、数据库的表结构自行设计;

1、配置SQLite 数据库的运行环境

2、熟悉contentprovider对数据库sqlite增、删、改、查的具体操作和流程

3、充分理解SQLite数据库的使用原理和方式

二.代码部分

(一)创建项目

(二)项目结构

(三)MainActivity

复制代码

package com.example.demo6;

import androidx.appcompat.app.AppCompatActivity;

import androidx.core.app.ActivityCompat;

import androidx.core.content.ContextCompat;

import android.Manifest;

import android.content.Intent;

import android.content.pm.PackageManager;

import android.os.Bundle;

import android.view.View;

import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

}

public void toOne(View view) {

if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)!= PackageManager.PERMISSION_GRANTED)

{

ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_CONTACTS},1);

Toast.makeText(this,"未允许读取通讯录权限!",Toast.LENGTH_SHORT).show();

}

if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)== PackageManager.PERMISSION_GRANTED)

{

Intent intent = new Intent(MainActivity.this,ContentActivity.class);

startActivity(intent);

}

}

public void toTwo(View view) {

Intent intent = new Intent(MainActivity.this,SQLActivity.class);

startActivity(intent);

}

}

(四)ContentActivity

复制代码

package com.example.demo6;

import android.Manifest;

import android.app.Activity;

import android.content.ContentResolver;

import android.content.pm.PackageManager;

import android.database.Cursor;

import android.os.Bundle;

import android.provider.ContactsContract;

import android.widget.TextView;

import androidx.annotation.Nullable;

import androidx.core.app.ActivityCompat;

import androidx.core.content.ContextCompat;

public class ContentActivity extends Activity {

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.contentlayout);

TextView textView = (TextView) findViewById(R.id.callName);

if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)!= PackageManager.PERMISSION_GRANTED)

{

ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_CONTACTS},1);

textView.setText("未允许读取通讯录权限!");

}

if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)== PackageManager.PERMISSION_GRANTED)

{

textView.setText(getQueryData());

}

}

public String getAllPhoneNumbers(String lookUp_Key){

StringBuilder allPhoneNo = new StringBuilder();

String[] proj2 = {ContactsContract.CommonDataKinds.Phone.NUMBER};

String selection = ContactsContract.Data.LOOKUP_KEY+"=?";

String[] selectionArgs = {lookUp_Key};

ContentResolver resolver = getContentResolver();

Cursor cursor = resolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,proj2,selection,selectionArgs,null);

while(cursor.moveToNext()){

allPhoneNo.append(cursor.getString(0)).append(" ");

}

return allPhoneNo.toString();

}

private CharSequence getQueryData() {

StringBuilder stringBuilder = new StringBuilder();

ContentResolver resolver = getContentResolver();

Cursor cursor = resolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,

null,null,null,null);

String name = ContactsContract.Contacts.DISPLAY_NAME;

String key = ContactsContract.Contacts.LOOKUP_KEY;

int displayNameIndex = cursor.getColumnIndex(name);

int KeyIndex = cursor.getColumnIndex(key);

for (cursor.moveToFirst();!cursor.isAfterLast();cursor.moveToNext()) {

String displayName = cursor.getString(displayNameIndex);

String Key = cursor.getString(KeyIndex);

String displayPhone = getAllPhoneNumbers(Key);

stringBuilder.append(displayName).append(" ").append(displayPhone).append("\n");

}

cursor.close();

return stringBuilder.toString();

}

}

(五)PersonDBOpenHelper

复制代码

package com.example.demo6;

import android.content.Context;

import android.database.sqlite.SQLiteDatabase;

import android.database.sqlite.SQLiteOpenHelper;

public class PersonDBOpenHelper extends SQLiteOpenHelper {

public PersonDBOpenHelper(Context context) {

super(context,"info.db",null,1);

}

@Override

public void onCreate(SQLiteDatabase db) {

db.execSQL("create table info(_id integer primary key autoincrement,name varchar(50),phone varchar(20),UNIQUE(phone))");

}

@Override

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

}

}

(六)PersonProvider

复制代码

package com.example.demo6;

import android.content.ContentProvider;

import android.content.ContentUris;

import android.content.ContentValues;

import android.content.UriMatcher;

import android.database.Cursor;

import android.database.sqlite.SQLiteDatabase;

import android.net.Uri;

import androidx.annotation.NonNull;

import androidx.annotation.Nullable;

public class PersonProvider extends ContentProvider {

private static UriMatcher mUriMatcher = new UriMatcher(-1);

private static final int SUCCESS = 1;

private PersonDBOpenHelper helper;

static {

mUriMatcher.addURI("com.example.test05_contentprovider.PersonProvider","info",SUCCESS);

}

@Override

public boolean onCreate() {

helper = new PersonDBOpenHelper(getContext());

return false;

}

@Nullable

@Override

public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {

int code = mUriMatcher.match(uri);

if (code == SUCCESS) {

SQLiteDatabase db = helper.getReadableDatabase();

long rowId = db.insert("info",null,values);

if (rowId>0) {

Uri insertedUri = ContentUris.withAppendedId(uri,rowId);

getContext().getContentResolver().notifyChange(insertedUri,null);

return insertedUri;

}

db.close();

return uri;

}else {

try {

throw new IllegalAccessException("插入失败,路径不正确!");

} catch (IllegalAccessException e) {

e.printStackTrace();

}

}

return null;

}

@Nullable

@Override

public Cursor query(@NonNull Uri uri, @Nullable String[] strings, @Nullable String s, @Nullable String[] strings1, @Nullable String s1) {

int code = mUriMatcher.match(uri);

if (code == SUCCESS) {

SQLiteDatabase db = helper.getReadableDatabase();

return db.query("info",strings,s,strings1,null,null,s1);

}else {

try {

throw new IllegalAccessException("查询失败,路径不正确!");

} catch (IllegalAccessException e) {

e.printStackTrace();

}

}

return null;

}

@Nullable

@Override

public String getType(@NonNull Uri uri) {

return null;

}

@Override

public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String s, @Nullable String[] strings) {

int code = mUriMatcher.match(uri);

if (code == SUCCESS) {

SQLiteDatabase db = helper.getReadableDatabase();

int count = db.update("info",contentValues,s,strings);

if (count>0) {

getContext().getContentResolver().notifyChange(uri,null);

}

db.close();

return count;

}else {

try {

throw new IllegalAccessException("更新失败,路径不正确!");

} catch (IllegalAccessException e) {

e.printStackTrace();

}

}

return 0;

}

@Override

public int delete(@NonNull Uri uri, @Nullable String s, @Nullable String[] strings) {

int code = mUriMatcher.match(uri);

if (code == SUCCESS) {

SQLiteDatabase db = helper.getReadableDatabase();

int count = db.delete("info",s,strings);

if (count>0) {

getContext().getContentResolver().notifyChange(uri,null);

}

db.close();

return count;

}else {

try {

throw new IllegalAccessException("删除失败,路径不正确!");

} catch (IllegalAccessException e) {

e.printStackTrace();

}

}

return code;

}

}

(七)SQLActivity

复制代码

package com.example.demo6;

import android.Manifest;

import android.app.Activity;

import android.content.ContentResolver;

import android.content.ContentValues;

import android.content.pm.PackageManager;

import android.database.Cursor;

import android.database.sqlite.SQLiteDatabase;

import android.net.Uri;

import android.os.Bundle;

import android.provider.ContactsContract;

import android.view.View;

import android.widget.EditText;

import android.widget.Toast;

import androidx.annotation.Nullable;

import androidx.core.app.ActivityCompat;

import androidx.core.content.ContextCompat;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

public class SQLActivity extends Activity {

private final Uri uri = Uri.parse("content://com.example.test05_contentprovider.PersonProvider/info");

private ContentValues values;

private ContentResolver resolver;

private EditText et_id;

private EditText et_name;

private EditText et_phone;

private EditText et_queryAll;

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.sqllayout);

et_id = (EditText) findViewById(R.id.editText1);

et_name = (EditText) findViewById(R.id.editText2);

et_phone = (EditText) findViewById(R.id.editText3);

et_queryAll = (EditText) findViewById(R.id.eT);

}

public String getAllPhoneNumbers(String lookUp_Key){

StringBuilder allPhoneNo = new StringBuilder();

String[] proj2 = {ContactsContract.CommonDataKinds.Phone.NUMBER};

String selection = ContactsContract.Data.LOOKUP_KEY+"=?";

String[] selectionArgs = {lookUp_Key};

ContentResolver resolver = getContentResolver();

Cursor cursor = resolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,proj2,selection,selectionArgs,null);

while(cursor.moveToNext()){

allPhoneNo.append(cursor.getString(0)).append(" ");

}

return allPhoneNo.toString();

}

public void btnCreate(View view) {

PersonDBOpenHelper helper = new PersonDBOpenHelper(this);

SQLiteDatabase db = helper.getWritableDatabase();

resolver = getContentResolver();

if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)!= PackageManager.PERMISSION_GRANTED)

{

ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_CONTACTS},1);

Toast.makeText(this,"未允许读取通讯录权限!",Toast.LENGTH_SHORT).show();

}

if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)== PackageManager.PERMISSION_GRANTED)

{

Cursor cursor = resolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,

null,null,null,null);

String name = ContactsContract.Contacts.DISPLAY_NAME;

String key = ContactsContract.Contacts.LOOKUP_KEY;

int displayNameIndex = cursor.getColumnIndex(name);

int KeyIndex = cursor.getColumnIndex(key);

for (cursor.moveToFirst();!cursor.isAfterLast();cursor.moveToNext()) {

String displayName = cursor.getString(displayNameIndex);

String Key = cursor.getString(KeyIndex);

String displayPhone = getAllPhoneNumbers(Key);

values = new ContentValues();

values.put("name",displayName);

values.put("phone",displayPhone);

db.insert("info",null,values);

}

cursor.close();

db.close();

btnQueryAll(view);

Toast.makeText(this,"插入成功!",Toast.LENGTH_SHORT).show();

}

}

public void btnAdd(View view) {

resolver = getContentResolver();

values = new ContentValues();

if (et_name.length() != 0 && et_phone.length() != 0){

values.put("name",et_name.getText().toString());

values.put("phone",et_phone.getText().toString());

Uri newUri = resolver.insert(uri,values);

Toast.makeText(this,"增加成功",Toast.LENGTH_SHORT).show();

btnQueryAll(view);

} else {

et_name.setHint("请在此输入需增加的姓名");

et_phone.setHint("请在此输入需增加的号码");

}

}

public void btnQuery(View view) {

resolver = getContentResolver();

if (et_name.length() != 0){

Cursor cursor = resolver.query(uri,new String[]{"_id","name","phone"},"name=?",new String[]{et_name.getText().toString()},null);

if (cursor.getCount() != 0){

cursor.moveToFirst();

et_id.setText(cursor.getString(0));

et_name.setText(cursor.getString(1));

et_phone.setText(cursor.getString(2));

cursor.close();

}

else {

Toast.makeText(this,"未查询到结果!",Toast.LENGTH_SHORT).show();

}

}

else {

et_name.setHint("请在此输入需查询的姓名");

et_phone.setHint("号码");

}

}

public void btnQueryAll(View view) {

resolver = getContentResolver();

List> data = new ArrayList>();

Cursor cursor = resolver.query(uri,new String[]{"_id","name","phone"},null,null,null);

while (cursor.moveToNext()){

Map map = new HashMap();

map.put("_id",cursor.getString(0));

map.put("name",cursor.getString(1));

map.put("phone",cursor.getString(2));

data.add(map);

}

cursor.close();

et_queryAll.setText(new String(data.toString()));

}

public void btnUpdate(View view) {

resolver = getContentResolver();

values = new ContentValues();

if (et_name.length() != 0 && et_phone.length() != 0){

values.put("phone",et_phone.getText().toString());

int updateCount = resolver.update(uri,values,"name=?",new String[]{et_name.getText().toString()});

Toast.makeText(this,"成功更新了" + updateCount + "条记录",Toast.LENGTH_SHORT).show();

btnQueryAll(view);

} else {

et_name.setHint("请在此输入需修改的姓名");

et_phone.setHint("请在此输入修改后的号码");

}

}

public void btnDelete(View view) {

resolver = getContentResolver();

if (et_name.length() != 0){

int deleteCount = resolver.delete(uri,"name=?",new String[]{et_name.getText().toString()});

Toast.makeText(this,"成功删除了" + deleteCount + "条记录",Toast.LENGTH_SHORT).show();

btnQueryAll(view);

} else {

et_name.setHint("请在此输入需删除的姓名");

et_phone.setHint("号码");

}

}

}

(八)activity_main.xml

复制代码

xmlns:app="http://schemas.android.com/apk/res-auto"

xmlns:tools="http://schemas.android.com/tools"

android:orientation="vertical"

android:layout_width="match_parent"

android:layout_height="match_parent"

tools:context=".MainActivity">

android:id="@+id/toOne"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@string/toOne"

android:onClick="toOne" />

android:id="@+id/toTwo"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@string/toTwo"

android:onClick="toTwo" />

(九)contentlayout.xml

复制代码

xmlns:app="http://schemas.android.com/apk/res-auto"

xmlns:tools="http://schemas.android.com/tools"

android:orientation="vertical"

android:layout_width="match_parent"

android:layout_height="match_parent"

tools:context=".ContentActivity">

android:id="@+id/hint"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@string/hint"

android:textSize="30sp" />

android:id="@+id/callName"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:textSize="20sp" />

(十)sqllayout.xml

复制代码

xmlns:app="http://schemas.android.com/apk/res-auto"

xmlns:tools="http://schemas.android.com/tools"

android:orientation="vertical"

android:layout_width="match_parent"

android:layout_height="match_parent"

tools:context=".SQLActivity">

android:id="@+id/editText1"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_marginLeft="10dp"

android:layout_marginRight="10dp"

android:hint="@string/id" />

android:id="@+id/editText2"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_marginLeft="10dp"

android:layout_marginRight="10dp"

android:hint="@string/name" />

android:id="@+id/editText3"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_marginLeft="10dp"

android:layout_marginRight="10dp"

android:hint="@string/phone" />

android:id="@+id/add"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@string/add"

android:onClick="btnAdd" />

android:id="@+id/delete"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@string/delete"

android:onClick="btnDelete" />

android:id="@+id/update"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@string/update"

android:onClick="btnUpdate" />

android:id="@+id/query"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@string/query"

android:onClick="btnQuery" />

android:id="@+id/addContent"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@string/addContent"

android:onClick="btnCreate" />

android:id="@+id/queryAll"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@string/queryAll"

android:onClick="btnQueryAll" />

android:id="@+id/eT"

android:layout_width="match_parent"

android:layout_height="0dp"

android:layout_marginLeft="10dp"

android:layout_marginRight="10dp"

android:layout_marginTop="15dp"

android:layout_weight="1"

android:gravity="start|top"

android:inputType="textMultiLine" />

(十一)strings.xml

复制代码

test05_contentprovider

id

姓名

号码

增加

删除

修改

查询

插入通讯录数据

查看所有数据

访问通讯录

数据库

读取到的联系人姓名 号码:

(十二)AndroidManifest.xml

复制代码

package="com.example.demo6">

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.Demo6">

android:name="com.example.demo6.MainActivity"

android:exported="true">

android:authorities="com.example.test05_contentprovider.PersonProvider"

android:name="com.example.demo6.PersonProvider"

android:exported="false" />

三.运行部分

(一)打开Device Manager

(二)选择上次创建的虚拟机

(三)运行

(四)运行结果

四.ContentProvider

前言

ContentProvider是Android四大组件之一,另外三个是Activity、Service和Broadcast。它可以被其他应用程序调用,从而实现数据的共享和交互。

(一)ContentProvider基础介绍

1.1 简介

ContentProvider是Android系统中的一个组件,用于在不同的应用程序之间共享数据。它提供了一种统一的接口,使得应用程序可以访问和修改其他应用程序中的数据,同时还可以对数据进行安全性和权限控制。

1.2 作用

实现进程间的数据交互 & 共享,即跨进程通信。

ContentProvider通常用于提供数据访问的接口,例如访问联系人信息、媒体文件、日历事件等。它可以将数据存储在SQLite数据库中,也可以通过其他方式进行数据存储。

1.ContentProvider=中间者角色(搬运工) 真正存储和操作数据的数据源还是原来存储数据的方式(数据库、文件、xml或网络)

2.数据源可以是:数据库(如Sqlite)、文件、XML、网络等等

1.3 实现原理

ContentProvider是通过Binder机制来实现跨进程通信的,它通过Binder对象来与其他应用程序或组件进行通信。当其他应用程序或组件通过ContentResolver请求数据时,ContentResolver会将请求转发给ContentProvider,而ContentProvider会通过Binder机制将数据返回给请求方。

Binder是什么呢? 浅浅的先了解一下

Binder是Android系统中用于实现跨进程通信的机制,它提供了一种轻量级的IPC(进程间通信)方式,可以实现进程间数据的传输和通信。ContentProvider利用Binder机制来实现数据共享和访问,保证了数据的安全性和权限控制。

(二)具体使用

2.1 统一资源标识符(URI)

ContentProvider使用 URI(统一资源标识符)来标识数据,每个数据都有一个唯一的URI来访问。当其他应用程序通过ContentResolver发起数据请求时,ContentProvider会根据请求的URI来匹配相应的数据,并返回给请求方。

定义:Uniform Resource Identifier,即统一资源标识符

作用:唯一标识 ContentProvider 其中的数据

外界进程通过 URI 找到对应的ContentProvider 其中的数据,再进行数据操作

URI分类:

URI分为 系统预置 & 自定义,分别对应系统内置的数据(如通讯录、日程表等等)和自定义数据库

系统预置URI可以在源码中找到,比如:

管理联系人的Uri:

ContactsContract.Contacts.CONTENT_URI

管理联系人的电话的Uri:

ContactsContract.CommonDataKinds.Phone.CONTENT_URI

管理联系人的Email的Uri:

ContactsContract.CommonDataKinds.Email.CONTENT_URI

发送箱中的短信URI:

Content://sms/outbox

收信箱中的短信URI:

Content://sms/sent

草稿中的短信URI:

Content://sms/draft

自定义URI:

例如:

URl= content:// com.henry.provider/User/1

content: 主题名

com.henry.provider:授权信息

User:表名

1:记录

主题(Schema):ContentProvider的URI前缀(Android 规定)

授权信息(Authority):ContentProvider的唯一标识符·

表名(Path):ContentProvider指向数据库中的某个表名·

记录(ID):表中的某个记录(若无指定,则返回全部记录

具体使用

设置URI

Uri uri = Uri.parse("content://com.henry.provider/User/1")

上述URI指向的资源是:名为 `com.henry.provider`的`ContentProvider` 中表名 为`User` 中的 `id`为1的数据

特别注意:URI模式存在匹配通配符* & #

*:匹配任意长度的任何有效字符的字符串

以下的URI 表示 匹配provider的任何内容

content://com.example.app.provider/ *

#:匹配任意长度的数字字符的字符串

以下的URI 表示 匹配provider中的table表的所有行

content://com.example.app.provider/table/#

2.2 MIME数据类型

ContentProvider中的MIME类型用于标识数据的类型和格式,帮助客户端应用程序正确解析和处理数据。开发者在使用ContentProvider时需要注意正确指定数据的MIME类型,以确保数据能够被正确处理。

作用:指定某个扩展名的文件用某种应用程序来打开

如指定.html文件采用text应用程序打开、指定.pdf文件采用flash应用程序打开

2.2.1 MIME类型组成

每种MIME类型 由2部分组成 = 类型 + 子类型

MIME类型是 一个 包含2部分的字符串

text / html

// 类型 = text、子类型 = html

text/css

text/xml

application/pdf

2.2.2 常见的MIME类型

在Android开发中,常见的MIME类型包括但不限于以下几种:

text/plain:纯文本数据

text/html:HTML格式数据

image/jpeg:JPEG格式图像数据

image/png:PNG格式图像数据

audio/mpeg:MP3格式音频数据

video/mp4:MP4格式视频数据

application/json:JSON格式数据

application/xml:XML格式数据

2.2.3 ContentProvider根据 URI 返回MIME类型

ContentProvider.geType(uri) ;

2.2.4 类型分类

两种常见的MIME类型形式是单条记录和多条记录(集合)

单条记录形式(vnd.android.cursor.item/自定义):

用于表示返回的数据是单个记录(一行数据)。

MIME类型的格式为"vnd.android.cursor.item/自定义",其中"自定义"部分是开发者自定义的标识符,通常用于指示数据表的类型。

示例:vnd.android.cursor.item/vnd.example.contacts,表示返回的数据是单个联系人记录。

多条记录(集合)形式(vnd.android.cursor.dir/自定义):

用于表示返回的数据是多个记录(多行数据,集合)。

MIME类型的格式为"vnd.android.cursor.dir/自定义",其中"自定义"部分是开发者自定义的标识符,通常用于指示数据表的类型。

示例:vnd.android.cursor.dir/vnd.example.contacts,表示返回的数据是多个联系人记录的集合。

2.3 ContentProvider三剑客

ContentProvider内容提供者

对外提供数据,其他应用可以通过ContentProvider对你应用中的数据进行添删改查

ContentResolver内容解析者

按一定规则访问内容提供者的数据

ContentObserver内容监听器

监听指定Uri引起的变化,当ContentObserver所观察的Uri发生变化时,便会触发

2.4 辅助工具类

Android 提供了3个用于辅助ContentProvide的工具类:

ContentUris

UriMatcher

ContentObserver

(三)总结

数据共享:ContentProvider提供了一种标准的接口,允许不同应用程序之间共享数据。通过ContentProvider,应用程序可以将自己的数据暴露给其他应用程序,实现数据的共享和交互。

访问控制:ContentProvider可以对数据进行访问控制,通过URI的权限控制和ContentProvider的权限设置,可以限制哪些应用程序可以访问数据,从而保护数据的安全性。

数据封装:ContentProvider可以将数据封装起来,隐藏数据的具体存储方式和结构,只提供统一的接口供其他应用程序访问。这样可以提高数据的安全性和保护数据的完整性。

数据变化通知:ContentProvider支持数据变化通知机制,可以通过ContentResolver注册ContentObserver监听数据的变化,当数据发生变化时,会及时通知监听者,实现数据的实时更新和同步。

访问简单和高效:

对比于其他对外共享数据的方式,数据访问方式会因数据存储的方式而不同:

采用 文件方式 对外共享数据,需要进行文件操作读写数据;

采用 Sharedpreferences 共享数据,需要使用sharedpreferences API读写数据

这使得访问数据变得复杂且难度大。

而采用ContentProvider方式,其 解耦了 底层数据的存储方式,使得无论底层数据存储采用何种方式,外界对数据的访问方式都是统一的,这使得访问简单 & 高效

如一开始数据存储方式 采用 SQLite 数据库,后来把数据库换成 MongoDB,也不会对上层数据ContentProvider使用代码产生影响