您的位置:

Android ContentProvider:提供数据共享和访问的方式

在Android平台上,ContentProvider是一种非常有用的组件,用于共享数据和简化数据访问的过程。ContentProvider能够帮助应用程序之间共享数据,同时提供了一种标准化的接口来访问数据。

一、ContentProvider的基本概念

ContentProvider是Android中的四大组件之一,其它三种组件是Activity、Service和BroadcastReceiver。ContentProvider的主要作用是提供数据给其他应用程序或其他部分的应用程序。ContentProvider是一个标准的接口,它用于访问数据。它隐藏了底层的数据访问方式,提供了一组标准的方法来进行数据访问。通过这些方法,应用程序可以添加、查询、更新和删除数据。

ContentProvider通过URI来标识和访问数据。URI包含三部分:schema、authority和path。例如,下面的URI表示一个ContentProvider,可以通过该ContentProvider来访问联系人数据。

content://com.android.contacts/contacts

URI的三部分:

  • schema:URI的协议部分,表明这是一个ContentProvider的URI。
  • authority:ContentProvider的唯一标识符。
  • path:ContentProvider中数据的路径。

二、创建自定义ContentProvider

下面是一个简单的ContentProvider的创建过程,以提供联系人数据为例。

1.定义Provider的metadata

在AndroidManifest.xml文件中定义Provider的metadata:

<provider
  android:name=".ContactsProvider"
  android:authorities="com.example.provider.contacts"
  android:exported="true" />

android:name:Provider的类名。

android:authorities:Provider的唯一标识符。

android:exported:是否允许其它应用程序访问Provider。

2.定义Provider的接口

创建一个类实现ContentProvider的接口:

public class ContactsProvider extends ContentProvider {
    public static final String AUTHORITY = "com.example.provider.contacts";
    private static final String DATABASE_NAME = "contacts.db";
    private static final int DATABASE_VERSION = 1;
    private static final String TABLE_NAME = "contacts";
    
    private SQLiteDatabase database;

    // onCreate方法:初始化数据库和表
    public boolean onCreate() {
        DatabaseHelper databaseHelper = new DatabaseHelper(getContext());
        database = databaseHelper.getWritableDatabase();
        return (database == null) ? false : true;
    }

    // getType方法:返回MIME类型
    public String getType(Uri uri) {
        return null;
    }

    // insert方法:插入一行数据
    public Uri insert(Uri uri, ContentValues values) {
        database.insert(TABLE_NAME, null, values);
        getContext().getContentResolver().notifyChange(uri, null);
        return uri;
    }

    // query方法:查询数据
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        // 根据查询参数获取需要查询的数据
        Cursor cursor = database.query(TABLE_NAME,
                new String[] { "id", "name", "phone" }, selection, selectionArgs, null, null, sortOrder);
        cursor.setNotificationUri(getContext().getContentResolver(), uri);
        return cursor;
    }

    // update方法:更新数据
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        int count = database.update(TABLE_NAME, values, selection, selectionArgs);
        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }

    // delete方法:删除数据
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        int count = database.delete(TABLE_NAME, selection, selectionArgs);
        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }

    // DatabaseHelper类:用于创建和更新数据库
    private static class DatabaseHelper extends SQLiteOpenHelper {
        public DatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

        // onCreate方法:创建表
        public void onCreate(SQLiteDatabase database) {
            database.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME +
                    "(id INTEGER PRIMARY KEY autoincrement, name TEXT, phone TEXT);");
        }

        // onUpgrade方法
        public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) {
            database.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
            onCreate(database);
        }
    }
}

在上面的代码中,需要注意一下方法:

  • onCreate:初始化ContentProvider的实例。
  • getType:返回MIME类型。
  • insert:插入一行数据。
  • query:查询数据。
  • update:更新数据。
  • delete:删除数据。

3.使用自定义Provider

使用ContentProvider的步骤如下:

// 定义需要查询的数据
String[] projection = new String[] { "id", "name", "phone" };
String selection = "id = ?";
String[] selectionArgs = new String[] { "1" };
String sortOrder = "name desc";

// ContentResolver:用于访问ContentProvider
ContentResolver contentResolver = getContentResolver();

