//此系列博文是《第一行Android代码》的学习笔记,如有错漏,欢迎指正!

  我们继续在Database项目的基础上继续开发,通过内容提供器来给它加入外部访问接口。首先将 MyDatabaseHelper 中使用 Toast弹出创建数据库成功的提示去除掉,因为跨程序访问时我们不能直接使用 Toast。

一、添加一个 DatabaseProvider 类:

  1. public class DatabaseProvider extends ContentProvider {
  2. public static final int BOOK_DIR = 0;
  3. public static final int BOOK_ITEM = 1;
  4. public static final int CATEGORY_DIR = 2;
  5. public static final int CATEGORY_ITEM = 3;
  6. public static final String AUTHORITY = "com.mycompany.database.provider";
  7. private static UriMatcher uriMatcher;
  8. private MyDatabaseHelper dbHelper;
  9. static {
  10. uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
  11. uriMatcher.addURI(AUTHORITY, "book", BOOK_DIR);
  12. uriMatcher.addURI(AUTHORITY, "book/#", BOOK_ITEM);
  13. uriMatcher.addURI(AUTHORITY, "category", CATEGORY_DIR);
  14. uriMatcher.addURI(AUTHORITY, "category/#", CATEGORY_ITEM);
  15. }
  16. @Override
  17. public boolean onCreate() {
  18. dbHelper = new MyDatabaseHelper(getContext(), "BookStore.db", null, 2);
  19. return true;
  20. }
  21. @Override
  22. public Cursor query(Uri uri, String[] projection, String selection,
  23. String[] selectionArgs, String sortOrder) {
  24. // 查询数据
  25. SQLiteDatabase db = dbHelper.getReadableDatabase();
  26. Cursor cursor = null;
  27. switch (uriMatcher.match(uri)) {
  28. case BOOK_DIR:
  29. cursor = db.query("Book", projection, selection, selectionArgs,
  30. null, null, sortOrder);
  31. break;
  32. case BOOK_ITEM:
  33. String bookId = uri.getPathSegments().get(1);
  34. cursor = db.query("Book", projection, "id = ?", new String[]
  35. { bookId }, null, null, sortOrder);
  36. break;
  37. case CATEGORY_DIR:
  38. cursor = db.query("Category", projection, selection,
  39. selectionArgs, null, null, sortOrder);
  40. break;
  41. case CATEGORY_ITEM:
  42. String categoryId = uri.getPathSegments().get(1);
  43. cursor = db.query("Category", projection, "id = ?", new String[]
  44. { categoryId }, null, null, sortOrder);
  45. break;
  46. default:
  47. break;
  48. }
  49. return cursor;
  50. }
  51. @Override
  52. public Uri insert(Uri uri, ContentValues values) {
  53. // 添加数据
  54. SQLiteDatabase db = dbHelper.getWritableDatabase();
  55. Uri uriReturn = null;
  56. switch (uriMatcher.match(uri)) {
  57. case BOOK_DIR:
  58. case BOOK_ITEM:
  59. long newBookId = db.insert("Book", null, values);
  60. uriReturn = Uri.parse("content://" + AUTHORITY + "/book/" + newBookId);
  61. break;
  62. case CATEGORY_DIR:
  63. case CATEGORY_ITEM:
  64. long newCategoryId = db.insert("Category", null, values);
  65. uriReturn = Uri.parse("content://" + AUTHORITY + "/category/" +
  66. newCategoryId);
  67. break;
  68. default:
  69. break;
  70. }
  71. return uriReturn;
  72. }
  73. @Override
  74. public int update(Uri uri, ContentValues values, String selection,
  75. String[] selectionArgs) {
  76. // 更新数据
  77. SQLiteDatabase db = dbHelper.getWritableDatabase();
  78. int updatedRows = 0;
  79. switch (uriMatcher.match(uri)) {
  80. case BOOK_DIR:
  81. updatedRows = db.update("Book", values, selection, selectionArgs);
  82. break;
  83. case BOOK_ITEM:
  84. String bookId = uri.getPathSegments().get(1);
  85. updatedRows = db.update("Book", values, "id = ?", new String[]
  86. { bookId });
  87. break;
  88. case CATEGORY_DIR:
  89. updatedRows = db.update("Category", values, selection,
  90. selectionArgs);
  91. break;
  92. case CATEGORY_ITEM:
  93. String categoryId = uri.getPathSegments().get(1);
  94. updatedRows = db.update("Category", values, "id = ?", new String[]
  95. { categoryId });
  96. break;
  97. default:
  98. break;
  99. }
  100. return updatedRows;
  101. }
  102. @Override
  103. public int delete(Uri uri, String selection, String[] selectionArgs) {
  104. // 删除数据
  105. SQLiteDatabase db = dbHelper.getWritableDatabase();
  106. int deletedRows = 0;
  107. switch (uriMatcher.match(uri)) {
  108. case BOOK_DIR:
  109. deletedRows = db.delete("Book", selection, selectionArgs);
  110. break;
  111. case BOOK_ITEM:
  112. String bookId = uri.getPathSegments().get(1);
  113. deletedRows = db.delete("Book", "id = ?", new String[] { bookId });
  114. break;
  115. case CATEGORY_DIR:
  116. deletedRows = db.delete("Category", selection, selectionArgs);
  117. break;
  118. case CATEGORY_ITEM:
  119. String categoryId = uri.getPathSegments().get(1);
  120. deletedRows = db.delete("Category", "id = ?", new String[]
  121. { categoryId });
  122. break;
  123. default:
  124. break;
  125. }
  126. return deletedRows;
  127. }
  128. @Override
  129. public String getType(Uri uri) {
  130. switch (uriMatcher.match(uri)) {
  131. case BOOK_DIR:
  132. return "vnd.android.cursor.dir/vnd.com.mycompany.database.provider.book";
  133. case BOOK_ITEM:
  134. return "vnd.android.cursor.item/vnd.com.mycompany.database.provider.book";
  135. case CATEGORY_DIR:
  136. return "vnd.android.cursor.dir/vnd.com.mycompany.database.provider.category";
  137. case CATEGORY_ITEM:
  138. return "vnd.android.cursor.item/vnd.com.mycompany.database.provider.category";
  139. }
  140. return null;
  141. }
  142. }

  代码中我们主要重写了CRUD操作:

  1)query()方法:在这个方法中先获取到了 SQLiteDatabase 的实例,然后根据传入的 Uri参数判断出用户想要访问哪张表,再调用 SQLiteDatabase 的 query()进行查询,并将 Cursor 对象返回就好了。注意当访问单条数据的时候有一个细节,这里调用了 Uri 对象的getPathSegments()方法,它会将内容 URI权限之后的部分以“/”符号进行分割,并把分割后的结果放入到一个字符串列表中,那这个列表的第 0 个位置存放的就是路径,第 1个位置存放的就是 id 了。得到了 id 之后,再通过 selection 和 selectionArgs 参数进行约束,就实现了查询单条数据的功能。

  2)insert()方法: 同样先获取到了 SQLiteDatabase 的实例, 然后根据传入的 Uri参数判断出用户想要往哪张表里添加数据, 再调用 SQLiteDatabase 的 insert()方法进行添加。 注意 insert()方法要求返回一个能够表示这条新增数据的 URI, 所以我们还需要调用 Uri.parse()方法来将一个内容 URI解析成 Uri对象,当然这个内容 URI是以新增数据的 id 结尾的。

  3)update()方法:先获取SQLiteDatabase 的实例,然后根据传入的 Uri 参数判断出用户想要更新哪张表里的数据,再调用 SQLiteDatabase的 update()方法进行更新,最后将受影响的行数作为返回值返回。

  4)delete()方法:仍然是先获取到 SQLiteDatabase 的实例,然后根据传入的 Uri 参数判断出用户想要删除哪张表里的数据,再调用 SQLiteDatabase 的 delete()方法进行删除就好了,被删除的行数将作为返回值返回。

