文章标题

ContentProvider向我们提供了我们在应用程序之前共享数据的一种机制,而我们知道每一个应用程序都是运行在不同的应用程序的,数据和文件在不同应用程序之间达到数据的共享不是没有可能,而是显得比较复杂,而正好Android中的ContentProvider则达到了这一需求,比如有时候我们需要操作手机里的联系人,手机里的多媒体等一些信息,我们都可以用到这个ContentProvider来达到我们所需。

1)、ContentProvider为存储和获取数据提供了统一的接口。ContentProvide对数据进行封装,不用关心数据存储的细节。使用表的形式来组织数据。
2)、使用ContentProvider可以在不同的应用程序之间共享数据。
3)、Android为常见的一些数据提供了默认的ContentProvider(包括音频、视频、图片和通讯录等)。
总的来说使用ContentProvider对外共享数据的好处是统一了数据的访问方式。
我们在此先介绍provider的写法,
(1)首先该类必须继承 ContentProvider

public class DictProvider extends ContentProvider

Uri

为系统的每一个资源起一个名字,比方说通话记录。
1)、每一个ContentProvider都拥有一个公共的URI,这个URI用于表示这个ContentProvider所提供的数据。
2)、Android所提供的ContentProvider都存放在android.provider包中。 将其分为A,B,C,D 4个部分:
这里写图片描述
A:标准前缀,用来说明一个Content Provider控制这些数据,无法改变的;”content://”
B:AUTHORITY (URI 的标识),用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。它定义了是哪个Content Provider提供这些数据。对于第三方应用程序,为了保证URI标识的唯一性,它必须是一个完整的、小写的类名。这个标识在 元素的 authorities属性中说明:一般是定义该ContentProvider的包.类的名称
C:路径(path),通俗的讲就是你要操作的数据库中表的名字,或者你也可以自己定义,记得在使用的时候保持一致就可以了;”content://com.bing.provider.myprovider/tablename”
D:如果URI中包含表示需要获取的记录的ID;则就返回该id对应的数据,如果没有ID,就表示返回全部; “content://com.bing.provider.myprovider/tablename/#” #表示数据id。
PS:

