Android第一行代码学习笔记五----内容提供器
2016-09-20 20:51
405 查看
1、简介
内容提供器主要用于在不同的应用程序直接实现数据共享。内容提供器一般有两种,一种是使用现有的内容提供器另一种是创建自己的内容提供器给我们程序的数据提供外部访问接口。
2、访问其他程序的数据
要访问内容提供器中共享的数据,就一定要借助ContentResolve 类,可以通过 Context 中的 getContentResolver()方法获取到该类的实例。ContentResolver提供insert()、update()、delete()、query()操作数据。不同于 SQLiteDatabase,ContentResolver 中的方法使用一个 Uri 参数代替表名参数,成为内容URL。内容 URI由两部分组成,权限(authority)和路径(path) 。权限用于对应用程序做区分,路径用于对表做区分。内容URL标准格式写法如下:content://com.example.app.provider/table1 content://com.example.app.provider/table2在得到了内容 URI 字符串之后,我们还需要调用 Uri.parse()方法将它解析成 Uri 对象才可以作为参数传入。示例如下:
Uri uri = Uri.parse("content://com.example.app.provider/table1")
1、query()
查询代码:Cursor cursor = getContentResolver().query( uri, projection, selection, selectionArgs, sortOrder);
遍历返回的Cursor对象。
if (cursor != null) { while (cursor.moveToNext()) { String column1 = cursor.getString(cursor.getColumnIndex("column1")); int column2 = cursor.getInt(cursor.getColumnIndex("column2")); } cursor.close(); }
2、insert()
ContentValues values = new ContentValues(); values.put("column1", "text"); values.put("column2", 1); getContentResolver().insert(uri, values);
3、update()
ContentValues values = new ContentValues(); values.put("column1", ""); getContentResolver().update(uri, values, "column1 = ? and column2 = ?", new String[] {"text", "1"});
4、delete()
getContentResolver().delete(uri, "column2 = ?", new String[] { "1" });
3、创建自己的内容提供器
我们可以通过新建一个类去继承 ContentProvider 的方式来创建一个自己的内容提供器。ContentProvider 类中有六个抽象方法,我们需要重写这六个方法。新建 MyProvider 继承自 ContentProvider,示例代码如下:public class MyProvider extends ContentProvider { @Override public boolean onCreate() { return false; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { return null; } @Override public Uri insert(Uri uri, ContentValues values) { return null; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { return 0; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { return 0; } @Override public String getType(Uri uri) { return null; } }其中CRUD操作跟前面一样,onCreate()在初始化内容提供器的时候调用。通常会在这里完成对数据库的创建和升级等操作,返回 true 表示内容提供器初始化成功,返回 false 则表示失败。getType()是根据传入的内容 URI 来返回相应的 MIME 类型。
内容 URI 的格式主要有以下两种,以路径结尾就表示期望访问该表中所有的数据,以 id 结尾就表示期望访问该表中拥有相应 id 的数据
content://com.example.app.provider/table1 content://com.example.app.provider/table1/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 对象所对应的自定义代码,利用这个代码,我们就可以判断出调用方期望访问的是哪张表中的数据了。
query()
示例代码如下,其他CRUD可参考。public class MyProvider extends ContentProvider { public static final int TABLE1_DIR = 0; public static final int TABLE1_ITEM = 1; public static final int TABLE2_DIR = 2; public static final int TABLE2_ITEM = 3; private static UriMatcher uriMatcher; static { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI("com.example.app.provider", "table1", TABLE1_DIR); uriMatcher.addURI("com.example.app.provider ", "table1/#", TABLE1_ITEM); uriMatcher.addURI("com.example.app.provider ", "table2", TABLE2_ITEM); uriMatcher.addURI("com.example.app.provider ", "table2/#", TABLE2_ITEM); } …… @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { 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; } …… } …… }
getType()
它是所有的内容提供器都必须提供的一个方法,用于获取 Uri 对象所对应的 MIME 类型。一个内容 URI 所对应的 MIME字符串主要由三部分组分,格式如下: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
getType()示例代码如下:
public class MyProvider extends ContentProvider { …… @Override public String getType(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: break; } return null; } }
跨程序数据共享示例
DatabaseProvider 类
public class DatabaseProvider extends ContentProvider { public static final int BOOK_DIR = 0; public static final int BOOK_ITEM = 1; public static final int CATEGORY_DIR = 2; public static final int CATEGORY_ITEM = 3; public static final String AUTHORITY = "com.example.databasetest.provider"; private static UriMatcher uriMatcher; 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, "category", CATEGORY_DIR); uriMatcher.addURI(AUTHORITY, "category/#", CATEGORY_ITEM); } @Override public boolean onCreate() { dbHelper = new MyDatabaseHelper(getContext(), "BookStore.db", null, 2); return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // 查询数据 SQLiteDatabase db = dbHelper.getReadableDatabase(); Cursor cursor = null; switch (uriMatcher.match(uri)) { case BOOK_DIR: cursor = db.query("Book", projection, selection, selectionArgs, null, null, sortOrder); break; case BOOK_ITEM: String bookId = uri.getPathSegments().get(1); cursor = db.query("Book", projection, "id = ?", new String[] { bookId }, null, null, sortOrder); break; case CATEGORY_DIR: cursor = db.query("Category", projection, selection, selectionArgs, null, null, sortOrder); break; case CATEGORY_ITEM: String categoryId = uri.getPathSegments().get(1); cursor = db.query("Category", projection, "id = ?", new String[] { categoryId }, null, null, sortOrder); break; default: break; } return cursor; } @Override public Uri insert(Uri uri, ContentValues values) { // 添加数据 SQLiteDatabase db = dbHelper.getWritableDatabase(); Uri uriReturn = null; switch (uriMatcher.match(uri)) { case BOOK_DIR: case BOOK_ITEM: long newBookId = db.insert("Book", null, values); uriReturn = Uri.parse("content://" + AUTHORITY + "/book/" + newBookId); break; case CATEGORY_DIR: case CATEGORY_ITEM: long newCategoryId = db.insert("Category", null, values); uriReturn = Uri.parse("content://" + AUTHORITY + "/category/" + newCategoryId); break; default: break; } return uriReturn; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { // 更新数据 SQLiteDatabase db = dbHelper.getWritableDatabase(); int updatedRows = 0; switch (uriMatcher.match(uri)) { case BOOK_DIR: updatedRows = db.update("Book", values, selection, selectionArgs); break; case BOOK_ITEM: String bookId = uri.getPathSegments().get(1); updatedRows = db.update("Book", values, "id = ?", new String[] { bookId }); break; case CATEGORY_DIR: updatedRows = db.update("Category", values, selection, selectionArgs); break; case CATEGORY_ITEM: String categoryId = uri.getPathSegments().get(1); updatedRows = db.update("Category", values, "id = ?", new String[] { categoryId }); break; default: break; } return updatedRows; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { // 删除数据 SQLiteDatabase db = dbHelper.getWritableDatabase(); int deletedRows = 0; switch (uriMatcher.match(uri)) { case BOOK_DIR: deletedRows = db.delete("Book", selection, selectionArgs); break; case BOOK_ITEM: String bookId = uri.getPathSegments().get(1); deletedRows = db.delete("Book", "id = ?", new String[] { bookId }); break; case CATEGORY_DIR: deletedRows = db.delete("Category", selection, selectionArgs); break; case CATEGORY_ITEM: String categoryId = uri.getPathSegments().get(1); deletedRows = db.delete("Category", "id = ?", new String[] { categoryId }); break; default: break; } return deletedRows; } @Override public String getType(Uri uri) { switch (uriMatcher.match(uri)) { case BOOK_DIR: return "vnd.android.cursor.dir/vnd.com.example.databasetest. provider.book"; case BOOK_ITEM: return "vnd.android.cursor.item/vnd.com.example.databasetest. provider.book"; case CATEGORY_DIR: return "vnd.android.cursor.dir/vnd.com.example.databasetest. provider.category"; case CATEGORY_ITEM: return "vnd.android.cursor.item/vnd.com.example.databasetest. provider.category"; } return null; } }注意:当访问单条数据的时候调用了Uri对象的getPathSegments()方法,它会将内容 URI 权限之后的部分以“/”符号进行分割,第 0 个位置存放的就是路径,第 1 个位置存放的就是 id 。得到了 id 之后,再通过 selection 和 selectionArgs 参数进行约束,就实现了查询单条数据的功能。insert()方法要求返回一个能够表示这条新增数据的 URI,所以我们还需要调用 Uri.parse()方法来将一个内容 URI 解析成 Uri 对象,当然这个内容
URI 是以新增数据的 id 结尾的。update()方法受影响的行数将作为返回值返回,delete()方法被删除的行数将作为返回值返回。
内容提供器的注册
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.databasetest" android:versionCode="1" android:versionName="1.0" > …… <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > …… <provider android:name="com.example.databasetest.DatabaseProvider" android:authorities="com.example.databasetest.provider" > </provider> </application> </manifest>
示例内容提供器的使用
public class MainActivity extends Activity { private String newId; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button addData = (Button) findViewById(R.id.add_data); addData.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // 添加数据 Uri uri = Uri.parse("content://com.example.databasetest. provider/book"); ContentValues values = new ContentValues(); values.put("name", "A Clash of Kings"); values.put("author", "George Martin"); values.put("pages", 1040); values.put("price", 22.85); Uri newUri = getContentResolver().insert(uri, values); newId = newUri.getPathSegments().get(1); } }); Button queryData = (Button) findViewById(R.id.query_data); queryData.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // 查询数据 Uri uri = Uri.parse("content://com.example.databasetest. provider/book"); Cursor cursor = getContentResolver().query(uri, null, null, null, null); if (cursor != null) { while (cursor.moveToNext()) { String name = cursor.getString(cursor. getColumnIndex("name")); String author = cursor.getString(cursor. getColumnIndex("author")); int pages = cursor.getInt(cursor.getColumnIndex ("pages"));
相关文章推荐
- 第一行代码学习笔记,第七章 内容提供者
- android第一行代码-9.内容提供器
- android 学习笔记 创建自己的内容提供器
- 第二行代码学习笔记——第一章:开始启程——你的第一行Android代码
- Android第一行代码学习笔记四----数据存储
- 第一行代码-Android 学习笔记(一)
- Android第一行代码学习笔记
- Android第一行代码学习笔记六----手机多媒体
- Android 第一行代码(第二版)学习笔记
- 《第一行代码--Android》学习笔记--第一章:开始起航:思路
- Android系统相关组件解析(Android第一行代码学习笔记2)
- android 学习笔记 内容提供器ContentResolver
- 第一行代码学习笔记1——Android简介
- 第二行代码学习笔记——第一章:开始启程——你的第一行Android代码
- Android第一行代码学习笔记三----广播
- Android第一行代码学习笔记八----网络技术
- Android-第一行代码学习笔记——activity
- 第二行代码学习笔记——第七章:跨程序共享数据——探究内容提供器
- [Android][第一行代码][第 7 章 内容提供器]
- Androidc学习笔记五之四大组件之内容提供器ContentProvider