二、在AndroidManifest.xml文件中进行注册:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="com.mycompany.database" >
  4.  
  5. <application
  6. android:allowBackup="true"
  7. android:icon="@mipmap/ic_launcher"
  8. android:label="@string/app_name"
  9. android:supportsRtl="true"
  10. android:theme="@style/AppTheme" >
  11. <activity android:name=".MainActivity" >
  12. <intent-filter>
  13. <action android:name="android.intent.action.MAIN" />
  14.  
  15. <category android:name="android.intent.category.LAUNCHER" />
  16. </intent-filter>
  17. </activity>
  18. <provider
  19. android:name="com.mycompany.database.DatabaseProvider"
  20. android:authorities="com.mycompany.database.provider" >
  21. </provider>
  22. </application>
  23.  
  24. </manifest>

  这里我们使用了<provider>标签来对 DatabaseProvider 这个内容提供器进行注册,在 android:name 属性中指定了该类的全名,又在 android:authorities 属性中指定了该内容提供器的权限。现在 Database这个项目就已经拥有了跨程序共享数据的功能了。接着我们需要将 Database 程序从手机中删除掉,以防止上次中产生的遗留数据对我们造成干扰。然后运行一下项目,将Database程序重新安装在手机了。接着关闭掉Databaset 这个项目,并创建一个新项目 ProviderTest,我们就将通过这个程序去访问Database中的数据。

