ContentProvider数据库共享 实例

概述

ContentProvider定义

1. ContentProvider,Android四大组件之一。主要作用是,在不同应用程序 之间进行数据共享。

ContentProvider就像一个中介,其他应用通过这个中介,对指定应用中的数据进行操作。
2. Android系统自带的应用中,提供了一些主要数据的共享,如:联系人、媒体资源(音频、视频、图片等)、
日历数据等。我们也可以自定一个Content Provider(本文主要讲如何自定义Content Provider)。

ContentProvider原理简述

每一个Content Provider组件都是通过一个URI来访问的。
URI:统一资源定位符,标识每个Content Provider,根据指定URI,找到对应的ContentProvider,对相应数据进行操作。
URI格式:[content://][com.way.note][/items][/11]
[content://]: 协议名称,固定为 “content://”。是Content Provider组件的专用访问协议。
[com.way.note]: 是Content Provider组件的 android:authority 属性值。必须保证该值全局唯一性,一般用Content Provider组件的包名来命名。
[/items]: 是一个资源的相对路径。
[/11] : 是一个资源的ID。

实现步骤,实例解析

实例概要

Note应用,是一个记事本。FloatingNote是一个悬浮便签窗口,该悬浮应用通过Content Provider访问Note应用的数据。

实例详解

该实例由两部分组成。
第一:建立了数据库,提供了ContentProvider的“Note记事本”应用。
第二:利用ContentResolver,通过指定的URI,访问对应ContentProvider指定的数据。由“FloatingNote悬浮便签”应用来完成。

第一:Note记事本应用(建立了数据库,提供了ContentProvider)

  • 创建一个数据库,存储用户添加的记事本条目信息。 DBOpenHelper.java

    public class DBOpenHelper extends SQLiteOpenHelper
    SQLiteOpenHelper类, 用来创建数据库,版本的更新管理。是一个抽象类,所以,要使用它必须实现它的nCreate(SQLiteDatabase),onUpgrade(SQLiteDatabase, int, int)方法。
    还有一个方法选用: onOpen() :当每次打开数据库时被调用。 数据库创建完成。

private static final String DB_NAME = "Notes.db";// 数据库名称

public DBOpenHelper(Context context) {
    //在构造函数中创建数据库Notes.db
    super(context, DB_NAME, null, DB_VERSION);
}

@Override
public void onCreate(SQLiteDatabase db) {
    //创建数据表
    db.execSQL(" CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " ( " + ID
        + " integer primary key autoincrement , " + NOTE_CONTENT
        + " text , " + RINGTONE_URI + " text ," + RINGTONE_NAME
        + " text ," + ISVIBRATE + " int ," + RINGTONE_DATE + " text ,"
        + RINGTONE_TIME + " text ,"
        + NOTE_ALARM_ENABLE + " integer , " + NOTE_BG_COLOR
        + " integer , " + NOTE_IS_FOLDER + " int , "
        + NOTE_PARENT_FOLDER + " varchar, " + NOTE_TITLE + " text, "
        + NOTE_UPDATE_DATE + " long);");
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    db.execSQL(" DROP TABLE IF EXISTS " + TABLE_NAME);
    onCreate(db);
}

Note记事本UI:
Note记事本UI

Note记事本对应的数据库:
数据库
数据表

  • 创建一个Content Provider。 NoteProvider.java
    自定义NoteProvider extends ContentProvider,提供了数据操作的接口。对数据的操作主要是增删改查, 要重写ContentProvider提供的方法:

    • query:查询

      @Override
      public Cursor query(Uri uri, String[] projection, String selection,
              String[] selectionArgs, String sortOrder) {
          SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
      
          // Generate the body of the query
          Log.d(TAG, "query() uri = " + uri);
          int match = sURLMatcher.match(uri);
          switch (match) {
          case EVENTS:
              qb.setTables("items");
              break;
          case EVENTS_ID:
              qb.setTables("items");
              qb.appendWhere("_id=");
              qb.appendWhere(uri.getPathSegments().get(1));
              break;
          default:
              throw new IllegalArgumentException("Unknown URL " + uri);
          }
      
          return qb.query(db, projection, selection, selectionArgs, null, null,
                  sortOrder);
      }
    • insert:添加

      @Override
      public Uri insert(Uri uri, ContentValues values) {
          Uri newUrl = null;
          SQLiteDatabase db = helper.getWritableDatabase();
          switch (sURLMatcher.match(uri)) {
          case EVENTS:
              long rowId = db.insert("items", DBOpenHelper.NOTE_CONTENT, values);
              if (rowId < 0) {
                  throw new SQLException("Failed to insert row");
              }
      
              newUrl = ContentUris.withAppendedId(
                      Uri.parse("content://com.way.note/items"), rowId);
      
              NoteDataManagerImpl noteDataManger = (NoteDataManagerImpl) NoteDataManagerImpl
                      .getNoteDataManger(getContext());
              noteDataManger.updateCacheFromDB();
      
              break;
          }
          return newUrl;
      }
    • update:更新

      @Override
      public int update(Uri uri, ContentValues values, String selection,
              String[] selectionArgs) {
          int count;
          long rowId = 0;
          int match = sURLMatcher.match(uri);
          SQLiteDatabase db = helper.getWritableDatabase();
          switch (match) {
          case EVENTS_ID: {
              String segment = uri.getPathSegments().get(1);
              rowId = Long.parseLong(segment);
              count = db.update("items", values, "_id=" + rowId, null);
              break;
          }
          default: {
              throw new UnsupportedOperationException("Cannot update URL: " + uri);
          }
          }
          return count;
      }
    • delete:删除

      @Override
      public int delete(Uri uri, String selection, String[] selectionArgs) {
          SQLiteDatabase db = helper.getWritableDatabase();
          int count;
          long rowId = 0;
          switch (sURLMatcher.match(uri)) {
          case EVENTS:
              count = db.delete("items", selection, selectionArgs);
              break;
          case EVENTS_ID:
              String segment = uri.getPathSegments().get(1);
              rowId = Long.parseLong(segment);
              if (TextUtils.isEmpty(selection)) {
                  selection = "_id=" + segment;
              } else {
                  selection = "_id=" + segment + " AND (" + selection + ")";
              }
              count = db.delete("items", selection, selectionArgs);
              break;
          default:
              throw new IllegalArgumentException("Cannot delete from URL: " + uri);
          }
      
          return count;
      }
    • getType:得到数据类型
      Android的MIME类型有两种形式:多条记录 单条记录
      多条记录:vnd.android.cursor.dir/items
      单条记录:vnd.android.cursor.item/items
      在使用Intent时,用到MIME。
      intent.setType(“vnd.android.cursor.item/items”);

    @Override
    public String getType(Uri uri) {
        int match = sURLMatcher.match(uri);
        switch (match) {
        case EVENTS:
            return "vnd.android.cursor.dir/items";
        case EVENTS_ID:
            return "vnd.android.cursor.item/items";
        default:
            throw new IllegalArgumentException("Unknown URL");
        }
    }

    在这几个函数中,可以看到都有Uri参数的传入。这几个函数中,要执行具体的操作,需要对URI进行匹配。那么URI的匹配是怎么做呢,利用UriMatcher匹配。UriMatcher预先要addURI (String authority, String path, int code)

    1. authority:ContentProvider的authority参数。
    2. path:URI格式中authority后面部分。
    3. code:匹配成功后,返回的值。
      private static final UriMatcher sURLMatcher = new UriMatcher(
              UriMatcher.NO_MATCH); //如果匹配不成功,返回UriMatcher.NO_MATCH
      
      static {
          sURLMatcher.addURI("com.way.note", "items", EVENTS);
          sURLMatcher.addURI("com.way.note", "items/#", EVENTS_ID);
          //符号#表示一个任意的数字
      }
  • 在AndroidManifest.xml中注册该Content Provider
    数据库和ContentProvider都建立好了。这时候,要对NoteProvider进行注册:

    <provider
    android:name=".backup.DBOperations"
    android:authorities="com.way.note"
    android:exported="true" />

    1. android:exported: 这个属性用于指示该服务是否能够被其他应用程序组件调用或跟它交互。如果设置为true,则能够被调用或交互,否则不能。
    2. android:authorities:该值对应URI格式中authority值。

第二:FloatingNote悬浮便签 通过ContentProvider 访问Note记事本应用数据

  • 如何访问ContentProvider提供的数据。
    外界的程序通过ContentResolver接口可以访问ContentProvider提供的数据,通过getContentResolver()可以得到当前应用的ContentResolver实例。
    public static final Uri CONTENT_URI = Uri.parse(“content://com.way.note/items”);

    查询: context.getContentResolver().query(CONTENT_URI, null, “(isfilefolder != 1)”, null, null);

    添加: context.getContentResolver().insert(CONTENT_URI, cv);

    删除: context.getContentResolver().delete(CONTENT_URI, where, null);

    修改: context.getContentResolver().update(CONTENT_URI, cv, s4, null)

  • 监听ContentProvider中数据的变化。

    1. 如果ContentProvider的访问者需要得到数据变化通知,必须使用ContentObserver对数据(数据采用uri描述)进行监听,当监听到数据变化通知时,系统就会调用ContentObserver的onChange()方法:

      context.getContentResolver().registerContentObserver(
                      NotesPopupUtils.CONTENT_URI, true, mObserver);
      private class NotesPopupContentObserver extends ContentObserver {
          public NotesPopupContentObserver() {
              super(handler);
          }
      
          @Override
          public boolean deliverSelfNotifications() {
              return true;
          }
      
          @Override
          public void onChange(boolean selfChange) {
              handler.sendEmptyMessageDelayed(MSG_UPDATE_GALLERY, 100);
          }
      }
    2. 如果ContentProvider的访问者需要知道ContentProvider中的数据发生变化,可以在ContentProvider发生数据变化时调用getContentResolver().notifyChange(uri, null)来通知注册在此URI上的访问者。

    FloatingNote悬浮便签UI:
    悬浮便签1
    悬浮便签2

第三:ContentProvider使用中权限问题

ContentProvider中,有一些数据是私有的,需要读写权限。这就需要我们在AndroidManifest.xml中添加读写权限。
比如Launcher3的数据库:
1. 申请permission

<permission
android:name="com.philips.launcher3.permission.WRITE_SETTINGS"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:protectionLevel="signatureOrSystem"
android:label="@string/permlab_write_settings"
android:description="@string/permdesc_write_settings"/>

2. 注册provider时,添加permission

<provider
android:name="com.philips.launcher3.LauncherProvider"
android:authorities="com.philips.launcher3.settings"
android:exported="true"
android:writePermission="com.philips.launcher3.permission.WRITE_SETTINGS"
android:readPermission="com.philips.launcher3.permission.READ_SETTINGS" />

3. 访问ContentProvider中数据的第三方应用,AndroidManifest.xml中添加权限。

```
<uses-permission android:name="com.philips.launcher3.permission.READ_SETTINGS" />
<uses-permission android:name="com.philips.launcher3.permission.WRITE_SETTINGS" />
```
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Android ContentProviderAndroid系统的一个组件,用于管理应用程序之间的共享。它提供了一种标准的接口,使得应用程序可以访问其他应用程序的据,同时也可以保护据的安全性。ContentProvider可以将据存储在文件系统、SQLite数据库或者网络上,然后通过URI来访问这些据。开发者可以通过继承ContentProvider类来创建自己的ContentProvider,然后在AndroidManifest.xml文件注册。在使用ContentProvider时,需要使用ContentResolver类来访问据。 ### 回答2: Android ContentProviderAndroid Framework的一个重要组件,用于在应用间共享据。它提供一种标准化的方式,让其它应用或组件访问原本受到封装的私有据。ContentProvider采用标准的CRUD(Create、Retrieve、Update、Delete)逻辑来管理据,且提供额外的查询功能,是实现据在应用间共享的理想选择。 ContentProvider可以用来实现以下几个功能: 1. 共享ContentProvider提供了一个标准的接口,让其它应用或组件来操作内容提供者的据。 2. 据访问保护:ContentProvider可以控制其它应用或组件只有在得到授权的情况下才能访问据。 3. 储存树形据:储存树形据是很常见的需求,不像SQLite那样的关系型数据库。 4. 据访问审计:作为应用的一个央存储库,ContentProvider可以记录其它应用或组件对它的操作记录。 下面以一个简单的例子来说明ContentProvider的使用过程: 1. 首先在AndroidManifest.xml文件定义ContentProvider,必须在所有Activity的前面定义; 2. 在代码继承ContentProvider实现CRUD和查询方法; 3. 在应用使用CursorLoader或ContentResolver访问ContentProvider据; 4. 客户端进程和服务端进程都需要读写ContentProvider,为了防止多线程据访问问题, ContentProvider通常会使用线程池来进行并发处理。 ContentProviderAndroid组件的一种,应用程序可以通过该组件来暴露自己的据给其它应用程序使用,同时也可以访问其它应用程序的ContentProvider,以获取到这些应用程序所提供的据。ContentProvider实例Android开发广泛运用。通过ContentProvider,我们可以更加方便地共享据,能够让我们的应用程序变得更加灵活。 ### 回答3: Android提供了Content Provider框架,以便不同的应用程序之间共享据。ContentProvider提供了一种安全访问据的方式,防止据被未经授权的访问。 实现Content Provider需要定义一个类,该类继承自ContentProvider类,并实现一些必要的方法,包括onCreate()、query()、insert()、update()和delete()。我们可以通过Content Resolver类来访问Content Provider,它是一个用于查询、插入、更新和删除据的类。 Content Provider的最大好处是在应用程序之间共享据。例如,一个应用程序可以提供联系人列表,并允许其他应用程序访问该列表。如果应用程序需要共享据,可以使用Content Provider。 在实现Content Provider时,需要确定好URI的结构,以便其他应用程序访问据。URI的结构可以根据应用程序的需求来定制。例如,我想创建一个共享书籍列表的Content Provider,URI可以定义为content://com.example.bookprovider/books。通过这个URI,其他应用程序可以访问该Provider的books表,并操作据。 要使用Content Provider,需要先在AndroidManifest.xml文件注册该Provider。这需要声明一个<provider>标记,其包含Provider的名称、权限和URI。 Content ProviderAndroid被广泛使用,它可以让应用程序之间共享据,并提高应用程序的安全性。但是,使用Content Provider也需要注意据安全性,防止据被未经授权的访问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值