ContentProvider自定义-笔记
来源:互联网 发布:在线网页制作软件 编辑:程序博客网 时间:2024/06/11 18:34
对于每一个应用程序来说,要想访问访问内容提供器中共享的数据,就一定要借助 ContentResolve 类,可以通过 Context 中的 getContentResolver() 方法获取到该类的实例,提供了一系列的的方法对数据进行增删改查的操作。
不同于SQLitDatabase,ContentResolver 中增删改查方法都是接受表名参数的,而是使用一个 uri 参数代替,这个参数被称为内容 uri ,它主要由两部分组成,权限(authority)和路径(path)。权限是对不同应用程序做区分,一般用包名,路径是对同一程序中不同的表做区分的,比如某个程序的包名是com.example.app,然后在字符串的头部加上声明协议,一个 uri 就是这个样子的content://com.example.app.provider/table1,可以清楚的表达访问哪个程序中的哪张表。得到了 uri 字符串之后需要将他解析成 uri 对象,只需要调用Uri.parse()方法,就可以将内容URI 字符串解析成Uri 对象了。
Uri uri = Uri.parse("content://com.example.app.provider/table1")
我们就可以使用这个Uri 对象来查询table1 表中的数据
Cursor cursor = getContentResolver().query( uri, projection, selection, selectionArgs, sortOrder);
下面是每个参数的意义
接下来简单的写一个获取本地联系人的例子,请看代码.
public class ProviderActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_mvp); Button btnQuery = (Button) findViewById(R.id.btn_query); assert btnQuery != null; btnQuery.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 查询联系人数据 Cursor cursor = getContentResolver().query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null); assert 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)); Log.e("ProviderActivity","__displayName" + displayName); Log.e("ProviderActivity","__number" + number); } cursor.close(); } }); }}查询的参数只添加了一个 uri 默认查询所有 ,可以添加别的参数,用法跟数据库查询差不多,剩下的就是一些系统的常量
添加一个权限:
<uses-permission android:name="android.permission.READ_CONTACTS" />就没什么了。
接下来说说创建自己的内同提供器
首先我们需要创建一个自己的内容提供器 MyProvider 继承自ContentProvider
public class MyProvider extends ContentProvider { public static final int TABLE1_DIR = 0; //访问 table1 中所有的数据 public static final int TABLE1_ITEM = 1; //访问 table1 中的单条数据 public static final int TABLE2_DIR = 2; //访问 table2 中的所有数据 public static final int TABLE2_ITEM = 3; //访问 table2 中的单条数据 private static UriMatcher uriMatcher; static { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI("com.ning.demosky", "table1", TABLE1_DIR); uriMatcher.addURI("com.ning.demosky ", "table1/#", TABLE1_ITEM); uriMatcher.addURI("com.ning.demosky ", "table2", TABLE2_DIR); uriMatcher.addURI("com.ning.demosky ", "table2/#", TABLE2_ITEM); } /** * 初始化内容提供器的时候调用。通常会在这里完成对数据库的创建和升级等操作, * 返回true 表示内容提供器初始化成功,返回false 则表示失败。注意,只有当存在 * ContentResolver 尝试访问我们程序中的数据时,内容提供器才会被初始化 */ @Override public boolean onCreate() { return false; } /** * 向内容提供器中添加一条数据。使用uri 参数来确定要添加到的表,待添加的数据 * 保存在values 参数中。添加完成后,返回一个用于表示这条新记录的URI。 */ @Nullable @Override public Uri insert(@NonNull Uri uri, ContentValues values) { return null; } /** * 从内容提供器中删除数据。使用uri 参数来确定删除哪一张表中的数据,selection * 和selectionArgs 参数用于约束删除哪些行,被删除的行数将作为返回值返回。 */ @Override public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) { return 0; } /** * 更新内容提供器中已有的数据。使用uri 参数来确定更新哪一张表中的数据,新数 * 据保存在values 参数中,selection 和selectionArgs 参数用于约束更新哪些行,受影响的 * 行数将作为返回值返回。 */ @Override public int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) { return 0; } /** * 从内容提供器中查询数据。使用uri 参数来确定查询哪张表,projection 参数用于确 * 定查询哪些列,selection 和selectionArgs 参数用于约束查询哪些行,sortOrder 参数用于 * 对结果进行排序,查询的结果存放在Cursor 对象中返回 */ @Nullable @Override public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {//通过上面 uriMatcher.addURI 中自定义的参数来确定所需要执行的操作switch (uriMatcher.match(uri)) {
case TABLE1_DIR:
// 查询table1表中的所有数据
break;
case TABLE1_ITEM:
// 查询table1表中的单条数据
break;
case TABLE2_DIR:
// 查询table2表中的所有数据
break;
case TABLE2_ITEM:
// 查询table2表中的单条数据
break;
default:
break;
}
return null; //暂时返回 null
}
/** * 根据传入的内容URI 来返回相应的MIME 类型。 */
@Nullable
@Override
public String getType(@NonNull Uri uri) {
switch (uriMatcher.match(uri)) {
case TABLE1_DIR:
return "vnd.android.cursor.dir/vnd.com.example.app.provider. table1";
case TABLE1_ITEM:
return "vnd.android.cursor.item/vnd.com.example.app.provider. table1";
case TABLE2_DIR:
return "vnd.android.cursor.dir/vnd.com.example.app.provider. table2";
case TABLE2_ITEM:
return "vnd.android.cursor.item/vnd.com.example.app.provider. table2";
default:
return null;
}
}
}
可以看到几乎每一个方法中都有 uri 参数,这个参数也正是调用 CotentResolver 的增删改查方法传递过来的,而现在,我们需要对传入的 uri 进行解析,从中分析出调用方法期望访问的表和数据。
上面说到,一个标准的内容 uri 写法是这样的,
ontent://com.example.app.provider/table1
这就表示调用方期望访问的 com.example.app.provider 这个应用程序的table1 表中的数据,除此之外,我们还可以在这个内容 uri 后面加上一个 id
ontent://com.example.app.provider/table1/1
这就表示调用方期望访问的是这个应用程序table1中id为 1 的数据
我们可以使用分配符的方式来匹配内容 uri
1. *:表示匹配任意长度的任意字符
2. #:表示匹配任意长度的数字
所以,一个能够匹配任意表的内容URI 格式就可以写成:
content://com.example.app.provider/*
而一个能够匹配table1 表中任意一行数据的内容URI 格式就可以写成:
content://com.example.app.provider/table1/#
接下来,我们在借助 UriMatcher 这个类就可以轻松的实现匹配内容 uri 的功能,UriMatcher 提供了一个 addURI 方法,这个方法接收三个参数,可以分别把权限,路径,和一个自定义的代码传进去。这样当调用 UriMatcher 的 match() 方法时,就可以将一个 uri 传入,返回值时某个能够匹配这个 uri 对象所对应的自定义的代码,利用这个代码就可以知道调用方法期望访问哪张表中的数据。
下面说说 getType () 方法,首先要说说 MOME类型 ,网上的解释是 :
MIME 类型就是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。
反正就是一种类型吧,getType()方法。它是所有的内容提供器都必
须提供的一个方法,用于获取Uri 对象所对应的MIME 类型。一个内容URI 所对应的MIME
字符串主要由三部分组分,Android 对这三个部分做了如下格式规定。
1. 必须以vnd 开头。
2. 如果内容URI 以路径结尾,则后接android.cursor.dir/,如果内容URI 以id 结尾,
则后接android.cursor.item/。
3. 最后接上vnd.<authority>.<path>。
所以,对于content://com.example.app.provider/table1 这个内容URI,它所对应的MIME
类型就可以写成:
vnd.android.cursor.dir/vnd.com.example.app.provider.table1
对于content://com.example.app.provider/table1/1 这个内容URI,它所对应的MIME 类型
就可以写成:
vnd.android.cursor.item/vnd. com.example.app.provider.table1
下面是我写的一个自定义的 ContentProvider 之实现了查询的方法
public class MyProvider extends ContentProvider { public static final int BOOK_DIR = 0; public static final int BOOK_ITEM = 1; public static final int USER_DIR = 2; public static final int USER_ITEM = 3; private static UriMatcher uriMatcher; public static final String AUTHORITY = "com.ning.demosky.provider"; private MyDataBaseHelper dbHelper; static { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(AUTHORITY, "book", BOOK_DIR); uriMatcher.addURI(AUTHORITY, "book/#", BOOK_ITEM); uriMatcher.addURI(AUTHORITY, "user", USER_DIR); uriMatcher.addURI(AUTHORITY, "user/#", USER_ITEM); } /** * 初始化内容提供器的时候调用。通常会在这里完成对数据库的创建和升级等操作, * 返回true 表示内容提供器初始化成功,返回false 则表示失败。注意,只有当存在 * ContentResolver 尝试访问我们程序中的数据时,内容提供器才会被初始化 */ @Override public boolean onCreate() { dbHelper = new MyDataBaseHelper(getContext(),"BookStore.db",null,2); return true; } /** * 向内容提供器中添加一条数据。使用uri 参数来确定要添加到的表,待添加的数据 * 保存在values 参数中。添加完成后,返回一个用于表示这条新记录的URI。 */ @Nullable @Override public Uri insert(@NonNull Uri uri, ContentValues values) { SQLiteDatabase db = dbHelper.getWritableDatabase(); switch (uriMatcher.match(uri)){ case BOOK_DIR: db.insert("book",null,values); break; } return null; } /** * 从内容提供器中删除数据。使用uri 参数来确定删除哪一张表中的数据,selection * 和selectionArgs 参数用于约束删除哪些行,被删除的行数将作为返回值返回。 */ @Override public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) { return 0; } /** * 更新内容提供器中已有的数据。使用uri 参数来确定更新哪一张表中的数据,新数 * 据保存在values 参数中,selection 和selectionArgs 参数用于约束更新哪些行,受影响的 * 行数将作为返回值返回。 */ @Override public int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) { return 0; } /** * 从内容提供器中查询数据。使用uri 参数来确定查询哪张表,projection 参数用于确 * 定查询哪些列,selection 和selectionArgs 参数用于约束查询哪些行,sortOrder 参数用于 * 对结果进行排序,查询的结果存放在Cursor 对象中返回 */ @Nullable @Override public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { Cursor cursor = null; SQLiteDatabase db = dbHelper.getWritableDatabase(); switch (uriMatcher.match(uri)) { case BOOK_DIR: // 查询book表中的所有数据 cursor = db.query("book",projection,selection,selectionArgs,null,null,sortOrder); break; case BOOK_ITEM: // 查询book表中的单条数据 String bookId = uri.getPathSegments().get(1); cursor = db.query("book",projection,"id = ?",new String[]{bookId},null,null,sortOrder); break; case USER_DIR: // 查询table2表中的所有数据 cursor = db.query("user",projection,selection,selectionArgs,null,null,sortOrder); break; case USER_ITEM: // 查询table2表中的单条数据 String userId = uri.getPathSegments().get(1); cursor = db.query("user",projection,"id = ?",new String[]{userId},null,null,sortOrder); break; default: break; } return cursor; } /** * 根据传入的内容URI 来返回相应的MIME 类型。 */ @Nullable @Override public String getType(@NonNull Uri uri) { switch (uriMatcher.match(uri)) { case BOOK_DIR: return "vnd.android.cursor.dir/vnd.com.example.app.provider.table1"; case BOOK_ITEM: return "vnd.android.cursor.item/vnd.com.example.app.provider.table1"; case USER_DIR: return "vnd.android.cursor.dir/vnd.com.example.app.provider.table2"; case USER_ITEM: return "vnd.android.cursor.item/vnd.com.example.app.provider.table2"; default: return null; } }}
本应用的 Activity 调用
public class ProviderActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_mvp); /** * "content://com.ning.demosky.provider/book" 完整的叫做内容 uri * com.ning.demosky.provider 这个叫做权限,一般是包名 + provider * 爱叫什么叫什么 ,aaaaa 也可以 * */ final Uri uri = Uri.parse("content://com.ning.demosky.provider/book"); Button btnAdd = (Button) findViewById(R.id.btn_add); Button btnDelete = (Button) findViewById(R.id.btn_delete); Button btnUp = (Button) findViewById(R.id.btn_up); Button btnQuery = (Button) findViewById(R.id.btn_query); assert btnQuery != null; btnQuery.setText("查询(长按查本地联系人)"); btnQuery.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { // 查询联系人数据 Cursor cursor = getContentResolver().query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null); assert 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)); Log.e("ProviderActivity","__displayName" + displayName); Log.e("ProviderActivity","__number" + number); } cursor.close(); return false; } }); btnQuery.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //Cursor cursor = ProviderActivity.this.getContentResolver().query(uri,null,"id = ?",new String[]{"1"},null,null); Cursor cursor = ProviderActivity.this.getContentResolver().query(uri,null,null,null,null,null); if (cursor != null){ while (cursor.moveToNext()){ String bookName = cursor.getString(cursor.getColumnIndex("name")); String bookAuthor = cursor.getString(cursor.getColumnIndex("author")); String bookPrice = cursor.getString(cursor.getColumnIndex("price")); String bookPages = cursor.getString(cursor.getColumnIndex("pages")); Log.e("ProviderActivity","bookName is " + bookName); Log.e("ProviderActivity","bookAuthor is " + bookAuthor); Log.e("ProviderActivity","bookPrice is " + bookPrice); Log.e("ProviderActivity","bookPages is " + bookPages); } cursor.close(); } } }); assert btnAdd != null; btnAdd.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ContentValues values = new ContentValues(); values.put("name","第二行"); values.put("author","母鸡啊"); values.put("price",10); values.put("pages",1000); getContentResolver().insert(uri,values); } }); assert btnDelete != null; btnDelete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { getContentResolver().delete(uri,"name = ?",new String[]{"第二行"}); } }); assert btnUp != null; btnUp.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ContentValues contentValues = new ContentValues(); contentValues.put("name","第三行"); getContentResolver().update(uri,contentValues,"price = ?" ,new String[]{"10"}); } }); }}
其他应用中的调用 别忘了 在我们的应用 manifest.xml 中进行注册 ,别忘了 在我们的应用 manifest.xml 中进行注册
,别忘了 在我们的应用 manifest.xml 中进行注册,别忘了 在我们的应用 manifest.xml 中进行注册
<provider android:name=".view.provider.MyProvider" android:authorities="com.ning.demosky.provider" android:exported="true" />
Uri uri = Uri.parse("content://com.ning.demosky.provider/book");Cursor cursor = MainActivity.this.getContentResolver().query(uri,null,null,null,null,null);if (cursor != null){ while (cursor.moveToNext()){ String bookName = cursor.getString(cursor.getColumnIndex("name")); String bookAuthor = cursor.getString(cursor.getColumnIndex("author")); String bookPrice = cursor.getString(cursor.getColumnIndex("price")); String bookPages = cursor.getString(cursor.getColumnIndex("pages")); Log.e("ProviderActivity","bookName is " + bookName); Log.e("ProviderActivity","bookAuthor is " + bookAuthor); Log.e("ProviderActivity","bookPrice is " + bookPrice); Log.e("ProviderActivity","bookPages is " + bookPages); } cursor.close();}
有点乱,有时间在整理吧
如有错误,欢迎指出,不胜感激
- ContentProvider自定义-笔记
- Android学习笔记----自定义ContentProvider
- Android学习笔记之ContentProvider自定义
- 安卓学习笔记之自定义ContentProvider
- 【Android基础笔记16】自定义ContentProvider
- 自定义ContentProvider
- 自定义ContentProvider
- 自定义ContentProvider
- 自定义ContentProvider
- 自定义contentprovider
- 自定义ContentProvider
- 自定义contentProvider
- 自定义ContentProvider
- 自定义ContentProvider
- 自定义ContentProvider
- 自定义ContentProvider
- 自定义ContentProvider
- 自定义ContentProvider
- fastqc的使用
- java学习日记_39:多态的引入、特点和弊端以及弊端解决方案
- Mac升级为macOS Sierra系统后项目报错
- web前端-HTML标题-004
- java thread status disgram
- ContentProvider自定义-笔记
- STM32 移植FreeModbus 详细过程
- Qt -- MainWindow实现文本新建/打开/保存/另存
- @responsebody 乱码问题
- 01、Android开发环境搭建和HelloWorld
- JQ修改css样式小结
- layout_gravity和gravity的区别
- git常用指令
- zedboard学习专题