三、编写ProviderTest的布局文件:

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
  3. android:orientation="vertical"
  4. android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
  5. android:paddingRight="@dimen/activity_horizontal_margin"
  6. android:paddingTop="@dimen/activity_vertical_margin"
  7. android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
  8.  
  9. <Button
  10. android:id="@+id/add_data"
  11. android:layout_width="match_parent"
  12. android:layout_height="wrap_content"
  13. android:text="Add To Book" />
  14. <Button
  15. android:id="@+id/query_data"
  16. android:layout_width="match_parent"
  17. android:layout_height="wrap_content"
  18. android:text="Query From Book" />
  19. <Button
  20. android:id="@+id/update_data"
  21. android:layout_width="match_parent"
  22. android:layout_height="wrap_content"
  23. android:text="Update Book" />
  24. <Button
  25. android:id="@+id/delete_data"
  26. android:layout_width="match_parent"
  27. android:layout_height="wrap_content"
  28. android:text="Delete From Book" />
  29. </LinearLayout>

  布局文件比较简单,里面放置了四个按钮,分别用于添加、查询、修改和删除数据的。

四、修改ProviderTest主代码:

  1. public class MainActivity extends AppCompatActivity {
  2.  
  3. private String newId;
  4. @Override
  5. protected void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(R.layout.activity_main);
  8. Button addData = (Button) findViewById(R.id.add_data);
  9. addData.setOnClickListener(new View.OnClickListener() {
  10. @Override
  11. public void onClick(View v) {
  12. // 添加数据
  13. Uri uri = Uri.parse("content://com.mycompany.database.provider/book");
  14. ContentValues values = new ContentValues();
  15. values.put("name", "A Clash of Kings");
  16. values.put("author", "George Martin");
  17. values.put("pages", 1040);
  18. values.put("price", 22.85);
  19. Uri newUri = getContentResolver().insert(uri, values);
  20. newId = newUri.getPathSegments().get(1);
  21. }
  22. });
  23. Button queryData = (Button) findViewById(R.id.query_data);
  24. queryData.setOnClickListener(new View.OnClickListener() {
  25. @Override
  26. public void onClick(View v) {
  27. // 查询数据
  28. Uri uri = Uri.parse("content://com.mycompany.database.provider/book");
  29. Cursor cursor = getContentResolver().query(uri, null, null, null, null);
  30. if (cursor != null) {
  31. while (cursor.moveToNext()) {
  32. String name = cursor.getString(cursor.
  33. getColumnIndex("name"));
  34. String author = cursor.getString(cursor.
  35. getColumnIndex("author"));
  36. int pages = cursor.getInt(cursor.getColumnIndex
  37. ("pages"));
  38. double price = cursor.getDouble(cursor.
  39. getColumnIndex("price"));
  40. Log.d("MainActivity", "book name is " + name);
  41. Log.d("MainActivity", "book author is " + author);
  42. Log.d("MainActivity", "book pages is " + pages);
  43. Log.d("MainActivity", "book price is " + price);
  44. }
  45. cursor.close();
  46. }
  47. }
  48. });
  49. Button updateData = (Button) findViewById(R.id.update_data);
  50. updateData.setOnClickListener(new View.OnClickListener() {
  51. @Override
  52. public void onClick(View v) {
  53. // 更新数据
  54. Uri uri = Uri.parse("content://com.mycompany.database.provider/book/" + newId);
  55. ContentValues values = new ContentValues();
  56. values.put("name", "A Storm of Swords");
  57. values.put("pages", 1216);
  58. values.put("price", 24.05);
  59. getContentResolver().update(uri, values, null, null);
  60. }
  61. });
  62. Button deleteData = (Button) findViewById(R.id.delete_data);
  63. deleteData.setOnClickListener(new View.OnClickListener() {
  64. @Override
  65. public void onClick(View v) {
  66. // 删除数据
  67. Uri uri = Uri.parse("content://com.mycompany.database.provider/book/" + newId);
  68. getContentResolver().delete(uri, null, null);
  69. }
  70. });
  71. }
  72. }

  我们分别在这四个按钮的点击事件里面处理了增删改查的逻辑。

  1)Add To Book: 添加数据的时候,首先调用了 Uri.parse()方法将一个内容 URI解析成 Uri对象,然后把要添加的数据都存放到 ContentValues对象中,接着调用 ContentResolver 的 insert()方法执行添加操作就可以了。注意 insert()方法会返回一个 Uri 对象,这个对象中包含了新增数据的 id,我们通过getPathSegments()方法将这个 id 取出,稍后会用到它。
  2)Query From Book: 查询数据的时候,同样是调用了 Uri.parse()方法将一个内容 URI解析成 Uri对象,然后调用 ContentResolver 的 query()方法去查询数据,查询的结果当然还是存放在 Cursor对象中的。之后对 Cursor 进行遍历,从中取出查询结果,并一一打印出来。
  3)Update Book: 更新数据的时候,也是先将内容 URI 解析成 Uri 对象,然后把想要更新的数据存放到ContentValues对象中,再调用 ContentResolver 的 update()方法执行更新操作就可以了。注意这里我们为了不想让 Book 表中其他的行受到影响,在调用 Uri.parse()方法时,给内容 URI的尾部增加了一个 id,而这个 id 正是添加数据时所返回的。这就表示我们只希望更新刚刚添加的那条数据,Book 表中的其他行都不会受影响。
  4)Delete From Book: 删除数据的时候,也是使用同样的方法解析了一个以 id 结尾的内容 URI,然后调用ContentResolver 的 delete()方法执行删除操作就可以了。由于我们在内容 URI 里指定了一个id,因此只会删掉拥有相应 id 的那行数据,Book 表中的其他数据都不会受影响。

  程序运行效果如下:

  

  按下Add按钮后,再按下查询,在Android Monitor中可看到:

  1. 04-25 21:49:18.327 31285-31285/com.mycompany.database D/MainActivity: book name is A Clash of Kings
  2. 04-25 21:49:18.327 31285-31285/com.mycompany.database D/MainActivity: book author is George Martin
  3. 04-25 21:49:18.327 31285-31285/com.mycompany.database D/MainActivity: book pages is 1040
  4. 04-25 21:49:18.337 31285-31285/com.mycompany.database D/MainActivity: book price is 22.85

  按下Update后,再按下查询,可看到:

  1. 04-25 22:11:10.768 31285-31285/com.mycompany.database D/MainActivity: book name is A Storm of Swords
  2. 04-25 22:11:10.768 31285-31285/com.mycompany.database D/MainActivity: book author is George Martin
  3. 04-25 22:11:10.768 31285-31285/com.mycompany.database D/MainActivity: book pages is 1216
  4. 04-25 22:11:10.768 31285-31285/com.mycompany.database D/MainActivity: book price is 24.05

  当按下Delete后,再按下查询,此时已没有数据显示了。

  //End.

 

