内容提供者 ContentProvider

概念

内容提供者管理对中央数据存储区(结构化数据集)的访问。通常是其他应用通过内容提供者对应用的数据访问。通常情况下如果不需要与其他应用共享数据,就不需要使用内容提供者。

内容提供者通过一个或多个表(对sqlite的封装)的形式将数据呈现给外部应用。对数据的增删改查与sqlite数据库基本一致。

URl

用于标识数据的URl,包括内容提供者的名字(唯一标识、授权)的一个指向表的名称(路径)。外部应用通过URL来访问指定的数据。如:

content://user_dictionary/words

其中,user_dictionary 字符串是提供程序的授权,words 字符串是表的路径。

读写访问权限

内容提供程序提供结构化存储机制,可以将内容限制为仅供自己的应用访问,也可以将内容导出以供其他应用访问。如果您不打算向其他应用授予访问您的 ContentProvider 的权限,请在应用清单中将其标记为 android:exported=false;要允许其他应用访问存储的数据,请将 android:exported 属性设置为 “true”。

      <provider
        android:name=".provider.FengfanckyProvider"
        android:authorities="cn.math.cky"
        android:exported="true" />

在创建要导出以供其他应用使用的 ContentProvider 时,您可以在清单中指定允许读取和写入的单一权限,也可以针对读取和写入操作分别指定权限。如下:
1.在application的同级标签中申请一个自定义权限

<permission  
    android:name="cn.math.cky.provider.read"  
    android:label="provider pomission"  
    android:protectionLevel="normal" /> 

<permission  
    android:name="cn.math.cky.provider.write"  
    android:label="provider pomission"  
    android:protectionLevel="normal" /> 

<permission  
    android:name="cn.math.cky.provider.permission"  
    android:label="provider pomission"  
    android:protectionLevel="normal" /> 

2.将上述申请的权限赋值给provider的readPermission或writePermission

<provider
    android:name=".provider.FengfanckyProvider"
    android:authorities="cn.math.cky"
    android:readPermission="cn.math.cky.provider.read" 
    android:writePermission="cn.math.cky.provider.write"/>

<provider
    android:name=".provider.FengfanckyProvider"
    android:authorities="cn.math.cky"
    android:permission="cn.math.cky.provider.permission"/>

3.在第三方应用中根据需求使用uses-permission来声明使用对应的权限

<uses-permission android:name="cn.math.cky.provider.read"/>  

<uses-permission android:name="cn.math.cky.provider.write"/>  

<uses-permission android:name="cn.math.cky.provider.permission"/>  

provider几个的属性:

  • exported:其他应用是否可以访问该ContentProvider。
  • readPermission: ContentProvider读取权限。
  • writePermission: ContentProvider写入权限。
  • permission: 一次性设置ContentProvider的读写权限,如果同时设置了readPermission、writePermission,优先级低于readPermission、writePermission。
  • grantUriPermissions:并使用用来启动组件的 Intent 对象中的 FLAG_GRANT_READ_URI_PERMISSION 和 FLAG_GRANT_WRITE_URI_PERMISSION 标记。

如下:

<provider
    android:name=".provider.FengfanckyProvider"
    android:authorities="cn.math.cky"
    android:readPermission="cn.math.cky.provider.read" 
    android:grantUriPermissions="true"/>

可以通过Intent将权限传递给第三方应用:

Intent intent = new Intent(this,ReadProvider.class);
intent.setClassName("xx.xxx.xxx","xx.xxx.xxx.MainActivity");
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);  //传递权限
startActivity(intent);

如果将provider的属性android:grantUriPermissions设置为false,则不允许通过接受传递的权限方式。

创建内容提供者

创建步骤

  • 设计数据存储原始结构。主要有两种:文件数据、结构化数据(SQLite数据库)。
  • 定义 ContentProvider 类及其所需方法的具体实现。
  • 定义提供程序的授权字符串、其内容 URI 以及列名称。
  • 其他。

