`
zhanglfat
  • 浏览: 89917 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Uri、UriMatcher、ContentUris类使用介绍&&Android应用间数据共享之ContentProvider

 
阅读更多
Android应用开发中我们会经常用Uri进行数据的处理,下面简单介绍一下与Uri相关Api类的使用方法,希望能给大家提供帮助.
一、Uri介绍
Uri代表了要操作的数据,Uri主要包含了两部分信息:
1》需要操作的ContentProvider ,
2》对ContentProvider中的什么数据进行操作,一个Uri由以下几部分组成:
content:// com.xxx.provider.myprovider /person/10
scheme           主机名或authority           路径ID

ContentProvider(内容提供者)的scheme已经由Android所规定, scheme为:content://
主机名(或叫Authority)用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。
路径(path)可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:
要操作person表中id为10的记录,可以构建这样的路径:/person/10
要操作person表中id为10的记录的name字段, person/10/name
要操作person表中的所有记录,可以构建这样的路径:/person
要操作xxx表中的记录,可以构建这样的路径:/xxx
当然要操作的数据不一定来自数据库,也可以是文件等他存储方式,如下:
要操作xml文件中person节点下的name节点,可以构建这样的路径:/person/name
如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下:
Uri uri = Uri.parse("content://com.xxx.provider.myprovider/person")


二、UriMatcher类使用介绍
因为Uri代表了要操作的数据,所以我们很经常需要解析Uri,并从Uri中获取数据。
Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher 和ContentUris 。掌握它们的使用,会便于我们的开发工作。
UriMatcher类用于匹配Uri,它的用法如下:
首先第一步把你需要匹配Uri路径全部给注册上,如下:
        //常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码
        UriMatcher  sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        //如果match()方法匹配content://com.xxx.provider.myprovider/person路径,返回匹配码为1
        sMatcher.addURI(“com.xxx.provider.myprovider”, “person”, 1); //添加需要匹配uri,如果匹配就会返回匹配码
        //如果match()方法匹配content://com.xxx.provider.myprovider/person/230路径,返回匹配码为2
        sMatcher.addURI(“com.xxx.provider.myprovider”, “person/#”, 2);  //#号为通配符
        switch (sMatcher.match(Uri.parse("content://com.xxx.provider.myprovider/person/10"))) {
            case 1
                    break;
                case 2
                    break;
            default://不匹配
                    break;
        }

注册完需要匹配的Uri后,就可以使用sMatcher.match(uri)方法对输入的Uri进行匹配,
如果匹配就返回匹配码,匹配码是调用addURI()方法传入的第三个参数,
假设匹配content://com.xxx.provider.myprovider/person路径,返回的匹配码为1


三、ContentUris类使用介绍
ContentUris类用于获取Uri路径后面的ID部分,它有两个比较实用的方法:
withAppendedId(uri, id)用于为路径加上ID部分:
Uri uri = Uri.parse("content://com.xxx.provider.myprovider/person");
Uri resultUri = ContentUris.withAppendedId(uri, 10);
//生成后的Uri为:content://com.xxx.provider.myprovider/person/10
parseId(uri)方法用于从路径中获取ID部分:
Uri uri = Uri.parse("content://com.xxx.provider.myprovider/person/10")
long personid = ContentUris.parseId(uri);//获取的结果为:10










/***********************************************************/
  通常在android应用中,数据都是在本应用沙盒之内的,其他外部应用不能够访问,那么如果一个应用需要访问另外一个应用的数据,怎么办呢?那就把另外一个应用的数据公布出来,比如android中的通讯录数据,这些数据是以ContentProvider方式提供与其他应用访问的。

    那么我们也可以定义自己的ContentProvider来使跨应用共享数据。数据具体的存贮方式可以为数据库、文件,持久化或非持久化存储的其他形式。在这里我们还是使用sqlite数据库存贮数据吧。

老规矩,先来点基础知识。
一.基础知识

1:URI是什么?统一资源标识符,用来标识某一资源的。

通常一个Uri主要由以三部分组成:scheme、Authority、path
     1.scheme:ContentProvider(内容提供者)的scheme已经由Android系统规定为:content://
     2.主机名(或Authority):用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。
     3.路径(path):可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:
      要操作persion表中id为5的记录,可以构建这样的路径:/persion/5
      要操作persion表中id为20的记录的name字段, persion/name/10
      要操作persion表中的所有记录,可以构建这样的路径:/persion
使用Uri类中的parse()方法获取Uri: Uri uri = Uri.parse("content://com.dongzi/persion")

上面Uri的scheme:      content://

            Authority:    com.dongzi

            path:             /contact


2、UriMatcher、ContentUrist和ContentResolver

Android系统提供了两个用于操作Uri的工具类:UriMatcher 和ContentUris

UriMatcher:用于匹配Uri:
View Code
复制代码

static final int CODES=2;
    static final int CODE=1;
    static final String AUTHORITY="com.dongzi";          //授权
    static final UriMatcher uriMatcher;                  //Uri匹配
    static {                                             //注册匹配的Uri以及返回码
        uriMatcher=new UriMatcher(UriMatcher.NO_MATCH);  //不匹配任何路径返回-1
        uriMatcher.addURI(AUTHORITY, "persion", CODES);  //匹配content://com.dongzi/persion 返回2
        uriMatcher.addURI(AUTHORITY, "persion/#", CODE); //匹配content://com.dongzi/persion/1234 返回1
    }
   
   

复制代码

ContentUris:用于获取Uri路径后面的ID部分,它有两个比较实用的方法:
•         withAppendedId(uri, id)用于为路径加上ID部分
•         parseId(uri)方法用于从路径中获取ID部分
View Code
复制代码

//为Uri添加ID
        Uri uri=Uri.parse("content://"+AUTHORITY+"/persion");
        ContentUris.withAppendedId(uri, 1234);
        //生成后的Uri为:content://com.dongzi/person/1234
       
        //获取Uri后面的ID
        long id=ContentUris.parseId(Uri.parse("content://com.dongzi/person/1234"));
        //得到ID为:1234

复制代码

ContentResolver提供了如下主要方法:
View Code
复制代码

@Override
    public int delete(Uri arg0, String arg1, String[] arg2) {
        //该方法用于供外部应用从ContentProvider删除数据。
        return 0;
    }
    @Override
    public String getType(Uri uri) {
        //该方法用于返回当前Url所代表数据的MIME类型。
        return null;
    }
    @Override
    public Uri insert(Uri uri, ContentValues values) {
        //该方法用于供外部应用往ContentProvider添加数据。
        return null;
    }
    @Override
    public boolean onCreate() {
        //在其它应用第一次访问它时被创建。
        return false;
    }
    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
         //该方法用于供外部应用从ContentProvider中获取数据。
        return null;
    }
    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        //该方法用于供外部应用更新ContentProvider中的数据。
        return 0;
    }

复制代码

这里主要说下Url所代表数据的MIME类型:

如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/开头,

例如:要得到所有person记录的Uri为content://com.dongzi/person,那么返回的MIME类型字符串应该为:"vnd.android.cursor.dir/person"。

如果要操作的数据属于非集合类型数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头,

例如:得到id为1234的person记录,Uri为content://com.dongzi/person/1234,那么返回的MIME类型字符串为:"vnd.android.cursor.item/person"。

使用ContentResolver操作ContentProvider中的数据

当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查 询操作时,可以使用ContentResolver 类来完成,要获取ContentResolver 对象,可以使用Activity提供的getContentResolver()方法。ContentResolver提供了ContentProvider对应的增、删、改、查方法。

监听ContentProvider中数据的变化

如果我们需要得到数据变化通知,可以使用ContentObserver对数据(数据采用uri描述)进行通知更改以及监听。
View Code
复制代码

//通知内容以及发生改变,同时注册了内容监听,监听到内容变化,就调用onChange方法
        this.getContext().getContentResolver().notifyChange(uri, new ContentObserver(new Handler()){
            public void onChange(boolean selfChange) {
                  //此处可以进行相应的业务处理
               }
        });

复制代码
二.实战

说了那么多,是时候了解ContentProvider的使用了,我们这里采用sqlite存贮数据。当然,我们直接采用联系人数据不是更好?

1:首先我们定义DBHelper继承SQLiteOpenHelper,并建表。
View Code
复制代码

package com.dongzi;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;

public class DBHelper extends SQLiteOpenHelper {

    static final String DB_NAME = "dongzi.db";
    static final int DB_VERSION = 1;
    static final String TABLE="persion";
    static final String TABLE_COLUMN_NAME="name";
    static final String TABLE_COLUMN_PHONE="phone";
    static final String CREATE_TABLE = "create table persion(id integer primary key autoincrement,name varchar(40) phone varchar(40))";
    static final String DRPO_TABLE="drop table if exists persion";
    public DBHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);

    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_TABLE);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
     //这里其实是比较版本,然后升级数据库的,比如说是增加一个字段,或者删除一个字段,或者增加表
     db.execSQL(DRPO_TABLE);
     onCreate(db);
    }

}

复制代码

2:然后定义MyContentProvider继承ContentProvider,并且在类加载时候初始化UriMatcher匹配,以及授权AUTHORITY,同时,这个ContentProvider需要在AndroidManifest.xml中进行注册,并添加授权。

代码如下:
View Code
复制代码

package com.dongzi;

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

public class MyContentProvider extends ContentProvider {
   
    DBHelper dbHelper=null;
    //MIME类型
    static final String PERSIONS_TYPE="vnd.android.cursor.dir/person";
    static final String PERSION_ITEM_TYPE="vnd.android.cursor.item/person";
    //返回码
    static final int CODES=2;
    static final int CODE=1;
    //授权
    static final String AUTHORITY="com.dongzi";          //授权
    static final UriMatcher uriMatcher;                  //Uri匹配
    static {                                             //注册匹配的Uri以及返回码
        uriMatcher=new UriMatcher(UriMatcher.NO_MATCH);  //不匹配任何路径返回-1
        uriMatcher.addURI(AUTHORITY, "persion", CODES);  //匹配content://com.dongzi/persion 返回2
        uriMatcher.addURI(AUTHORITY, "persion/#", CODE); //匹配content://com.dongzi/persion/1234 返回1
    }
   
    private void init(){
        //为Uri添加ID
        Uri uri=Uri.parse("content://"+AUTHORITY+"/persion");
        ContentUris.withAppendedId(uri, 1234);
        //生成后的Uri为:content://com.dongzi/person/1234
       
        //获取Uri后面的ID
        long id=ContentUris.parseId(Uri.parse("content://com.dongzi/person/1234"));
        //得到ID为:1234
    }
   
   
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        //该方法用于供外部应用从ContentProvider删除数据。
        SQLiteDatabase db=dbHelper.getWritableDatabase();
        int count=0;
        switch(uriMatcher.match(uri)){
        case CODES:
          count = db.delete(DBHelper.DB_NAME, selection, selectionArgs);
          break;
        case CODE:
            // 下面的方法用于从URI中解析出id,对这样的路径content://com.dongzi/persion/1234
            // 进行解析,返回值为10
            long id = ContentUris.parseId(uri);
            String where = "id=" + id;// 删除指定id的记录
            where += !TextUtils.isEmpty(selection) ? " and (" + selection + ")" : "";// 把其它条件附加上
            count = db.delete(DBHelper.DB_NAME, where, selectionArgs);
            break;
        default:throw new IllegalArgumentException("throw Uri:"+uri.toString());
       
        }
        db.close();
        return count;
    }
    @Override
    public String getType(Uri uri) {
        //该方法用于返回当前Url所代表数据的MIME类型。
        switch(uriMatcher.match(uri)){
        case CODES:
         return PERSIONS_TYPE;               //这里CODES代表集合,故返回的是集合类型的MIME
        case CODE:
             return PERSION_ITEM_TYPE;
        default:throw new IllegalArgumentException("throw Uri:"+uri.toString());
        }
    }
    @Override
    public Uri insert(Uri uri, ContentValues values) {
        //该方法用于供外部应用往ContentProvider添加数据。
        SQLiteDatabase db= dbHelper.getWritableDatabase();
        long id=0;
        //匹配Uri
        switch(uriMatcher.match(uri)){
         //返回码
        case CODES:
            id=db.insert(DBHelper.TABLE, DBHelper.TABLE_COLUMN_NAME, values);// 返回的是记录的行号,主键为int,实际上就是主键值
            return ContentUris.withAppendedId(uri, id);
        case CODE:
            id=db.insert(DBHelper.TABLE, DBHelper.TABLE_COLUMN_NAME, values);// 返回的是记录的行号,主键为int,实际上就是主键值
            String path = uri.toString();
            return Uri.parse(path.substring(0, path.lastIndexOf("/"))+id); // 替换掉id
        default:throw new IllegalArgumentException("throw Uri:"+uri.toString());
        }
    }
    @Override
    public boolean onCreate() {
        //在其它应用第一次访问它时被创建。
        dbHelper =new DBHelper(getContext());
        return false;
    }
    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
         //该方法用于供外部应用从ContentProvider中获取数据。
        SQLiteDatabase db=dbHelper.getWritableDatabase();
        Cursor cursor=null;
        switch(uriMatcher.match(uri)){
        case CODES:
            cursor=db.query(DBHelper.DB_NAME, projection, selection, selectionArgs, null, null, sortOrder);
            break;
        case CODE:
               //下面的方法用于从URI中解析出id,对这样的路径content://com.dongzi/persion/1234
                // 进行解析,返回值为10
                long id = ContentUris.parseId(uri);
                String where = "id=" + id;// 获取指定id的记录
                where += !TextUtils.isEmpty(selection) ? " and (" + selection + ")" : "";// 把其它条件附加上
                cursor=db.query(DBHelper.DB_NAME, projection, where, selectionArgs, null, null, sortOrder);
                break;
            default:break;
        }
        return cursor;
    }
    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        //该方法用于供外部应用更新ContentProvider中的数据。
        return 0;
    }

}
分享到:
评论

相关推荐

    Android实现使用自定义ContentProvider共享生词本数据库

    Android高级编程雪梨作业之自定义ContentProvider 将任务01生词本作业中生成的生词本数据库通过自定义ContentProvider的方式,共享给其他应用。 要求如下: (1) 使用自定义SQLiteOpenHelper来管理数据库; (2) 提交...

    androdi ContentProvider和Uri详解

    androdi ContentProvider和Uri详解

    contentprovider

    当应用继承ContentProvider类 并重写该类用于提供数据和存储数据的方法 就可以向其他应用共享其数据 虽然使用其他方法也可以对外共享数据 但数据访问方式会因数据存储的方式而不同 如:采用文件方式对外共享数据 ...

    基于Android ContentProvider的总结详解

    1.适用场景1) ContentProvider为存储和读取数据提供了统一的接口2) 使用ContentProvider,应用程序可以实现数据共享3) android内置的许多数据都是使用ContentProvider形式,供开发者调用的(如视频,音频,图片,...

    android-关于ContentProvider的使用例子

    android-关于ContentProvider的使用例子 有详细注释

    Android学习笔记之ContentProvider和Uri详解

    本篇文章主要介绍了Android学习笔记之ContentProvider和Uri详解,对于学习Android的朋友具有一定的参考价值,有需要可以可以了解一下。

    Android程序技术:ContentProvider.pptx

    进程间共享数据的本质是:添加、删除、获取 & 修改(更新)数据。 以ContentProvider的核心方法也主要是以下4个作用 Android为常见的数据(如通讯录、日程表等)提供了内置了默认的ContentProvider。 ...

    ContentProvider

    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...

    Android开发之ContentProvider的使用详解

     Content Provider为存储数据和获取数据提供了统一的接口,它可以完成在不同应用程序下的数据共享,而在上一篇文章Android开发之SQLite的使用方法讲到的SQLite只能在同一个程序中共享数据。另外android为一些常见的...

    android:scheme 通过uri跳转到APP应用指定Activity

    android:scheme 通过uri跳转到APP应用指定Activity

    Android开发教程之ContentProvider数据存储

    ContentProvider提供了一种多应用间数据共享的方式。 ContentProvider是个实现了一组用于提供其他应用程序存取数据的标准方法的类。应用程序可以在ContentProvider中执行如下操作:查询数据、修改数据、添加数据、...

    Android ContentProvider的实现及简单实例代码

    内容提供者是一个Android应用的基础模块,提供内容给这个应用,它们封装数据和提供它给应用通过这个ContentResolver接口,使用ContentProvider可以在不同的应用程序之间共享数据,android为常见的一些数据提供了...

    A_APP通过Uri调用B_APP(Uri含两个应用包)demo最新版

    Android APP间授权登录(无需SDK类似微信登录),A_APP通过Uri调用B_APP(Uri含两个应用包)demo

    Android 中ContentProvider的实例详解

    在Android系统中,没有一个公共的内存区域,供多个应用共享存储数据; * Android 提供了一些主要数据类型的ContentProvider ,比如:音频、视频、图片和私人通讯录等; 在android.provider 包下面找到一些...

    Android识别TextView的Uri并在自己的应用程序中打开

    Android识别TextView的Uri并在自己的应用程序中打开

    查看android.provider包中的uri内容

    可以快速查找android.provider包中所有类的中的URI里面的详细内容,当进入详细内容时 内容没有完全显示时 你可以点击列进行展开 你也可以单击你想看的那行内容 查看那一行的具体信息

    ContentProvider与ContentResolver跨进程共享数据实例

    程序例子包含了2个独立的Android程序,其中一个负责提供数据并提供本地操作,另外一个可以跨进程访问提供者提供的数据。...由于没有其他多余的代码,功能针对性很强,是学习Android跨进程数据共享的入门助手。

    Android中ContentProvider和ContentResolver详解

    在Android中,我们的应用有的时候需要对外提供数据接口,可以有如下几种方法: 1)AIDL 2)Broadcast 3)ContentProvider。 使用AIDL需要我们编写AIDL接口以及实现,而且对方也要有相应的接口描述,有点麻烦;使用...

Global site tag (gtag.js) - Google Analytics