// 获取ContentProvider的数据,使用Cursor保存查询结果
Uri uri = Uri.parse("content://com.example.provider.contacts/contacts");
Cursor cursor = contentResolver.query(uri, projection, selection, selectionArgs, sortOrder);

// 遍历查询结果
while (cursor.moveToNext()) {
    int id = cursor.getInt(cursor.getColumnIndex("id"));
    String name = cursor.getString(cursor.getColumnIndex("name"));
    String phone = cursor.getString(cursor.getColumnIndex("phone"));
    Log.i(TAG, String.format("id=%s, name=%s, phone=%s", id, name, phone));
}

// 关闭Cursor
cursor.close();

在上面的代码中,需要注意一下几点:

  • URI:ContentProvider的标识符。
  • ContentResolver:用于访问ContentProvider。
  • Cursor:用于保存查询结果。

三、ContentProvider的权限控制

ContentProvider能够控制访问权限,以允许或拒绝访问者访问数据。通过使用AndroidManifest.xml中的标签,可以控制ContentProvider的访问权限。

<provider
  android:name=".ContactsProvider"
  android:authorities="com.example.provider.contacts"
  android:exported="false"
  android:readPermission="com.example.provider.permission.READ_CONTACTS"
  android:writePermission="com.example.provider.permission.WRITE_CONTACTS" />

android:readPermissionandroid:writePermission:用于控制读写权限。

当ContentProvider中有多个表或多种数据类型时,可以将URI分为不同的路径。例如下面的代码是一个内容提供者,可以访问联系人和日历表:

<provider
  android:name=".ContactsProvider"
  android:authorities="com.example.provider"
  android:exported="false">
  <!-- 联系人表 -->
  <path-permission
    android:pathPrefix="/contacts"
    android:readPermission="com.example.provider.permission.READ_CONTACTS"
    android:writePermission="com.example.provider.permission.WRITE_CONTACTS" />
  <!-- 日历表 -->
  <path-permission
    android:pathPrefix="/calendar"
    android:readPermission="com.example.provider.permission.READ_CALENDAR"
    android:writePermission="com.example.provider.permission.WRITE_CALENDAR" />
</provider>

使用ContentProvider需要注意以下几点:

  • ContentProvider提供了一种标准的接口来访问数据。
  • ContentProvider可以通过URI来标识和访问数据。
  • ContentProvider可以控制访问权限,以允许或拒绝访问者访问数据。

完整的代码示例:

// 定义Provider的metadata
<provider
  android:name=".ContactsProvider"
  android:authorities="com.example.provider.contacts"
  android:exported="true" />

// 创建一个类实现ContentProvider的接口
public class ContactsProvider extends ContentProvider {
    public static final String AUTHORITY = "com.example.provider.contacts";
    private static final String DATABASE_NAME = "contacts.db";
    private static final int DATABASE_VERSION = 1;
    private static final String TABLE_NAME = "contacts";

    private SQLiteDatabase database;

    // onCreate方法:初始化数据库和表
    public boolean onCreate() {
        DatabaseHelper databaseHelper = new DatabaseHelper(getContext());
        database = databaseHelper.getWritableDatabase();
        return (database == null) ? false : true;
    }

    // getType方法:返回MIME类型
    public String getType(Uri uri) {
        return null;
    }

    // insert方法:插入一行数据
    public Uri insert(Uri uri, ContentValues values) {
        database.insert(TABLE_NAME, null, values);
        getContext().getContentResolver().notifyChange(uri, null);
        return uri;
    }

    // query方法:查询数据
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        // 根据查询参数获取需要查询的数据
        Cursor cursor = database.query(TABLE_NAME,
                new String[] { "id", "name", "phone" }, selection, selectionArgs, null, null, sortOrder);
        cursor.setNotificationUri(getContext().getContentResolver(), uri);
        return cursor;
    }

    // update方法:更新数据
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        int count = database.update(TABLE_NAME, values, selection, selectionArgs);
        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }

    // delete方法:删除数据
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        int count = database.delete(TABLE_NAME, selection, selectionArgs);
        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }

    // DatabaseHelper类:用于创建和更新数据库
    private static class DatabaseHelper extends SQLiteOpenHelper {
        public DatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

        // onCreate方法:创建表
        public void onCreate(SQLiteDatabase database) {
            database.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME +
                    "(id INTEGER PRIMARY KEY autoincrement, name TEXT, phone TEXT);");
        }

        // onUpgrade方法
        public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) {
            database.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
            onCreate(database);
        }
    }
}