路径(path)可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:
1、要操作person表中id为10的记录,可以构建这样的路径:/person/10
2、要操作person表中id为10的记录的name字段, person/10/name
3、要操作person表中的所有记录,可以构建这样的路径:/person
4、要操作xxx表中的记录,可以构建这样的路径:/xxx
5、当然要操作的数据不一定来自数据库,也可以是文件、xml或网络等其他存储方式,如下:
要操作xml文件中person节点下的name节点,可以构建这样的路径:/person/name
6、如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下:Uri uri = Uri.parse(“content://com.bing.provider.personprovider/person”)
(2)一般我们会在一个静态类里面定义AUTHORITY 即Uri

 // 定义该ContentProvider的Authority
    public static final String AUTHORITY
            = "org.crazyit.providers.dictprovider";
 // 定义该Content提供服务的两个Uri
        public final static Uri DICT_CONTENT_URI = Uri
                .parse("content://" + AUTHORITY + "/words");
        public final static Uri WORD_CONTENT_URI = Uri
                .parse("content://" + AUTHORITY + "/word");

UriMatcher类使用介绍

UriMatcher类用于匹配Uri,它的用法如下:
(3)为UriMatcher注册两个Uri

 // 为UriMatcher注册两个Uri
        matcher.addURI(Words.AUTHORITY, "words", WORDS);
        matcher.addURI(Words.AUTHORITY, "word/#", WORD);

(4)注册完需要匹配的Uri后,就可以使用matcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码,匹配码是调用addURI()方法传入的第三个参数,上面的匹配码分别是WORDS、WORD,这里值分别是1和2.

 switch (matcher.match(uri))
        {
            // 如果操作的数据是多项记录
            case WORDS:
               ...
            case WORD:
               ...
            default:
                throw new IllegalArgumentException("未知Uri:" + uri);
        }

ContentUris类使用介绍

ContentUris类用于操作Uri路径后面的ID部分,它有两个比较实用的方法:
withAppendedId(uri, id)用于为路径加上ID部分:

Uri uri = Uri.parse("content://com.bing.provider.personprovider/person")
Uri resultUri = ContentUris.withAppendedId(uri, 10); 
//生成后的Uri为:content://com.bing.provider.personprovider/person/10

parseId(uri)方法用于从路径中获取ID部分:

Uri uri = Uri.parse("content://com.ljq.provider.personprovider/person/10")
long personid = ContentUris.parseId(uri);//获取的结果为:10

(5)完成继承的方法增删改查及getType,onCreate方法的复写。值得注意的是,onCreate()是在系统调用该provider是自动调用的,而其他的方法则是在另一个程序里该同名方法被执行时自动调用的。

// 第一次调用该DictProvider时,系统先创建DictProvider对象,并回调该方法
    @Override
    public boolean onCreate()
    {
        dbOpenHelper = new MyDatabaseHelper(this.getContext(),
                "myDict.db3", 1);
        return true;
    }
    // 返回指定Uri参数对应的数据的MIME类型
    @Override
    public String getType(Uri uri)
    {
        switch (matcher.match(uri))
        {
            // 如果操作的数据是多项记录
            case WORDS:
                return "vnd.android.cursor.dir/org.crazyit.dict";
            // 如果操作的数据是单项记录
            case WORD:
                return "vnd.android.cursor.item/org.crazyit.dict";
            default:
                throw new IllegalArgumentException("未知Uri:" + uri);
        }
    }
    // 查询数据的方法
    @Override
    public Cursor query(Uri uri, String[] projection, String where,
                        String[] whereArgs, String sortOrder)
    {
        SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
        switch (matcher.match(uri))
        {
            // 如果Uri参数代表操作全部数据项
            case WORDS:
                // 执行查询
                return db.query("dict", projection, where,
                        whereArgs, null, null, sortOrder);
            // 如果Uri参数代表操作指定数据项
            case WORD:
                // 解析出想查询的记录ID
                long id = ContentUris.parseId(uri);
                String whereClause = Words.Word._ID + "=" + id;
                // 如果原来的where子句存在,拼接where子句
                if (where != null && !"".equals(where))
                {
                    whereClause = whereClause + " and " + where;
                }
                return db.query("dict", projection, whereClause, whereArgs,
                        null, null, sortOrder);
            default:
                throw new IllegalArgumentException("未知Uri:" + uri);
        }
    }
    // 插入数据方法
    @Override
    public Uri insert(Uri uri, ContentValues values)
    {
        // 获得数据库实例
        SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
        switch (matcher.match(uri))
        {
            // 如果Uri参数代表操作全部数据项
            case WORDS:
                // 插入数据,返回插入记录的ID
                long rowId = db.insert("dict", Words.Word._ID, values);
                // 如果插入成功返回uri
                if (rowId > 0)
                {
                    // 在已有的 Uri的后面追加ID
                    Uri wordUri = ContentUris.withAppendedId(uri, rowId);
                    // 通知数据已经改变
                    getContext().getContentResolver()
                            .notifyChange(wordUri, null);
                    return wordUri;
                }
                break;
            default :
                throw new IllegalArgumentException("未知Uri:" + uri);
        }
        return null;
    }
    // 修改数据的方法
    @Override
    public int update(Uri uri, ContentValues values, String where,
                      String[] whereArgs)
    {
        SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
        // 记录所修改的记录数
        int num = 0;
        switch (matcher.match(uri))
        {
            // 如果Uri参数代表操作全部数据项
            case WORDS:
                num = db.update("dict", values, where, whereArgs);
                break;
            // 如果Uri参数代表操作指定数据项
            case WORD:
                // 解析出想修改的记录ID
                long id = ContentUris.parseId(uri);
                String whereClause = Words.Word._ID + "=" + id;
                // 如果原来的where子句存在,拼接where子句
                if (where != null && !where.equals(""))
                {
                    whereClause = whereClause + " and " + where;
                }
                num = db.update("dict", values, whereClause, whereArgs);
                break;
            default:
                throw new IllegalArgumentException("未知Uri:" + uri);
        }
        // 通知数据已经改变
        getContext().getContentResolver().notifyChange(uri, null);
        return num;
    }
    // 删除数据的方法
    @Override
    public int delete(Uri uri, String where, String[] whereArgs)
    {
        SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
        // 记录所删除的记录数
        int num = 0;
        // 对uri进行匹配
        switch (matcher.match(uri))
        {
            // 如果Uri参数代表操作全部数据项
            case WORDS:
                num = db.delete("dict", where, whereArgs);
                break;
            // 如果Uri参数代表操作指定数据项
            case WORD:
                // 解析出所需要删除的记录ID
                long id = ContentUris.parseId(uri);
                String whereClause = Words.Word._ID + "=" + id;
                // 如果原来的where子句存在,拼接where子句
                if (where != null && !where.equals(""))
                {
                    whereClause = whereClause + " and " + where;
                }
                num = db.delete("dict", whereClause, whereArgs);
                break;
            default:
                throw new IllegalArgumentException("未知Uri:" + uri);
        }
        // 通知数据已经改变
        getContext().getContentResolver().notifyChange(uri, null);
        return num;
    }

至此我们已经完成了provider类。
不过在写好DictProvider类以后需要在manifest文件声明

  <provider android:name=".DictProvider"
            android:authorities="org.crazyit.providers.dictprovider"
            android:exported="true"/>

而且要使该类能被调用,说明在调用以前也要写好该activity,可以数据库或者其他xml文件等。
接下来我们开始写应用该provider的activity
当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver 类来完成。
(1)要获取ContentResolver 对象,可以使用Activity提供的getContentResolver()方法。

  ContentResolver contentResolver;
 // 获取系统的ContentResolver对象
        contentResolver = getContentResolver();

ContentResolver 类提供了与ContentProvider类相同签名的四个方法:
public Uri insert(Uri uri, ContentValues values):该方法用于往ContentProvider添加数据。
public int delete(Uri uri, String selection, String[] selectionArgs):该方法用于从ContentProvider删除数据。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs):该方法用于更新ContentProvider中的数据。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder):该方法用于从ContentProvider中获取数据。

