一篇就够了系列之ContentProvider全解析

前言:

上一篇介绍广播接收者(BroadcastReceover),本篇继续,记叙下Android四大组件最后一个不常用,但是非常有用的ContentProvider。Google文档

本文主要从以下几个方面介绍:

  • 特点
  • 优缺点
  • 数据访问
  • 创建内容提供器
  • 工作机制

特点

  1. Android四大组件之一,需要进行注册,一般有name,authorities,export等属性
  2. 是一种定义数据共享的接口,并是不android数据存储的方式之一
  3. 跨进程数据访问
  4. android系统很多系统应用都是使用ContentProvider方式进行储存的(图片,通讯录,视频,音频等)
  5. 数据更新监听方便

优缺点

优点:

  1. 为数据访问提供统一的接口,解决了不同储存方式需要不同的API的访问所带来的繁琐
  2. 跨进程数据的访问,实现了不同App数据访问提供了很大的便利

缺点:

  1. 不能单独使用,必须需要和其他的储存方式结合使用

数据访问

下面示例如何获取通讯录信息:
Activity:

public class ContentProviderActivity extends AppCompatActivity {

    private ContentResolver mContentResolver;//
    StringBuilder builder=new StringBuilder("");
    TextView tv;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_content_provider);
        mContentResolver=getContentResolver();
        tv= (TextView) findViewById(R.id.tv_show_contract);
        findViewById(R.id.tv_press_contract).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            //动态申请权限
                if(ContextCompat.checkSelfPermission(ContentProviderActivity.this, android.Manifest.permission.READ_CONTACTS)!= PackageManager.PERMISSION_GRANTED){
                    ActivityCompat.requestPermissions(ContentProviderActivity.this,new String[]{Manifest.permission.READ_CONTACTS},1);
                }else{
                    readContacts();
                }
            }
        });
    }

    private void readContacts(){
        Cursor cursor=null;
        try {
            cursor=mContentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,null,null,null);
            if(cursor!=null){
                while(cursor.moveToNext()){
                    String displayName=cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
                    String number=cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                    builder.append(displayName);
                    builder.append(": ");
                    builder.append(number);
                    builder.append("   ");
                    Log.i("wy",displayName+"   "+number);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(cursor!=null){
                cursor.close();
            }
            tv.setText(builder);
        }
    }
}

以上:

  • 借助ContentResolver类访问内容提供器中共享的数据,其提供了一系列的增删改查(CRUD)操作,其中insert方法用于添加数据,update更新数据,delete删除数据,query用于查询数据。和SQLiteDatabase类似,只是参数上稍微有些区别,ContentResolver中接收的参数是不接收表名参数的,而是使用一个Uri参数代码(关于Uri内容欢迎参考一篇就够了系列之Activity全解析中关于Scheme的介绍)。
  • 由于联系人信息是危险权限,所以需要动态申请,同时manifest中也需要申明
  • 代码中的查询等方法可以看到是个常量,其实也源码的一个封装。

创建内容提供器

public class MyContentProvider extends ContentProvider {

    public static final int DIR1=0;
    public static final int ITEM1=1;
    public static final int DIR2=2;
    public static final int ITEM2=3;

    public static final String AUTHRITY="com.wenyi.interview.provider";
    private static UriMatcher uriMatcher;
    private MyDatabaseHelper dbhelper;

    static {
        uriMatcher=new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI(AUTHRITY,"book",DIR1);
        uriMatcher.addURI(AUTHRITY,"book/#",ITEM1);
        uriMatcher.addURI(AUTHRITY,"category",DIR2);
        uriMatcher.addURI(AUTHRITY,"category/#",ITEM2);
    }


    /**
     * 初始化内容提供器的时候调用,通常会在这里完成对数据库的创建和升级等操作
     * @return true表示初始化成功,false表示初始化失败
     * 只有当contentResolver尝试访问我们的程序中的数据是,内容提供器才会被初始化
     */
    @Override
    public boolean onCreate() {
        dbhelper=new MyDatabaseHelper(getContext(),"MyStore.db",null,2);
        return true;
    }

