目录
[(一)打开Device Manager](#(一)打开Device Manager)
[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<Map<String,String>> data = new ArrayList<Map<String,String>>();
Cursor cursor = resolver.query(uri,new String[]{"_id","name","phone"},null,null,null);
while (cursor.moveToNext()){
Map<String,String> map = new HashMap<String,String>();
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
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
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">
<Button
android:id="@+id/toOne"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/toOne"
android:onClick="toOne" />
<Button
android:id="@+id/toTwo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/toTwo"
android:onClick="toTwo" />
</LinearLayout>
(九)contentlayout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
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">
<TextView
android:id="@+id/hint"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/hint"
android:textSize="30sp" />
<TextView
android:id="@+id/callName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp" />
</LinearLayout>
(十)sqllayout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
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">
<EditText
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" />
<EditText
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" />
<EditText
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" />
<Button
android:id="@+id/add"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/add"
android:onClick="btnAdd" />
<Button
android:id="@+id/delete"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/delete"
android:onClick="btnDelete" />
<Button
android:id="@+id/update"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/update"
android:onClick="btnUpdate" />
<Button
android:id="@+id/query"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/query"
android:onClick="btnQuery" />
<Button
android:id="@+id/addContent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/addContent"
android:onClick="btnCreate" />
<Button
android:id="@+id/queryAll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/queryAll"
android:onClick="btnQueryAll" />
<EditText
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" />
</LinearLayout>
(十一)strings.xml
<resources>
<string name="app_name">test05_contentprovider</string>
<string name="id">id</string>
<string name="name">姓名</string>
<string name="phone">号码</string>
<string name="add">增加</string>
<string name="delete">删除</string>
<string name="update">修改</string>
<string name="query">查询</string>
<string name="addContent">插入通讯录数据</string>
<string name="queryAll">查看所有数据</string>
<string name="toOne">访问通讯录</string>
<string name="toTwo">数据库</string>
<string name="hint">读取到的联系人姓名 号码:</string>
</resources>
(十二)AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.demo6">
<uses-permission android:name="android.permission.READ_CONTACTS" />
<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.Demo6">
<activity
android:name="com.example.demo6.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.example.demo6.ContentActivity" />
<activity android:name="com.example.demo6.SQLActivity" />
<provider
android:authorities="com.example.test05_contentprovider.PersonProvider"
android:name="com.example.demo6.PersonProvider"
android:exported="false" />
</application>
</manifest>
三.运行部分
(一)打开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使用代码产生影响