ContentProvider数据库共享 实例

原创 2016年06月02日 02:37:09

概述

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" />
```
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

android ContentProvider实现资源共享实例

ContentProvider为存储和读取数据提供了统一的接口,使用ContentProvider,应用程序可以实现数据共享,android内置的许多数据都是使用ContentProvider形式,供...

Android ContentProvider 应用程序间共享数据库

闲来无事用下 ContentProvider 这是程序间共享数据的推荐途径(共享数据库); 比如通讯录软件就用了系统的共享的数据库; 废话少说: 要共享自己的数据库就得把自己整个的表结构以静态类的形式...

ContentProvider用法实例

  • 2016-01-27 11:28
  • 4.65MB
  • 下载

ContentProvider实例

这篇文章记录使用ContentProvider的方法,提供了最简单安全的移植方法 首先在工程目录建立包名对应的database目录 放入如下三个文件: DBHelper.java: p...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)