Android学习笔记(二十一)——实战:程序数据共享的更多相关文章

  1. python3.4学习笔记(二十一) python实现指定字符串补全空格、前面填充0的方法

    python3.4学习笔记(二十一) python实现指定字符串补全空格.前面填充0的方法 Python zfill()方法返回指定长度的字符串,原字符串右对齐,前面填充0.zfill()方法语法:s ...

  2. Android学习笔记(十一)——ListView的使用(下)

    //此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! ListView 这个控件比较复杂, 就是因为它有很多的细节可以优化,下面我们在试试提高它的运行效率:一.提高 ...

  3. (C/C++学习笔记) 二十一. 异常处理

    二十一. 异常处理 ● 异常的概念 程序的错误通常包括:语法错误.逻辑错误.运行异常. 语法错误指书写的程序语句不合乎编译器的语法规则,这种错误在编译.连接时由编译器指出. 逻辑错误是指程序能顺利运行 ...

  4. Android学习笔记二之初始Activity

    初识Activity,跟着教程学习敲了一遍这一章的内容,下面根据目录结构总结知识点: 一.活动是什么 上篇博文中我们提到了Android四大组件,其中有一个Activity,我们将之称为活动.活动是最 ...

  5. Java基础学习笔记二十一 多线程

    多线程介绍 学习多线程之前,我们先要了解几个关于多线程有关的概念.进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线 ...

  6. Android学习(二十一)OptionsMenu选项菜单

    一.OptionsMenu选项菜单 在应用程序中点击功能按钮会弹出选项菜单,点击可以实现具体功能. 二.实现思路: 1.创建选项菜单: onCreateOptionsMenu(); 2.设置菜单项可用 ...

  7. android 学习随笔二十一(内容提供者 )

    一.内容提供者* 应用的数据库是不允许其他应用访问的* 内容提供者的作用就是让别的应用访问到你的私有数据* 自定义内容提供者,继承ContentProvider类,重写增删改查方法,在方法中写增删改查 ...

  8. android学习笔记二

    ADT(Android Development Tools)安卓开发工具. android项目目录简介 ==> src==>源代码文件 res==>资源文件 AndroidManif ...

  9. Android学习笔记(十一)BroadcastReceiver动态注册、注销示例

    在上一篇博文中简单介绍了一下BroadcastReceiver的相关知识点,本篇举一个在代码中动态的注册.注销BroadcastReceiver的栗子. 1.首先创建一个MyReceiver并继承Br ...

  10. Pro Android学习笔记(十一):了解Intent(中)

    Intent的构成 Intent能够带有action,data(由URI表达),extra data(key/value map,键值对),指定的类名(成为component name).一个inte ...