1.创建数据存储(SQLite)
定义一个常量类,URI、表名、列名等

public class Contracts {

    protected static final String CONTENT_AUTHORITY = "cky.provider";
    public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY);

    public static final class HistoryEntry implements BaseColumns {

        protected static final String TABLE_NAME = "history";

        public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon().appendPath(TABLE_NAME).build();

        protected static Uri buildUri(long id) {
            return ContentUris.withAppendedId(CONTENT_URI, id);
        }

        public static final String COLUMN_ID="contentID";
        public static final String COLUMN_NAME="name";
        public static final String COLUMN_PICURL="picUrl";
        public static final String COLUMN_PACKAGENAME="packageName"; 
    }
}

创建SQLite数据库,继承至SQLiteOpenHelper。创建数据库,创建表,更新表

public class DBHelper extends SQLiteOpenHelper {
    private static final int DATABASE_VERSION =1;
    private static final String DATABASE_NAME = "cky_test.db";

    public DBHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }


    @Override
    public void onCreate(SQLiteDatabase db) {
        final String SQL_CREATE_HISTORY_TABLE = "CREATE TABLE "
                + Contracts.HistoryEntry.TABLE_NAME + "( "
                + Contracts.HistoryEntry.COLUMN_ID + " INTEGER PRIMARY KEY, "
                + Contracts.HistoryEntry.COLUMN_NAME + "  CHAR(50), "
                + Contracts.HistoryEntry.COLUMN_PICURL + " CHAR(50), "
                + Contracts.HistoryEntry.COLUMN_PACKAGENAME + " CHAR(50) ,"
                + Contracts.HistoryEntry.COLUMN_TYPE + " CHAR(50) ,"
                + Contracts.HistoryEntry.COLUMN_FILMPATH + " CHAR(50) ,"
                + Contracts.HistoryEntry.COLUMN_MOIVEPATH + " CHAR(50) ,"
                + Contracts.HistoryEntry.COLUMN_UPDATETIME + " INTEGER );";
        db.execSQL(SQL_CREATE_HISTORY_TABLE);

    }


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

2.创建ContentProvider以及所需方法实现

使用UriMatcher,匹配不同的uri来访问不同的表

private final static int HISTORY = 100;
private final static int COLLECT = 200;

static UriMatcher buildUriMatcher() {

   final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
   final String authority = Contracts.CONTENT_AUTHORITY;

   matcher.addURI(authority, Contracts.HistoryEntry.TABLE_NAME, HISTORY);
   matcher.addURI(authority, Contracts.CollectEntry.TABLE_NAME, COLLECT);

   return matcher;
}

继承ContentProvider,实现onCreate(),getType(),query(),insert(),delete(),update()方法。

public class UserInfoProvider extends ContentProvider {
    private DBHelper mOpenHelper;

    @Override
    public boolean onCreate() {
        mOpenHelper = new DBHelper(getContext());
        return true;
    }


    @Nullable
    @Override
    public String getType(Uri uri) {
        return null;
    }

    @Nullable
    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        final SQLiteDatabase db = mOpenHelper.getReadableDatabase();

        Cursor cursor = null;
        switch ( buildUriMatcher().match(uri)) {
            case HISTORY:
                cursor = db.query(Contracts.HistoryEntry.TABLE_NAME, projection, selection, selectionArgs, sortOrder, null, null);
                break;
            case COLLECT:
                cursor = db.query(Contracts.CollectEntry.TABLE_NAME, projection, selection, selectionArgs, sortOrder, null, null);
                break;
        }