// 使用自定义Provider
// 定义需要查询的数据
String[] projection = new String[] { "id", "name", "phone" };
String selection = "id = ?";
String[] selectionArgs = new String[] { "1" };
String sortOrder = "name desc";

// ContentResolver:用于访问ContentProvider
ContentResolver contentResolver = getContentResolver();

// 获取ContentProvider的数据,使用Cursor保存查询结果
Uri uri = Uri.parse("content://com.example.provider.contacts/contacts");
Cursor cursor = contentResolver.query(uri, projection, selection, selectionArgs, sortOrder);

// 遍历查询结果
while (cursor.moveToNext()) {
    int id = cursor.getInt(cursor.getColumnIndex("id"));
    String name = cursor.getString(cursor.getColumnIndex("name"));
    String phone = cursor.getString(cursor.getColumnIndex("phone"));
    Log.i(TAG, String.format("id=%s, name=%s, phone=%s", id, name, phone));
}

// 关闭Cursor
cursor.close();
Android ContentProvider:提供数据共享

2023-05-14
Android四大组件-深入剖析Activity、Servi

2023-05-14
深入浅出Android Provider

2023-05-20
Android IPC通信方式及其实现

2023-05-14
解决Android应用程序未响应(ANR)问题的技巧

随着移动设备的普及,人们越来越多地依赖于各种类型的应用程序来完成日常工作和为娱乐提供服务。但是,有时这些应用程序可能会遇到未响应(ANR)问题,这会导致应用程序停止响应,甚至崩溃。本文将介绍几种技巧来

2023-12-08
Android四大组件: Activity、Service、

一、Activity Activity是Android应用程序的基本组件之一,它代表了应用收到用户交互时呈现的界面。Activity通常会与其他Activity交互,并且可以包含其他组件,例如Frag

2023-12-08
Android数据存储:安全性与可靠性的解决方案

2023-05-14
Android IPC通信方式以及使用场景

2023-05-14
Android IPC:如何实现进程间通信?

2023-05-14
Android API文档:Android应用程序接口简介

2023-05-14
Android内核跨进程共享内存的高效实现方式:ashmem

2023-05-18
Android中的Persistent,如何更好地管理应用的

一、什么是数据持久化 在Android中,数据持久化是将数据保存在应用程序中,使得在程序关闭后,数据也不会丢失,并能够在下一次启动应用程序时读取这些数据。 数据持久化的方式有很多种,比如说Shared

2023-12-08
Android应用程序的基本要素及其使用

Android系统是一种移动设备操作系统,这使得Android平台的扩展能够很快。另外,开发人员可以在Android平台上创建各种类型的应用程序,这些应用程序可以运行在各种类型的设备上。Android

2023-12-08
Android开发必须掌握的面试题

2023-05-14
Android Cursor:数据查询和管理工具

2023-05-14
mysql源码之两阶段提交,数据库两阶段提交

2022-11-21
Android共享内存实现进程间通信

一、什么是共享内存 共享内存是一种IPC(进程间通信)的方式,它可以在多个进程间共享一段地址空间,从而达到通信的目的。共享内存通信的优点是速度快,因为不需要复制数据,而是直接操作内存中的数据。共享内存

2023-12-08
Android ThreadLocal:如何实现线程内数据共

2023-05-14
Android四大组件:Activity、Service、B

一、Activity作用 Activity是Android应用程序界面的载体,负责显示和响应用户的操作,通常可以看作是一种界面、视图或者屏幕。在整个Android应用程序的生命周期内,Activity

2023-12-08
Android四大组件:Activity、Service、B

一、Activity作用 Activity是Android应用程序界面的载体,负责显示和响应用户的操作,通常可以看作是一种界面、视图或者屏幕。在整个Android应用程序的生命周期内,Activity

2023-12-08