随机推荐

  1. jquery selector 基础

    转自:http://www.cnblogs.com/zwl12549/archive/2008/08/09/1264163.html query的这套选择符是比较帅气的,借用了XPath2.0和CSS ...

  2. Java查找算法——二分查找

    import java.lang.reflect.Array; import java.nio.Buffer; import java.util.Arrays; import java.util.Ra ...

  3. UIAlertController 标题文字大小 颜色

    NSString *title = [NSString stringWithFormat:]; NSString *msg = @"\n把红包分享给微信好友,金额随机,可用于购买雪票和雪卡& ...

  4. MSSQL数据库索引的应用

    一.索引的概念 索引就是加快检索表中数据的方法.数据库的索引类似于书籍的索引.在书籍中,索引允许用户不必翻阅完整个书就能迅速地找到所需要的信息.在数据库中,索引也允许数据库程序迅速地找到表中的数据,而 ...

  5. Joomla![1.5-3.4.5]反序列化远程代码执行EXP(直接写shell)

    Usage:x.py http://xxx.com # coding=utf-8# author:KuuKi# Help: joomla 1.5-3.4.5 unserialize remote co ...

  6. 安装 SQL server 2008 R2

    操作系统:WIN7 问题: The Windows Installer Service could not be accessed. This can occur if the Windows Ins ...

  7. Yii 框架里数据库操作详解-[增加、查询、更新、删除的方法 'AR模式']

    public function getMinLimit () {        $sql = "...";        $result = yii::app()->db-& ...

  8. Java WebService入门实例

    Web Services是由企业发布的完成其特定商务需求的在线应用服务,其他公司或应用软件能够通过Internet来访问并使用这项在线服务. Web Service的关键技术和规则: 1.XML:描述 ...

  9. mysql存储过程之异常处理篇

    mysql存储过程也提供了对异常处理的功能:通过定义HANDLER来完成异常声明的实现 语法如下: DECLARE handler_type HANDLER FOR condition_value[, ...

  10. linux下生成core dump文件方法及设置

    linux下生成core dump文件方法及设置    from:http://www.cppblog.com/kongque/archive/2011/03/07/141262.html core ...