深入学习ContentProvider
2015-06-16 23:24
671 查看
ContentProvider为存储和读取数据提供了统一的接口
使用ContentProvider,应用程序可以实现数据共享
android内置的许多数据都是使用ContentProvider形式,供开发者调用的(如视频,音频,图片,通讯录等)
当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据。虽然使用其他方法也可以对外共享数据,但数据访问方式会因数据存储的方式而不同,如:采用文件方式对外共享数据,需要进行文件操作读写数据;采用sharedpreferences共享数据,需要使用sharedpreferences API读写数据。而使用ContentProvider共享数据的好处是统一了数据访问方式。
一个应用程序可以通过实现一个Content provider的抽象接口将自己的数据共享给其他应用程序,而且Content providers是以类似数据库表的方式将数据暴露。
Content providers存储和检索数据,通过它可以让所有的应用程序访问到,这也是应用程序之间唯一共享数据的方法。
要想使应用程序的数据公开化,可通过2种方法:
创建一个属于你自己的Content provider或者将你的数据添加到一个已经存在的Content provider中,前提是有相同数据类型并且有写入Content provider的权限。
那么如何通过统一的接口获取其他应用程序共享的数据呢?
Android提供了ContentResolver,外界的程序可以通过ContentResolver接口访问ContentProvider提供的数据。
ContentUris:用于获取Uri路径后面的ID部分,它有两个比较实用的方法:
• withAppendedId(uri, id)用于为路径加上ID部分
• parseId(uri)方法用于从路径中获取ID部分
View
Code
ContentResolver提供了如下主要方法:
View
Code
这里主要说下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
2:然后定义MyContentProvider继承ContentProvider,并且在类加载时候初始化UriMatcher匹配,以及授权AUTHORITY,同时,这个ContentProvider需要在AndroidManifest.xml中进行注册,并添加授权。
代码如下:
View
Code
如果我们基本了解了上述说的基础知识,那么这些代码不难看懂,其实也非常简单,不直接操作DBHelper类,而是通过ContentProvider间接操作,而操作ContentProvider又是太通过ContentResolver这个类,实现不同应用都可以访问这些数据。
使用ContentProvider,应用程序可以实现数据共享
android内置的许多数据都是使用ContentProvider形式,供开发者调用的(如视频,音频,图片,通讯录等)
当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据。虽然使用其他方法也可以对外共享数据,但数据访问方式会因数据存储的方式而不同,如:采用文件方式对外共享数据,需要进行文件操作读写数据;采用sharedpreferences共享数据,需要使用sharedpreferences API读写数据。而使用ContentProvider共享数据的好处是统一了数据访问方式。
一个应用程序可以通过实现一个Content provider的抽象接口将自己的数据共享给其他应用程序,而且Content providers是以类似数据库表的方式将数据暴露。
Content providers存储和检索数据,通过它可以让所有的应用程序访问到,这也是应用程序之间唯一共享数据的方法。
要想使应用程序的数据公开化,可通过2种方法:
创建一个属于你自己的Content provider或者将你的数据添加到一个已经存在的Content provider中,前提是有相同数据类型并且有写入Content provider的权限。
那么如何通过统一的接口获取其他应用程序共享的数据呢?
Android提供了ContentResolver,外界的程序可以通过ContentResolver接口访问ContentProvider提供的数据。
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,并建表。 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中进行注册,并添加授权。 代码如下: <p>说了那么多,是时候了解<strong>ContentProvider</strong>的使用了,我们这里采用sqlite存贮数据。当然,我们直接采用联系人数据不是更好? </p><p>1:首先我们定义DBHelper继承SQLiteOpenHelper,并建表。</p><div class="cnblogs_code"><img style="display: none;" id="code_img_closed_26c89d67-4e4f-45c8-80ca-277ba26706af" class="code_img_closed" alt="" src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" /><img id="code_img_opened_26c89d67-4e4f-45c8-80ca-277ba26706af" class="code_img_opened" alt="" src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" /><span style="display: none;" class="cnblogs_code_collapse">View Code </span><div id="cnblogs_code_open_26c89d67-4e4f-45c8-80ca-277ba26706af" class="cnblogs_code_hide"><div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></span></div><pre><span style="color: rgb(0, 0, 255);">package</span> com.dongzi; <span style="color: rgb(0, 0, 255);">import</span> android.content.Context; <span style="color: rgb(0, 0, 255);">import</span> android.database.sqlite.SQLiteDatabase; <span style="color: rgb(0, 0, 255);">import</span> android.database.sqlite.SQLiteDatabase.CursorFactory; <span style="color: rgb(0, 0, 255);">import</span> android.database.sqlite.SQLiteOpenHelper; <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">class</span> DBHelper <span style="color: rgb(0, 0, 255);">extends</span> SQLiteOpenHelper { <span style="color: rgb(0, 0, 255);">static</span> <span style="color: rgb(0, 0, 255);">final</span> String DB_NAME = "dongzi.db"; <span style="color: rgb(0, 0, 255);">static</span> <span style="color: rgb(0, 0, 255);">final</span> <span style="color: rgb(0, 0, 255);">int</span> DB_VERSION = 1; <span style="color: rgb(0, 0, 255);">static</span> <span style="color: rgb(0, 0, 255);">final</span> String TABLE="persion"; <span style="color: rgb(0, 0, 255);">static</span> <span style="color: rgb(0, 0, 255);">final</span> String TABLE_COLUMN_NAME="name"; <span style="color: rgb(0, 0, 255);">static</span> <span style="color: rgb(0, 0, 255);">final</span> String TABLE_COLUMN_PHONE="phone"; <span style="color: rgb(0, 0, 255);">static</span> <span style="color: rgb(0, 0, 255);">final</span> String CREATE_TABLE = "create table persion(id integer primary key autoincrement,name varchar(40) phone varchar(40))"; <span style="color: rgb(0, 0, 255);">static</span> <span style="color: rgb(0, 0, 255);">final</span> String DRPO_TABLE="drop table if exists persion"; <span style="color: rgb(0, 0, 255);">public</span> DBHelper(Context context) { <span style="color: rgb(0, 0, 255);">super</span>(context, DB_NAME, <span style="color: rgb(0, 0, 255);">null</span>, DB_VERSION); } @Override <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">void</span> onCreate(SQLiteDatabase db) { db.execSQL(CREATE_TABLE); } @Override <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">void</span> onUpgrade(SQLiteDatabase db, <span style="color: rgb(0, 0, 255);">int</span> oldVersion, <span style="color: rgb(0, 0, 255);">int</span> newVersion) { <span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">这里其实是比较版本,然后升级数据库的,比如说是增加一个字段,或者删除一个字段,或者增加表</span><span style="color: rgb(0, 128, 0);"> </span> 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;
}
}
如果我们基本了解了上述说的基础知识,那么这些代码不难看懂,其实也非常简单,不直接操作DBHelper类,而是通过ContentProvider间接操作,而操作ContentProvider又是太通过ContentResolver这个类,实现不同应用都可以访问这些数据。
相关文章推荐
- 深入学习ContentProvider 2015-06-16 23:24 13人阅读 评论(0) 收藏
- laravel深入分析
- ftp装好配置好但是还是连接失败
- 转载--thinkphp框架的路径问题 - 总结
- thinkphp使用phpqrcode生成带logo二维码
- php扩展开发笔记(7) 错误使用 php_base64_decode 导致内存溢出
- vim+xdebug调试PHP
- H.264 RTP Streaming
- php学习整理之mysql(三)配置php使其支持mysql
- 用 xampp 在ubuntu 下配置php 运行环境 lampp
- 配置vsftpd
- [FlashDevelop] 001.FlashDevelop + LayaFlash环境搭建
- vsftpd 配置:chroot_local_user与chroot_list_enable详解
- MVC在安卓应用,ANR,Force Close,Contentprovider实现数据共享
- Loader异步加载ContentProvider
- 为Ubuntu安装FTP服务
- 在Windows下用C扩展PHP(打包成dll)的方法
- php框架的学习
- 系统吞吐量(TPS)、用户并发量、性能测试概念和公式
- Laravel导出excel教程