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

目录

一.本章要学习的内容

二.代码部分

(一)创建项目

(二)项目结构

(三)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 辅助工具类)

(三)总结


一.本章要学习的内容

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

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

  3. 理解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使用代码产生影响

相关推荐
C++小厨神41 分钟前
Java语言的循环实现
开发语言·后端·golang
Quantum&Coder2 小时前
Ruby语言的数据库编程
开发语言·后端·golang
請叫我菜鳥2 小时前
PHP xml 常用函数整理
开发语言·php
ByteBlossom6662 小时前
Ruby语言的网络编程
开发语言·后端·golang
J不A秃V头A2 小时前
自定义SqlSessionFactory时mybatis-config.xml失效
java·开发语言
码商行者2 小时前
精通Python (10)
开发语言·python
珹洺3 小时前
踏上 C++ 编程之旅:开篇之作
开发语言·c++
Yeats_Liao3 小时前
Java List过滤 Stream API filter() 应用
java·开发语言·list
qingy_20464 小时前
【算法】图解二叉树的前中后序遍历
java·开发语言·算法
程思扬4 小时前
Android笔记: 实现点击事件透传到底部
android·前端·windows·经验分享·笔记·科技·ui