    /**
     * 查询数据
     * @param uri 确定查询哪张表
     * @param projection 确定查询哪些列
     * @param selection 约束查询哪些行
     * @param selectionArgs 约束查询哪些行
     * @param sortOrder 用于对结果进行排序,查询的结果存放在Cursor对象中返回
     * @return
     */
    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        SQLiteDatabase db=dbhelper.getReadableDatabase();
        Cursor cursor=null;
        switch (uriMatcher.match(uri)){
            case DIR1:
                cursor=db.query("Book",projection,selection,selectionArgs,null,null,sortOrder);
                break;
            case ITEM1:
                String bookid=uri.getPathSegments().get(1);
                cursor=db.query("Book",projection,"id=?",new String[]{bookid},null,null,sortOrder);
                break;
            case DIR2:
                cursor=db.query("Category",projection,selection,selectionArgs,null,null,sortOrder);
                break;
            case ITEM2:
                String categoryid=uri.getPathSegments().get(1);
                cursor=db.query("Category",projection,"id=?",new String[]{categoryid},null,null,sortOrder);
                break;
            default:
                break;
        }
        return cursor;
    }

    /**
     *
     * @param uri
     * @return 传入的内容URI来返回相应的MIME类型
     */
    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        switch (uriMatcher.match(uri)){
            case DIR1:
                return "vnd.android.cursor.dir/vnd.com.wenyi.interview.provider.book";
            case ITEM1:
                return "vnd.android.cursor.item/vnd.com.wenyi.interview.provider.book";
            case DIR2:
                return "vnd.android.cursor.dir/vnd.com.wenyi.interview.provider.category";
            case ITEM2:
                return "vnd.android.cursor.item/vnd.com.wenyi.interview.provider.category";
            default:
                break;
        }
        return null;
    }

    /**
     * 添加数据
     * @param uri 确定要添加到的表
     * @param values 待添加的数据
     * @return 添加完成后,返回一个用于表示这条心记录的URI
     */
    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        return null;
    }

    /**
     * 删除数据
     * @param uri 确定删除哪一张表中的数据
     * @param selection 约束删除哪些行
     * @param selectionArgs 约束删除哪些行
     * @return 被删除的行
     */
    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        return 0;
    }

    /**
     * 更新数据
     * @param uri 更新的表
     * @param values 新数据保存在其中
     * @param selection 约束更新的行
     * @param selectionArgs 约束更新的行
     * @return 受影响的行作为返回值
     */
    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
        return 0;
    }
}

代码有点长,现在来细细分析:

  1. 自定义MyContentProvider继承自ContentProvider,重写相应的方法,方法都有解释
  2. 四个常量分别表示访问Book表中的说有数据,访问Book表中的单条数据,访问Category表中的所有数据和访问Category表中的单条数据
  3. 在manifest中进行注册,<provider
    android:exported="true"
    android:enabled="true"
    android:authorities="com.wenyi.interview.provider"
    android:name=".FourComponet.contentProvider.MyContentProvider"/>
  4. 代码中,UriMatche类,可以用来配皮Uri类型数据,其中,“*”和“#”分别表示匹配任意长度的任意字符和任意长度的数字。
  5. 创建MyDatabaseHelper对象,继承自SQLiteOpenHelper,方便数据可操作,因为内容提供着只是接口标准,需要和数据存储方式结合使用
  6. 只在query中写了相应代码,其他方法也需要写类似代码
  7. getType方法中,返回值很奇特。实际上,这是MIME字符格式,MIME主要由3部分组成,在Android中,格式为: a: 必须以vnd开头 b: 如果内容Uri以路径结尾,则后面接 android.cursor.dir/。如果内容Uri以id结尾,则后面接android.cursor.item/ c: 在最后面接 vnd.authority.path
  8. 这样,我们的内容提供器就创建完成了,通过这种机制,必须知道URI,才能顺利的访问该数据库中的内容,比保证了可访问,又保证了安全性。

工作机制

暂不分析

欢迎阅读其他系列文章:

一篇就够了系列之Activity全解析

一篇就够了系列之Service全解析

