ContentProvider重温

几万年都不见得用一次的ContentProvider,这几天说要用到,除了记得他是四大组件,还真是没啥印象了。。

用到provider,无非是想要跨进程进行DB操作,AIDL,或者两个app,我就是用了AIDL,再说吧。。

先来看下怎么使用ContentProvider进行数据操作。

Uri uri = Uri.parse("content://com.example.test.aidl.provider/student");
        ContentValues values = new ContentValues();
        values.put("name", "sss");
        values.put("age", 555);
        values.put("stuno", 222);
        getContentResolver().insert(uri, values);

调用getContentResolver()得到ContentResolver对象,根据传入的uri,可以知道调用方期望获取的是哪个provider,哪张表,哪条数据。

数据库

既然是DB操作,肯定要有DB了,先搞个DB

public class DBOpenHelper extends SQLiteOpenHelper {

    public DBOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String sql = "create table if not exists student(id integer primary key autoincrement,name varchar(20),age integer,stuno varchar(20))";
        db.execSQL(sql);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

创建DB的时候,新建了一张student表,包含姓名,年龄,学号还有自增ID

ContentProvider

首先创建一个DBProvider继承ContentProvider,默认实现有六个方法,分别为onCreate,query,insert,delete,update,还有getType。

public class DBProvider extends ContentProvider {
    @Override
    public boolean onCreate() {
        return false;
    }

    @Nullable
    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        return null;
    }

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

    @Nullable
    @Override
    public Uri insert(Uri uri, ContentValues values) {
        return null;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        return 0;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        return 0;
    }
}

当ContentResolver尝试访问Provider时,Provider才会初始化,所以在onCreate里创建数据库

 public boolean onCreate() {
        //provider 初始化时创建一个名字为stu.db 版本为1的数据库,这时数据库中有student表
        dbOpenHelper = new DBOpenHelper(getContext(),"stu.db",null,1);
        return true;
    }

再说下URI
一个标准的Uri如下格式
content://com.example.test.aidl.provider/student 访问student表
content://com.example.test.aidl.provider/student/1 访问student表下id为1的数据
包括

  • 声明协议: content://
  • authority :com.example.test.aidl.provider(自定义,一般为包名+.provider)
  • path : student (表名)
  • id:1(可不加,不加时访问整张表)

uri支持通配符

关于uri的匹配
用到UriMatcher这个类
在静态代码块中,初始化匹配规则

    private static final int STUDENT_DIR = 0;
    private static final int STUDENT_ITEM =1;
    private static String AUTHORITY = "com.example.test.aidl.provider";
    private static UriMatcher uriMatcher;

    static {
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI(AUTHORITY, "student", STUDENT_DIR);
        uriMatcher.addURI(AUTHORITY, "student/#", STUDENT_ITEM);
    }

addURI方法添加我们的匹配规则,第一个参数是自定义的AUTHORITY,第二个是Path,可以是表名,也可以是表名下的id结尾,这里#就是上面说的通配符,匹配任意数字,第三个参数是成功匹配uri时返回的自定义整型码

而uri的作用,都体现在除了onCreate之外的五个实现方法中,下面是整个ContentProvider的代码

 import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;

/**
 * Created by walker on 2016/12/7.
 */

public class DBProvider extends ContentProvider {
    
    private DBOpenHelper dbOpenHelper;
    private static final int STUDENT_DIR = 0;
    private static final int STUDENT_ITEM =1;
    private static String AUTHORITY = "com.example.test.aidl.provider";
    private static UriMatcher uriMatcher;

    static {
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI(AUTHORITY, "student", STUDENT_DIR);
        uriMatcher.addURI(AUTHORITY, "student/#", STUDENT_ITEM);
    }
    @Override
    public boolean onCreate() {
       
        dbOpenHelper = new DBOpenHelper(getContext(),"stu.db",null,1);

        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
        Cursor cursor = null;
        switch(uriMatcher.match(uri)){
            case STUDENT_DIR:
                cursor  = db.query("student", projection, selection, selectionArgs, null, null, sortOrder);
                break;
            case STUDENT_ITEM:
                String id = uri.getPathSegments().get(1); //切割URI  AUTHORITY之后的字符,0是路径,1是id
                cursor = db.query("student", projection, "id = ?", new String[]{id}, null, null, sortOrder);
                break;
        }
        cursor.setNotificationUri(getContext().getContentResolver(), uri);
        return cursor;
    }
    //==============================================================
    //返回各个Uri对象对应的MIME类型,MIME由三个部分组成,以vnd开头,
    //如果URI以路径结尾,接android.cursor.dir/   如果以id结尾,接android.cursor.item/
    //最后接vnd.权限.路径
    //对于content://com.example.test.aidl.provider/student
    //对应的MIME为 vnd.android.cursor.dir/vnd.com.example.test.aidl.provider.student
    //==============================================================
    @Override
    public String getType(Uri uri) {
        switch (uriMatcher.match(uri)) {
            case STUDENT_DIR:
                return "vnd.android.cursor.dir/vnd.com.example.test.aidl.provider.student";
            case STUDENT_ITEM:
                return "vnd.android.cursor.item/vnd.com.example.test.aidl.provider.student";
            default:
                break;
        }
        return null;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
        Uri uriReturn = null;
        switch (uriMatcher.match(uri)) {
            case STUDENT_DIR:
            case STUDENT_ITEM:
               long newID = db.insert("student", null, values);
                uriReturn = Uri.parse("content://"+AUTHORITY+"/student/"+newID);
                break;
            default:
                break;
        }
        return uriReturn;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
        int deleteRow = 0;
        switch (uriMatcher.match(uri)) {
            case STUDENT_DIR:
                deleteRow = db.delete("student", selection, selectionArgs);
                break;
            case STUDENT_ITEM:
                String id = uri.getPathSegments().get(1);
                deleteRow = db.delete("student", "id = ?" , new String[]{id});
                break;
        }
        return deleteRow;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
        int updateRows = 0;
        switch (uriMatcher.match(uri)) {
            case STUDENT_DIR:
                updateRows = db.update("student",values, selection, selectionArgs);
                break;
            case STUDENT_ITEM:
                String id = uri.getPathSegments().get(1);
                updateRows = db.update("student",values, "id = ?" , new String[]{id});
                break;
        }
        return updateRows;
    }
}

可以看到,switch里面对传进来的uri进行了匹配,根据结果进行不同操作,也就是一些db操作

这里说下getPathSegments获取的是path,也就是uri中authority之后的部分,这部分有路径,也可能有id,0是路径,1是id(如果有)

关于getType,返回的MIME不知道有啥用,貌似即使provider不exported出去,也是能够让其他进程访问到。

最后别忘了注册provider和exported它

<provider
            android:exported="true"
            android:authorities="com.example.test.aidl.provider"
            android:name=".DBProvider" />
就这样写完了,赶紧去找个多进程或者新建个app访问下这个数据库咯
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容