        return cursor;
    }

    @Nullable
    @Override
    public Uri insert(Uri uri, ContentValues values) {
        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        Uri returnUri;
        long _id;
        switch ( buildUriMatcher().match(uri)) {
            case HISTORY:
                _id = db.insert(Contracts.HistoryEntry.TABLE_NAME, null, values);
                if ( _id > 0 )
                    returnUri = Contracts.HistoryEntry.buildUri(_id);
                else
                    throw new android.database.SQLException("Failed to insert row into " + uri);
                break;

            case COLLECT:
                _id = db.insert(Contracts.CollectEntry.TABLE_NAME, null, values);
                if ( _id > 0 )
                    returnUri = Contracts.CollectEntry.buildUri(_id);
                else
                    throw new android.database.SQLException("Failed to insert row into " + uri);
                break;

            default:
                throw new android.database.SQLException("Unknown uri: " + uri);
        }
        return returnUri;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
        int num=0;
        switch ( buildUriMatcher().match(uri)) {
            case HISTORY:
                num=db.delete(Contracts.HistoryEntry.TABLE_NAME,selection,selectionArgs);
                break;
            case COLLECT:
                num=db.delete(Contracts.CollectEntry.TABLE_NAME,selection,selectionArgs);
                break;
        }
        return num;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
        int num=0;
        switch ( buildUriMatcher().match(uri)) {
            case HISTORY:
                num=db.update(Contracts.HistoryEntry.TABLE_NAME,values,selection,null);
                break;
            case COLLECT:
                num=db.update(Contracts.CollectEntry.TABLE_NAME,values,selection,null);
                break;
        }
        return num;
    }
}
数据的增删改查

应用从具有 ContentResolver 客户端对象的内容提供程序访问数据。 此对象具有调用提供程序对象(ContentProvider 的某个具体子类的实例)中同名方法的方法。 ContentResolver 方法可提供持续存储的基本“CRUD”(创建、检索、更新和删除)功能。

1.数据查询query()

// Queries the user dictionary and returns results
mCursor = getContentResolver().query(
    UserDictionary.Words.CONTENT_URI,   // The content URI of the words table
    mProjection,                        // The columns to return for each row
    mSelectionClause                    // Selection criteria
    mSelectionArgs,                     // Selection criteria
    mSortOrder);                        // The sort order for the returned rows

Query() 与 SQL 查询对比:
Query

获取查询结果:

Cursor cursor=getContentResolver().query(Contracts.HistoryEntry.CONTENT_URI,null,null,null,null,null);

    if (cursor!=null){

        while (cursor.moveToNext()){

            String contentID=cursor.getString(cursor.getColumnIndex(Contracts.HistoryEntry.COLUMN_ID));

            String name=cursor.getString(cursor.getColumnIndex(Contracts.HistoryEntry.COLUMN_NAME));

            String pic_url=cursor.getString(cursor.getColumnIndex(Contracts.HistoryEntry.COLUMN_PICURL));

        }
    }

2.数据插入

ContentValues contentValues=new ContentValues();

contentValues.put(Contracts.HistoryEntry.COLUMN_ID,"12233332");
contentValues.put(Contracts.HistoryEntry.COLUMN_NAME,"hello");
contentValues.put(Contracts.HistoryEntry.COLUMN_PICURL,"http://xx.xxx.xx");

getContentResolver().insert(Contracts.HistoryEntry.CONTENT_URI,contentValues);

3.数据更新

 ContentValues contentValues=new ContentValues();

 contentValues.put(Contracts.HistoryEntry.COLUMN_NAME,"hi");

 getContentResolver().update(
        Contracts.HistoryEntry.CONTENT_URI,
        Contracts.HistoryEntry.COLUMN_ID+"=12233332",
        null);

4.数据删除
删除行与检索行数据类似:为要删除的行指定选择条件,客户端方法会返回已删除的行数。 以下代码段会删除应用 ID 与“用户”匹配的行。该方法会返回已删除的行数。

getContentResolver().delete(
    Contracts.HistoryEntry.CONTENT_URI,
    Contracts.HistoryEntry.COLUMN_ID+"=12233332",
    null);

官方文档
Demo

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值