一篇就够了系列之BroadcastReceiver全解析

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
package com.example.tigongzhe; import android.R.integer; import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.UriMatcher; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.database.sqlite.SQLiteOpenHelper; import android.net.Uri; import android.provider.SyncStateContract.Helpers; import android.text.Selection; import android.util.Log; public class provider extends ContentProvider { private MyOpenHelper myOpenHelper; private SQLiteDatabase sqLiteDatabase; private static final UriMatcher URI_MATCHER=new UriMatcher(UriMatcher.NO_MATCH); private final String TAG="provider"; private static final String authority="com.example.tigongzhe.provider"; static { URI_MATCHER.addURI(authority, "contacter", 1); URI_MATCHER.addURI(authority, "contacter/#", 2); } private static final String _id="id"; private static final String name="name"; private static final String num="num"; @Override public boolean onCreate() { // TODO Auto-generated method stub myOpenHelper=new MyOpenHelper(getContext(), DB_Name, null, version_1); return true; } @Override public String getType(Uri uri) { // TODO Auto-generated method stub int flag=URI_MATCHER.match(uri); switch (flag) { case 2: return "vnd.android.cursor.item/contacter"; case 1: return "vnd.android.dir.item/contacter"; default: throw new IllegalArgumentException("异常参数"); } } @Override public Uri insert(Uri uri, ContentValues values) { // TODO Auto-generated method stub sqLiteDatabase=myOpenHelper.getWritableDatabase(); int flag=URI_MATCHER.match(uri); switch (flag) { case 1: sqLiteDatabase.insert(Table_Name, name, values); break; case 2: long id=sqLiteDatabase.insert(Table_Name, name, values); ContentUris.withAppendedId(uri, id); default: break; } return uri; } @Override public Cursor query(Uri uri, String[] arg1, String arg2, String[] arg3, String arg4) { // TODO Auto-generated method stub Cursor cursor; sqLiteDatabase=myOpenHelper.getReadableDatabase(); int flag=URI_MATCHER.match(uri); switch (flag) { case 1: cursor=sqLiteDatabase.query(Table_Name, arg1, arg2, arg3, null, null,arg4); break; case 2: long id=ContentUris.parseId(uri); arg2=(arg2==null||"".equals(arg2.trim()))? _id+"="+id:arg2+"and"+_id+"="+id; cursor=sqLiteDatabase.query(Table_Name, arg1, arg2, arg3, null, null,arg4); default: throw new IllegalArgumentException("参数错误"); } return cursor; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { // TODO Auto-generated method stub int num=0; sqLiteDatabase=myOpenHelper.getWritableDatabase(); int flag=URI_MATCHER.match(uri); switch (flag) { case 1: num=sqLiteDatabase.update(Table_Name, values,selection, selectionArgs); break; case 2: long id=ContentUris.parseId(uri); selection=(selection==null||"".equals(selection.trim()))? _id+"="+id:selection+"and"+_id+"="+id; num=sqLiteDatabase.update(Table_Name, values,selection, selectionArgs); default: break; } return num; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { // TODO Auto-generated method stub int num=0; sqLiteDatabase=myOpenHelper.getWritableDatabase(); int flag=URI_MATCHER.match(uri); switch (flag) { case 1: num=sqLiteDatabase.delete(Table_Name, selection, selectionArgs); break; case 2: long id=ContentUris.parseId(uri); selection=(selection==null||"".equals(selection.trim()))?_id+"="+id:selection+"and"+_id+"="+id; num=sqLiteDatabase.delete(Table_Name, selection, selectionArgs); default: throw new IllegalArgumentException("异常参数"); } return num; } private final String DB_Name = "mydb.db"; private final String Table_Name="contacter"; private final int version_1=1; private class MyOpenHelper extends SQLiteOpenHelper { public MyOpenHelper(Context context, String name, CursorFactory factory, int version) { super(context, name, factory, version); } /** * @description 当数据表无连接时创建新的表 */ @Override public void onCreate(SQLiteDatabase db) { String sql = " create table if not exists " + Table_Name + "(id INTEGER PRIMARY KEY AUTOINCREMENT," + "name varchar(64),num varchar(64))"; db.execSQL(sql); } /** * @description 当版本更新时触发的方法 */ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { String sql = " drop table if exists " + Table_Name; db.execSQL(sql); onCreate(db); } } } +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.tigongzhe" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="18" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.example.tigongzhe.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <provider android:name=".provider" android:authorities="com.example.tigongzhe.provider" android:multiprocess="true" android:exported="true" android:permission="com.example.tigongzhe.permission" ></provider> </application> <permission android:name="com.example.tigongzhe.permission" android:protectionLevel="normal"></permission> </manifest> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++package com.example.tigongzhe; import android.R.integer; import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.UriMatcher; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.database.sqlite.SQLiteOpenHelper; import android.net.Uri; import android.provider.SyncStateContract.Helpers; import android.text.Selection; import android.util.Log; public class provider extends ContentProvider { private MyOpenHelper myOpenHelper; private SQLiteDatabase sqLiteDatabase; private static final UriMatcher URI_MATCHER=new UriMatcher(UriMatcher.NO_MATCH); private final String TAG="provider"; private static final String authority="com.example.tigongzhe.provider"; static { URI_MATCHER.addURI(authority, "contacter", 1); URI_MATCHER.addURI(authority, "contacter/#", 2); } private static final String _id="id"; private static final String name="name"; private static final String num="num"; @Override public boolean onCreate() { // TODO Auto-generated method stub myOpenHelper=new MyOpenHelper(getContext(), DB_Name, null, version_1); return true; } @Override public String getType(Uri uri) { // TODO Auto-generated method stub int flag=URI_MATCHER.match(uri); switch (flag) { case 2: return "vnd.android.cursor.item/contacter"; case 1: return "vnd.android.dir.item/contacter"; default: throw new IllegalArgumentException("异常参数"); } } @Override public Uri insert(Uri uri, ContentValues values) { // TODO Auto-generated method stub sqLiteDatabase=myOpenHelper.getWritableDatabase(); int flag=URI_MATCHER.match(uri); switch (flag) { case 1: sqLiteDatabase.insert(Table_Name, name, values); break; case 2: long id=sqLiteDatabase.insert(Table_Name, name, values); ContentUris.withAppendedId(uri, id); default: break; } return uri; } @Override public Cursor query(Uri uri, String[] arg1, String arg2, String[] arg3, String arg4) { // TODO Auto-generated method stub Cursor cursor; sqLiteDatabase=myOpenHelper.getReadableDatabase(); int flag=URI_MATCHER.match(uri); switch (flag) { case 1: cursor=sqLiteDatabase.query(Table_Name, arg1, arg2, arg3, null, null,arg4); break; case 2: long id=ContentUris.parseId(uri); arg2=(arg2==null||"".equals(arg2.trim()))? _id+"="+id:arg2+"and"+_id+"="+id; cursor=sqLiteDatabase.query(Table_Name, arg1, arg2, arg3, null, null,arg4); default: throw new IllegalArgumentException("参数错误"); } return cursor; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { // TODO Auto-generated method stub int num=0; sqLiteDatabase=myOpenHelper.getWritableDatabase(); int flag=URI_MATCHER.match(uri); switch (flag) { case 1: num=sqLiteDatabase.update(Table_Name, values,selection, selectionArgs); break; case 2: long id=ContentUris.parseId(uri); selection=(selection==null||"".equals(selection.trim()))? _id+"="+id:selection+"and"+_id+"="+id; num=sqLiteDatabase.update(Table_Name, values,selection, selectionArgs); default: break; } return num; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { // TODO Auto-generated method stub int num=0; sqLiteDatabase=myOpenHelper.getWritableDatabase(); int flag=URI_MATCHER.match(uri); switch (flag) { case 1: num=sqLiteDatabase.delete(Table_Name, selection, selectionArgs); break; case 2: long id=ContentUris.parseId(uri); selection=(selection==null||"".equals(selection.trim()))?_id+"="+id:selection+"and"+_id+"="+id; num=sqLiteDatabase.delete(Table_Name, selection, selectionArgs); default: throw new IllegalArgumentException("异常参数"); } return num; } private final String DB_Name = "mydb.db"; private final String Table_Name="contacter"; private final int version_1=1; private class MyOpenHelper extends SQLiteOpenHelper { public MyOpenHelper(Context context, String name, CursorFactory factory, int version) { super(context, name, factory, version); } /** * @description 当数据表无连接时创建新的表 */ @Override public void onCreate(SQLiteDatabase db) { String sql = " create table if not exists " + Table_Name + "(id INTEGER PRIMARY KEY AUTOINCREMENT," + "name varchar(64),num varchar(64))"; db.execSQL(sql); } /** * @description 当版本更新时触发的方法 */ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { String sql = " drop table if exists " + Table_Name; db.execSQL(sql); onCreate(db); } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值