Activity_ContentProvider
2016-06-08 14:14
399 查看
Activity_ContentProvider
内容提供器(Content Provider)在Android中存在的意义就是,我们写的程序可以访问别人分享的数据,我们也可以将自己的程序用的基础数据进行一份分享的功能。比如现在很多程序都可以访问电话簿、短信什么的,这个就说明电话簿、短信、媒体库等程序都实现了夸程序数据分享的功能。内容提供器(Content Provider)主要用于在不同的应用程序之间实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访问数据的安全性。使用内容提供器是Android实现跨程序共享数据的标准方式。
访问其他程序中的数据
当我们想要访问其他程序中的代码的时候,我们需要使用到Context类提供的一个方法getContentResolver()方法,使用该方法可以获取到一个ContentResolve的对象,有了这个对象,我们就可以实现增删改查了。ContentResolver中的增删改查方法都不接收表名参数的,而是使用一个Uri参数代替的,这个参数被称为内容Uri。(Uri参数让我想起来了当我们使用隐士意图调用系统的拨打电话界面事,我们使用intent.setData()方法中就是接收的一个Uri参数。)内容Uri是内容提供器中的数据 建立的唯一标识。它主要由两部分组成,第一部分:权限(authority)是用于对不同的应用程序做的区分的,一般为了避免冲突,都会采用程序包名的方式来进行命名。比如某个程序的包名是com.example.app,那么该程序对应的权限就可以命名为com.example.app.provider。第二部分:路径是用于对同一应用程序中不同的表做区分的,通常都会添加到权限的后面。比如某个程序的数据库里存在两张表,table1和table2,这是就可以将路径分别命名为/table1和/table2,然后把权限和路径进行组合,内容URL就变成了:com.example.aap.provider/table1和com.example.aap.provider/table2。不过,目前还很难辨认出这两个字符串就是两个内容URL,我们还需要在字符串的头部添加上协议声明。内容URL最标准的格式写法如下:
content://com.example.app.provider/table1
content://com.example.app.provider/table2
得到一个Uri对象:
Uri uri=Uri.parse("content://com.example.app.provider/table1");
读取系统联系人
启动程序,获取电话簿中的联系人的姓名和手机号,并以ListView的形式展现出来。1、activity_main.xml文件中的布局代码:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <ListView android:id="@+id/contacts_view" android:layout_width="match_parent" android:layout_height="match_parent"/> </RelativeLayout>
2、MainActivity中的逻辑代码:
public class MainActivity extends Activity { private ListView lvContacts; private ArrayAdapter<String> adapter; private List<String> data =new ArrayList<String>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); lvContacts=(ListView) findViewById(R.id.contacts_view); adapter=new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, data); lvContacts.setAdapter(adapter); //获取电话簿中联系人的数据 readContacts(); } private void readContacts() { Cursor cursor=null; //系统中电话簿的Uri Uri uri=ContactsContract.CommonDataKinds.Phone.CONTENT_URI; try { cursor=getContentResolver().query (uri, null, null, null, null); if (cursor!=null) { while(cursor.moveToNext()){ //获取联系人姓名 String name=cursor.getString(cursor.getColumnIndex (ContactsContract.CommonDataKinds.Phone. DISPLAY_NAME)); //获取联系人手机号 String number =cursor.getString(cursor.getColumnIndex (ContactsContract.CommonDataKinds. Phone.NUMBER)); //将获取到的数据添加到ArrayList中 data.add(name + "\n" + number); } } } catch (Exception e) { e.printStackTrace(); }finally{ if (cursor!=null) { cursor.close(); } } } }
3、读取手机中的联系人操作是一个敏感操作,所以需要权限:
<uses-permission android:name="android.permission.READ_CONTACTS"/>
作为无私的程序猿的我们来说,我们写的程序也可以给其他程序提供一些数据,那么我们应该如何将我们程序中的数据提供给其他程序呢?
创建自己的内容提供器
1、创建自己的内容提供器,肯定会继承ContentProvider这个类了,继承这个类,需要重写6个方法,下面就看看这6个方法分别是什么?并且他们各自的方法作用是什么?public class MyContentProvider extends ContentProvider { @Override public boolean onCreate() { //初始化内容提供器的时候调用。通常会在这里完成对数据库的创建和升级等操作, //返回true表示内容提供器初始化成功,返回false表示失败。只有当存在 //ContentResolver尝试访问我们程序中的数据时,内容提供器才会被初始化。 return false; } @Override public Uri insert(Uri uri, ContentValues values) { return null; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { //从内容提供器中删除数据。使用Uri参数来确定删除哪一张表中的数据,selection和 //selectionArgs参数用于约束删除那些行,被删除的行数将作为返回值返回。 return 0; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { //更新内容提供器中已有的数据。使用Uri参数来确定更新哪一张表中的数据,新数据保存在values参数中, //selection和selectionArgs参数用于约束更新那些行,受影响的行数将最为返回值返回。 return 0; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { //向内容提供器中查询数据。使用Uri参数来确定查询哪张表,projection参数 //用于确定查询那些列,selection和selectionArgs参数用于约束查询那些行 //sortOrder参数用于对结果进行排序,查询的结果存放在Cursor对象中返回。 return null; } @Override public String getType(Uri uri) { //根据传入的Uri返回相应的MINE类型。一个内容URI所对应的MIME字符串主要由三部分组分, //1、必须以vnd开头。2、如果内容URI以路径结尾,则后接android.cursor.dir, //如果内容URI以id结尾,则后接android.cursor.item/ //3、最后接上vnd.<authority>.<path> //例如:content://com.example.app.provider/table1所对应的MIME类型: //vnd.android.cursor.dir/vnd.com.example.app.provider.table1 //例如:content://com.example.app.provider/table/1所对应的MIME类型: //vnd.android.cursor.item/vnd.com.example.app.provider.table1 return null; } }
2、当调用方调用我们的程序中的数据时,我们需要对调用方传来的Uri进行一定的解析与了解。内容Uri的格式主要有2种方式:
content://com.example.app.provider/table1
content://com.example.app.provider/table/1
以路径结尾表示期望访问该表中所有的数据,以id结尾表示访问该表中拥有相应id的数据。我们可以使用通配符的方式来分别匹配这两种格式的内容Uri:
1、*:表示匹配任意长度的任意字符串
2、#:表示匹配任意长度的数字
content://com.example.app.provider/*
content://com.example.app.provider/table/#
3、当我们了解完Uri的格式后,我们可以使用UriMatcher这个类就可以轻松地实现匹配内容URI的功能。UriMatcher中提供了一个addURI()方法,该方法接收三个参数:分别是权限、路径、自定义码。当调用UriMatcher的match()方法时,就可以将一个Uri对象传入,返回值是某个能够匹配这个Uri对象所对应的自定义码,利用这个代码,我们就可以判断出调用方期望访问的是哪张表中的数据了。你在这个时候,你可能已经晕菜了,让我们看代码,来更好的理解这些东西吧。
实现跨程序数据共享
我为了方便起见,我就用我从前写的代码,如果你是第一次看这篇blog,你可以去我的那篇有关对SQLite数据库介绍中沾代码。1、我先将我从前的那个SQLiteTest项目卸载,以免造成影响。
2、我在SQLiteTest这个项目中新建一个 DatabaseProvider类继承ContentProvider。
3、在AndroidManifest.xml文件中注册该ContentProvider。
4、创建一个新的项目ProviderTest项目,用于访问SQLiteTest中DatabaseProvider提供的数据。
5、编写ProviderTest的布局文件。
6、编写ProviderTest中MainActivity中的代码。
第一步:
public class DatabaseProvider extends ContentProvider { // 访问book表中的所有数据 public static final int BOOK_DIR = 0; // 访问book表中的单条数据 public static final int BOOK_ITEM = 1; // 访问category表中的所有数据 public static final int CATEGORY_DIR = 2; // 访问category表中的单条数据 public static final int CATEGORY_ITEM = 3; public static final String AUTHORITY = "com.example.sqlitetest.provider"; private static UriMatcher uriMatcher; private MyDatabaseHelper dbHelper; static { //构造方法,参数通常使用UriMathcer.NO_MATCH,表示验证Uri时,如果不匹配,则返回该值 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 queryDatabase = dbHelper.getReadableDatabase(); Cursor cursor = null; switch (uriMatcher.match(uri)) { case BOOK_DIR: cursor = queryDatabase.query("book", projection, selection, selectionArgs, null, null, sortOrder); break; case BOOK_ITEM: String bookId = uri.getPathSegments().get(1); cursor = queryDatabase.query("book", projection, "id = ?", new String[] { bookId }, null, null, sortOrder); break; case CATEGORY_DIR: cursor = queryDatabase.query("category", projection, selection, selectionArgs, null, null, sortOrder); break; case CATEGORY_ITEM: String categoryId = uri.getPathSegments().get(1); cursor = queryDatabase.query("book", projection, "id = ?", new String[] { categoryId }, null, null, sortOrder); break; default: break; } return cursor; } @Override public Uri insert(Uri uri, ContentValues values) { // 添加数据 SQLiteDatabase insertDatabase = dbHelper.getReadableDatabase(); Uri uriReturn = null; switch (uriMatcher.match(uri)) { case BOOK_DIR: case BOOK_ITEM: long newBookId = insertDatabase.insert("book", null, values); uriReturn = Uri.parse("content://" + AUTHORITY + "/book/" + newBookId); break; case CATEGORY_DIR: case CATEGORY_ITEM: long newCategoryId = insertDatabase .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 updateDatabase = dbHelper.getReadableDatabase(); int upDatedRows = 0; switch (uriMatcher.match(uri)) { case BOOK_DIR: upDatedRows = updateDatabase.update("book", values, selection, selectionArgs); break; case BOOK_ITEM: String bookId = uri.getPathSegments().get(1); upDatedRows = updateDatabase.update("book", values, "id = ?", new String[] { bookId }); break; case CATEGORY_DIR: upDatedRows = updateDatabase.update("category", values, selection, selectionArgs); break; case CATEGORY_ITEM: String categoryId = uri.getPathSegments().get(1); upDatedRows = updateDatabase.update("book", values, "id = ?", new String[] { categoryId }); break; default: break; } return upDatedRows; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { SQLiteDatabase deleteDatabase = dbHelper.getReadableDatabase(); int deletedRows = 0; switch (uriMatcher.match(uri)) { case BOOK_DIR: deletedRows = deleteDatabase.delete("book", selection, selectionArgs); break; case BOOK_ITEM: String bookId = uri.getPathSegments().get(1); deletedRows = deleteDatabase.delete("book", "id = ?", new String[] { bookId }); break; case CATEGORY_DIR: deletedRows = deleteDatabase.delete("category", selection, selectionArgs); break; case CATEGORY_ITEM: String categoryId = uri.getPathSegments().get(1); deletedRows = deleteDatabase.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.sqlitetest.provider.book"; case BOOK_ITEM: return "vnd.android.cursor.item/vnd.com.example.sqlitetest.provider.book"; case CATEGORY_DIR: return "vnd.android.cursor.dir/vnd.com.example.sqlitetest.provider.category"; case CATEGORY_ITEM: return "vnd.android.cursor.dir/vnd.com.example.sqlitetest.provider.category"; default: break; } return null; } }
第二步:
<provider android:name="com.example.sqlitetest.DatabaseProvider" android:authorities="com.example.sqlitetest.provider" android:exported="true" android:enabled="true"> </provider>
第三步:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity" > <Button android:id="@+id/add_data" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Add To Book" /> <Button android:id="@+id/query_data" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Query from Book" /> <Button android:id="@+id/update_data" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="update Book" /> <Button android:id="@+id/delete_data" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Delete from Book" /> </LinearLayout>
第四步:
public class MainActivity extends Activity implements OnClickListener { private Button addBtn,queryBtn,updateBtn,deleteBtn; private String newId; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); addBtn=(Button) findViewById(R.id.add_data); queryBtn=(Button) findViewById(R.id.query_data); updateBtn=(Button) findViewById(R.id.update_data); deleteBtn=(Button) findViewById(R.id.delete_data); addBtn.setOnClickListener(this); queryBtn.setOnClickListener(this); updateBtn.setOnClickListener(this); deleteBtn.setOnClickListener(this); } @Override public void onClick(View view) { switch (view.getId()) { //添加数据 case R.id.add_data: Uri uriAdd=Uri.parse("content://com.example.sqlitetest.provider/book"); ContentValues insertValues =new ContentValues(); insertValues.put("name", "A Clash Kings"); insertValues.put("author", "GoogleDeveloper"); insertValues.put("pages", 1040); insertValues.put("price", 22.85); Uri newUri=getContentResolver().insert(uriAdd, insertValues); newId =newUri.getPathSegments().get(1); Log.i("providertest", "newId :"+newId); break; //查询数据 case R.id.query_data: Uri uriQuery =Uri.parse("content://com.example.sqlitetest.provider/book"); Cursor cursor=getContentResolver().query(uriQuery, null, null, null, null); if (cursor!=null) { while(cursor.moveToNext()){ String name =cursor.getString(cursor.getColumnIndexOrThrow("name")); String author=cursor.getString(cursor.getColumnIndex("author")); int pages =cursor.getInt(cursor.getColumnIndex("pages")); double price =cursor.getDouble(cursor.getColumnIndex("price")); Log.i("providertest", "name :"+name); Log.i("providertest", "author :"+author); Log.i("providertest", "pages :"+pages); Log.i("providertest", "price :"+price); } cursor.close(); } break; //更新数据 case R.id.update_data: Uri uriUpdate=Uri.parse("content://com.example.sqlitetest.provider/book/" + newId); ContentValues updateValues=new ContentValues(); updateValues.put("name", "A Storm of Swords"); updateValues.put("pages", 1216); updateValues.put("price", "24.58"); int updateRows=getContentResolver().update(uriUpdate, updateValues, null, null); Log.i("providertest", "update lineNumber :"+updateRows); break; //删除数据 case R.id.delete_data: Uri uriDelete =Uri.parse("content://com.example.sqlitetest.provider/book/" + newId); int deleteRow=getContentResolver().delete(uriDelete, null, null); Log.i("providertest", "delete lineNumber :"+deleteRow); break; default: break; } } }
经过上面四步的完成,我们已经能够成功的访问SQLiteTest提供的DatabaseProvider这个类中的方法。为了证明成功还是那句话有图有真相:
1、当我点击Add To Book 按钮的时候,我将SQLiteTest项目下的BookStore.db数据库导出,看图:
并且看一下我打印的Log日志:
06-08 10:51:54.672: I/providertest(5681): newId :1
2、当我点击Query From Book 按钮的时候,让我们来看一下log日志吧:
06-08 10:53:22.936: I/providertest(5681): name :A Clash Kings 06-08 10:53:22.936: I/providertest(5681): author :GoogleDeveloper 06-08 10:53:22.936: I/providertest(5681): pages :1040 06-08 10:53:22.936: I/providertest(5681): price :22.85
3、当我点击Update Book 按钮的时候,让我们来看一下Log日志吧:
06-08 10:54:27.814: I/providertest(5681): update lineNumber :1 06-08 10:55:26.523: I/providertest(5681): name :A Storm of Swords 06-08 10:55:26.523: I/providertest(5681): author :GoogleDeveloper 06-08 10:55:26.523: I/providertest(5681): pages :1216 06-08 10:55:26.523: I/providertest(5681): price :24.58
4、当我点击Delete from Book 按钮的时候,让我们来看一下log日志吧:
06-08 10:55:48.323: I/providertest(5681): delete lineNumber :1
小笔记
ContentProvider是ANDROID系统的核心组件之一,用于向其它应用程序提供自身的数据的访问方式(可以包含增删改查),与其它系统组件相同,ContentProvider需要实现与系统的ContentProvider的继承关系,并且需要在AndroidManifest.xml文件中注册,注册时,除了android:name属性外,还必须配置android:authority属性,在偏高版本的ANDROID系统中,还需要配置android:exproted和android:enabled属性,均需要设置为true其中,android:authority属性是该ContentProvider的“网址”,在全设备中应该是唯一的,其值也是其它的访问者对数据进行访问时必要的参数之一
注意:
1) 尽管ContentProivder中定义了增删改查的抽象方法,但是开发者可以选择性的具体实现,对于不希望提供数据共享的方法,可以不添加实际代码,或者直接抛出异常表示不支持
2) 尽管ContentProvider中实现增删改查的方法与SQLiteDatabase中的方法非常相似,但并不代表内容提供者的数据必须来源于SQLite数据库
URI
在使用ContentProvider时,需要使用到Uri类型的数据,该数据本质是一个字符串,格式为:content://authority/path通过Uri Uri.parse(String uriString)可以将String转换为Uri格式的数据
通过Uri ContentUris.withAppendedId(Uri uri, long id)方法可以为已知的Uri添加id
通过long ContentUris.parseId(Uri uri)可以提取Uri中的id
一个Uri的实例调用getpathSegments()方法:
–getPathSegments得到uri的path部分,并拆分,去掉”/”,取到第一个元素(从第0个开始)。
比如这个项目中的:
content://com.example.sqlitetest.provider/book/1这个Uri的Path部分就是 /book/1,去掉”/”,就是 book/1,
getPathSegments.get(0) 得到的就是 book
getPathSegments.get(1)得到的就是 1
相关文章推荐
- win2008中设置计划任务执行PHP文件的方法
- 判断101-200之间有多少个素数,并输出所有素数。
- PHPCMS V9 全站 Sitemaps生成实现代码[服务器端版]
- AT SELECTION-SCREEN OUTPUT 用法实例
- PHP多种循环方法及示例
- PHP生成随机密码的方法
- PHP安装PDO
- 前两天使用PHP的strtotime的时候遇到了2038的问题
- php的命名空间层级与目录层级是一致的吗?
- PHP安装xcache
- Laravel如何优雅的使用Swoole
- php5.3中ZendGuardLoader与wincache冲突问题的解决方法
- PHP下编码转换函数mb_convert_encoding与iconv的使用说明
- PHP语言优势
- 事故记录:php-cgi进程过多导致系统资源耗尽
- php中的curl使用入门教程和常见用法实例
- 古典问题:有一对兔子,从出生后第三个月都能生一对兔子,小兔子长到第三个月后每个月又生一对兔子... 假如兔子不死,问每个月兔子的总数是多少个?
- php静态
- yii 简单依赖注入
- PHP_SQL根据当前坐标查询5公里以内的信息