这些方法的第一个参数为Uri,代表要操作的ContentProvider和对其中的什么数据进行操作,
其实和contentprovider里面的方法是一样的.他们所对应的数据,最终是会被传到我们在之前程序里面定义的那个contentprovider类的方法。
(2)设置查询按钮,插入按钮

 insert = (Button) findViewById(R.id.insert);
 search = (Button) findViewById(R.id.search);

(3)为按钮添加事件,即进行查询,插入数据

  insert.setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View source)
            {
                // 获取用户输入
                String word = ((EditText) findViewById(R.id.word))
                        .getText().toString();
                String detail = ((EditText) findViewById(R.id.detail))
                        .getText().toString();
                // 插入生词记录
                ContentValues values = new ContentValues();
                values.put(Words.Word.WORD, word);
                values.put(Words.Word.DETAIL, detail);
                contentResolver.insert(
                        Words.Word.DICT_CONTENT_URI, values);
                // 显示提示信息
                Toast.makeText(MainActivity.this, "添加生词成功!"
                        , Toast.LENGTH_SHORT).show();
            }
        });
        // 为search按钮的单击事件绑定事件监听器
        search.setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View source)
            {
                // 获取用户输入
                String key = ((EditText) findViewById(R.id.key))
                        .getText().toString();
                // 执行查询
                Cursor cursor = contentResolver.query(
                        Words.Word.DICT_CONTENT_URI, null,
                        "word like ? or detail like ?", new String[] {
                                "%" + key + "%", "%" + key + "%" }, null);
                // 创建一个Bundle对象
                Bundle data = new Bundle();
                data.putSerializable("data", converCursorToList(cursor));
                // 创建一个Intent
                Intent intent = new Intent(MainActivity.this,
                        ResultActivity.class);
                intent.putExtras(data);
                // 启动Activity
                startActivity(intent);
            }
        });

这里调用的contentResolver.insert(), contentResolver.query()实际上是为dictPrivider里对应的方法提供参数。
这样我们就完成不同程序间数据共享。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值