有时候我们自己的程序也需要向外接提供数据,那么就需要我们自己实现ContentProvider。

自己实现ContentProvider的话需要新建一个类去继承ContentProvider,然后重写类中的的6个抽象方法。

onCreate():初始化内容提供器时候会调用,通常会在这里完成对数据库的创建和升级等操作,返回true表示内容提供器初始化成功,返回false则表示失败,注意,只有当存在ContentResolver尝试访问我们程序中的数据时,内容提供其才会被初始化

query():从内容提供其中查询数据,使用uri参数来确定查询哪张表,projection参数用于确定查询哪些列,selection和selectionArgs参数用于约束查询哪些行,sortOrder参数用于对结果进行排序,查询结果存放在Cursor对象中返回。

insert():向内容提供器中添加一条数据,使用uri参数来确定要添加到的表,待添加的数据保存在values参数中,添加完成后,返回一个用于表示这条新记录的URI。

update():更新内容提供器中已有的数据,使用uri参数来确定更新哪一张表中的数据,新数据保存在values参数中,selection和selectionArgs参数用于约束更新哪些列,受影响的行数将作为返回值返回。

delete():从内容提供其中删除数据,使用uri参数来确定删除哪一张表中的数据,selection和selectionArgs参数用于约束删除哪些行,被删除的行数将作为返回值返回。

getType():根据传入的内容URI来返回相应的MIME类型。

可以看到,几乎每一个方法都会带有Uri这个参数,这个参数也正是调用ContentResolver的增删改查方法时传递过来的,而现在,我们需要对传入的Uri参数进行解析,从中分析出调用方期待访问的表和数据。

一般的标准的内容URI写法是这样的

content://com.example.app.provider/table1

这就表示调用方期待访问的是com.example.app这个应用的table1表中的数据。除此之外,我们还可以在这个内容URI的后面加上一个id,例如

content://com.example.app.provider/table1/1

这就表示调用方期待访问的是com.example.app这个应用的table1表中的id为1的数据。

内容URI的格式主要就只有以上两种,以路径结尾就表示期望访问该表中所有的数据,以id结尾就表示期望访问该表中拥有相应的id的数据,我们可以使用通配符的方式来分别匹配这两种格式的内容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对象所对应的自定义代码,利用这个代码,我们就可以判断出调用方期待访问的是哪张表中的数据了。

除此之外,还有一个getTypt()方法,它是所有的内容提供其都必须提供的一个方法,用于获取Uri对象所对应的MIME类型,一个内容URI所对应的MIME字符串主要由三部分组成,Android对这三个部分做了如下格式规定:

1.必须以vnd开头

2.如果内容URI以路径结尾,则后面接android.cursor.dir/,如果内容URI以id结尾,则后接android.cursor.item/。

3.最后接上vnd.<authority>.<path>

简单示例:

MyContentProvider

MyContentProvider.java

  1. package cn.lixyz.mycontentprovider;
  2.  
  3. import android.content.ContentProvider;
  4. import android.content.ContentValues;
  5. import android.content.Context;
  6. import android.content.UriMatcher;
  7. import android.database.Cursor;
  8. import android.database.sqlite.SQLiteDatabase;
  9. import android.database.sqlite.SQLiteDatabase.CursorFactory;
  10. import android.database.sqlite.SQLiteOpenHelper;
  11. import android.net.Uri;
  12.  
  13. public class MyContentProvider extends ContentProvider {
  14.  
  15. public static final int STUDENTS_DIR = 0;
  16. public static final int STUDENTS_ITEM = 1;
  17. public static final int CLASSES_DIR = 2;
  18. public static final int CLASSES_ITEM = 3;
  19.  
  20. private static UriMatcher uriMatcher;
  21.  
  22. private MyDBHelper myDBHelper;
  23. private SQLiteDatabase database;
  24.  
  25. private static final String AUTHORITY = "cn.lixyz.mycontentprovider.cp";
  26.  
  27. static {
  28. uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
  29. uriMatcher.addURI("cn.lixyz.mycontentprovider.cp", "students", STUDENTS_DIR);
  30. uriMatcher.addURI("cn.lixyz.mycontentprovider.cp", "students/#", STUDENTS_ITEM);
  31. uriMatcher.addURI("cn.lixyz.mycontentprovider.cp", "classes", CLASSES_DIR);
  32. uriMatcher.addURI("cn.lixyz.mycontentprovider.cp", "classes/#", CLASSES_ITEM);
  33. }
  34.  
  35. @Override
  36. public boolean onCreate() {
  37. myDBHelper = new MyDBHelper(getContext(), "school.db", null, 1);
  38. return true;
  39. }
  40.  
  41. @Override
  42. public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
  43.  
  44. database = myDBHelper.getReadableDatabase();
  45. Cursor cursor = null;
  46. switch (uriMatcher.match(uri)) {
  47. case STUDENTS_DIR:
  48. cursor = database.query("students", projection, selection, selectionArgs, null, null, sortOrder);
  49. break;
  50. case STUDENTS_ITEM:
  51. String studentID = uri.getPathSegments().get(1);
  52. cursor = database.query("students", projection, "_id=?", new String[] { studentID }, null, null, sortOrder);
  53. break;
  54. case CLASSES_DIR:
  55. cursor = database.query("classes", projection, selection, selectionArgs, null, null, sortOrder);
  56. break;
  57. case CLASSES_ITEM:
  58. String classID = uri.getPathSegments().get(1);
  59. cursor = database.query("classes", projection, "_id=?", new String[] { classID }, null, null, sortOrder);
  60. break;
  61. }
  62.  
  63. return cursor;
  64. }
  65.  
  66. @Override
  67. public String getType(Uri uri) {
  68. switch (uriMatcher.match(uri)) {
  69. case STUDENTS_DIR:
  70. return "vnd.android.cursor.dir/vnd.cn.lixyz.mycontentprovider.cp.students";
  71. case STUDENTS_ITEM:
  72. return "vnd.android.cursor.item/vnd.cn.lixyz.mycontentprovider.cp.students";
  73. case CLASSES_DIR:
  74. return "vnd.android.cursor.dir/vnd.cn.lixyz.mycontentprovider.cp.classes";
  75. case CLASSES_ITEM:
  76. return "vnd.android.cursor.item/vnd.cn.lixyz.mycontentprovider.cp.classes";
  77. }
  78. return null;
  79. }
  80.  
  81. @Override
  82. public Uri insert(Uri uri, ContentValues values) {
  83.  
  84. database = myDBHelper.getWritableDatabase();
  85. Uri returnUri = null;
  86. switch (uriMatcher.match(uri)) {
  87. case STUDENTS_DIR:
  88. case STUDENTS_ITEM:
  89. long newStudent = database.insert("students", null, values);
  90. returnUri = Uri.parse("content://" + AUTHORITY + "/students/" + newStudent);
  91. break;
  92. case CLASSES_DIR:
  93. case CLASSES_ITEM:
  94. long newClass = database.insert("classes", null, values);
  95. returnUri = Uri.parse("content://" + AUTHORITY + "/classes/" + newClass);
  96. break;
  97.  
  98. }
  99. return returnUri;
  100. }
  101.  
  102. @Override
  103. public int delete(Uri uri, String selection, String[] selectionArgs) {
  104. // TODO Auto-generated method stub
  105. return 0;
  106. }
  107.  
  108. @Override
  109. public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
  110. // TODO Auto-generated method stub
  111. return 0;
  112. }
  113.  
  114. class MyDBHelper extends SQLiteOpenHelper {
  115.  
  116. private Context mContext;
  117.  
  118. public MyDBHelper(Context context, String name, CursorFactory factory, int version) {
  119. super(context, name, factory, version);
  120. this.mContext = context;
  121.  
  122. }
  123.  
  124. @Override
  125. public void onCreate(SQLiteDatabase db) {
  126. db.execSQL(
  127. "create table if not exists students (_id integer primary key autoincrement,studentName text,studentAge integer,class text)");
  128. db.execSQL("create table if not exists classes (_id integer primary key autoincrement,className text)");
  129. }
  130.  
  131. @Override
  132. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  133. // TODO Auto-generated method stub
  134.  
  135. }
  136.  
  137. }
  138.  
  139. }

AndroidManifest.xml

  1. <provider
  2. android:name="MyContentProvider"
  3. android:authorities="cn.lixyz.mycontentprovider.cp"
  4. android:exported="true" >
  5. </provider>

MyContentResolver

MainActivity.java

  1. package cn.lixyz.mycontentresolver;
  2.  
  3. import android.app.Activity;
  4. import android.content.ContentResolver;
  5. import android.content.ContentValues;
  6. import android.database.Cursor;
  7. import android.net.Uri;
  8. import android.os.Bundle;
  9. import android.util.Log;
  10. import android.view.View;
  11. import android.widget.Button;
  12. import android.widget.EditText;
  13.  
  14. public class MainActivity extends Activity {
  15.  
  16. @Override
  17. protected void onCreate(Bundle savedInstanceState) {
  18. super.onCreate(savedInstanceState);
  19. setContentView(R.layout.activity_main);
  20.  
  21. initView();
  22. }
  23.  
  24. public void clickButton(View view) {
  25. switch (view.getId()) {
  26. case R.id.bt_addclass:
  27. addClass();
  28. break;
  29. case R.id.bt_addstudent:
  30. addStudent();
  31. break;
  32. case R.id.searchclass:
  33. searchClass();
  34. break;
  35. case R.id.searchstudent:
  36. searchStrudent();
  37. break;
  38. }
  39. }
  40.  
  41. // 搜索学生方法
  42. private void searchStrudent() {
  43. Uri uri = Uri.parse("content://cn.lixyz.mycontentprovider.cp/students");
  44. ContentResolver contentResolver = getContentResolver();
  45. Cursor cursor = contentResolver.query(uri, null, null, null, null);
  46. if (cursor != null) {
  47. cursor.moveToFirst();
  48. while (cursor.moveToNext()) {
  49. String tudentName = cursor.getString(cursor.getColumnIndex("studentName"));
  50. int studentAge = cursor.getInt(cursor.getColumnIndex("studentAge"));
  51. String className = cursor.getString(cursor.getColumnIndex("class"));
  52. Log.d("TTTT", "学生姓名:" + tudentName + ",年龄 : " + studentAge + ",所在班级:" + className);
  53. }
  54. }
  55. }
  56.  
  57. // 搜索班级方法
  58. private void searchClass() {
  59. Uri uri = Uri.parse("content://cn.lixyz.mycontentprovider.cp/classes");
  60. ContentResolver contentResolver = getContentResolver();
  61. Cursor cursor = contentResolver.query(uri, null, null, null, null);
  62. if (cursor != null) {
  63. cursor.moveToFirst();
  64. while (cursor.moveToNext()) {
  65. String className = cursor.getString(cursor.getColumnIndex("className"));
  66. Log.d("TTTT", "班级:" + className);
  67. }
  68. }
  69. }
  70.  
  71. // 添加学生方法
  72. private void addStudent() {
  73. String studentName = et_studentname.getText().toString().trim();
  74. String studentAge = et_studentage.getText().toString().trim();
  75. String studentClass = et_studentclass.getText().toString().trim();
  76. Uri uri = Uri.parse("content://cn.lixyz.mycontentprovider.cp/students");
  77. ContentResolver contentResolver = getContentResolver();
  78. ContentValues cv = new ContentValues();
  79. cv.put("studentName", studentName);
  80. cv.put("studentAge", studentAge);
  81. cv.put("class", studentClass);
  82. Uri returnUri = contentResolver.insert(uri, cv);
  83.  
  84. Log.d("TTTT", "returnUri:" + returnUri.toString());
  85. }
  86.  
  87. // 添加班级方法
  88. private void addClass() {
  89. ContentResolver contentResolver = getContentResolver();
  90. Uri uri = Uri.parse("content://cn.lixyz.mycontentprovider.cp/classes");
  91. String className = et_addclass.getText().toString().trim();
  92. ContentValues cv = new ContentValues();
  93. cv.put("className", className);
  94. contentResolver.insert(uri, cv);
  95. }
  96.  
  97. private EditText et_addclass, et_studentname, et_studentage, et_studentclass;
  98. private Button bt_addclass, bt_addstudent, searchclass, searchstudent;
  99.  
  100. private void initView() {
  101. et_addclass = (EditText) findViewById(R.id.et_addclass);
  102. et_studentname = (EditText) findViewById(R.id.et_studentname);
  103. et_studentage = (EditText) findViewById(R.id.et_studentage);
  104. et_studentclass = (EditText) findViewById(R.id.et_studentclass);
  105. bt_addclass = (Button) findViewById(R.id.bt_addclass);
  106. bt_addstudent = (Button) findViewById(R.id.bt_addstudent);
  107. searchclass = (Button) findViewById(R.id.searchclass);
  108. searchstudent = (Button) findViewById(R.id.searchstudent);
  109. }
  110. }

activity_main.xml

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:orientation="vertical"
  6. android:paddingBottom="@dimen/activity_vertical_margin"
  7. android:paddingLeft="@dimen/activity_horizontal_margin"
  8. android:paddingRight="@dimen/activity_horizontal_margin"
  9. android:paddingTop="@dimen/activity_vertical_margin"
  10. tools:context="cn.lixyz.mycontentresolver.MainActivity" >
  11.  
  12. <TextView
  13. android:layout_width="match_parent"
  14. android:layout_height="wrap_content"
  15. android:text="添加班级" />
  16.  
  17. <EditText
  18. android:id="@+id/et_addclass"
  19. android:layout_width="match_parent"
  20. android:layout_height="wrap_content"
  21. android:hint="输入班级名称" />
  22.  
  23. <Button
  24. android:id="@+id/bt_addclass"
  25. android:layout_width="match_parent"
  26. android:layout_height="wrap_content"
  27. android:onClick="clickButton"
  28. android:text="添 加" />
  29.  
  30. <TextView
  31. android:layout_width="match_parent"
  32. android:layout_height="wrap_content"
  33. android:text="添加学生" />
  34.  
  35. <EditText
  36. android:id="@+id/et_studentname"
  37. android:layout_width="match_parent"
  38. android:layout_height="wrap_content"
  39. android:hint="输入学生姓名" />
  40.  
  41. <EditText
  42. android:id="@+id/et_studentage"
  43. android:layout_width="match_parent"
  44. android:layout_height="wrap_content"
  45. android:hint="输入学生年龄" />
  46.  
  47. <EditText
  48. android:id="@+id/et_studentclass"
  49. android:layout_width="match_parent"
  50. android:layout_height="wrap_content"
  51. android:hint="输入学生班级" />
  52.  
  53. <Button
  54. android:id="@+id/bt_addstudent"
  55. android:layout_width="match_parent"
  56. android:layout_height="wrap_content"
  57. android:onClick="clickButton"
  58. android:text="添 加" />
  59.  
  60. <TextView
  61. android:layout_width="match_parent"
  62. android:layout_height="wrap_content"
  63. android:text="搜索" />
  64.  
  65. <Button
  66. android:id="@+id/searchclass"
  67. android:layout_width="match_parent"
  68. android:layout_height="wrap_content"
  69. android:onClick="clickButton"
  70. android:text="点我搜索班级" />
  71.  
  72. <Button
  73. android:id="@+id/searchstudent"
  74. android:layout_width="match_parent"
  75. android:layout_height="wrap_content"
  76. android:onClick="clickButton"
  77. android:text="点我搜索学生" />
  78.  
  79. </LinearLayout>

  这样,就可以在ContentResolver应用中,对ContentProvider应用的数据库进行insert和query操作了。

Android笔记(五十六) Android四大组件之一——ContentProvider,实现自己的ContentProvider的更多相关文章

  1. Android笔记(七十六) 点菜DEMO

    一个朋友让看一下他的代码,一个点菜的功能,他和我一样,初学者,代码比我的都混乱,也是醉了,干脆想着自己写个demo给他看,原本想着听简单,半个小时应该就可以搞定,真正写的时候,画了3h+,汗颜... ...

  2. Android笔记(十六) 简易计算器

    实现功能: 简单计算器 布局及美化 采用LinearLayout嵌套LinearLayout实现布局. 要求 1. 按钮所有文字居于右下角 2. 按钮为白色,点击变成橘色 3. 显示屏文字居右显示并且 ...

  3. Android笔记二十四.Android基于回调的事件处理机制

        假设说事件监听机制是一种托付式的事件处理,那么回调机制则与之相反,对于基于回调的事件处理模型来说,事件源和事件监听器是统一的,或者说事件监听器全然消失了,当用户在GUI控件上激发某个事件时,控 ...

  4. Android笔记(十) Android中的布局——表格布局

    TableLayout运行我们使用表格的方式来排列控件,它的本质依然是线性布局.表格布局采用行.列的形式来管理控件,TableLayout并不需要明确的声明包含多少行多少列,而是通过添加TableRo ...

  5. Android之旅十六 android中各种资源的使用

    android中各种资源的使用: 在android开发中,各种资源的合理使用应该在各自的xml中进行定义,以便反复使用; 字符串资源:strings.xml,xml中引用:@string/XXX,ja ...

  6. 论文阅读笔记五十六:(ExtremeNet)Bottom-up Object Detection by Grouping Extreme and Center Points(CVPR2019)

    论文原址:https://arxiv.org/abs/1901.08043 github: https://github.com/xingyizhou/ExtremeNet 摘要 本文利用一个关键点检 ...

  7. Android实训案例(六)——四大组件之一BroadcastReceiver的基本使用,拨号,短信,SD卡,开机,应用安装卸载监听

    Android实训案例(六)--四大组件之一BroadcastReceiver的基本使用,拨号,短信,SD卡,开机,应用安装卸载监听 Android中四大组件的使用时重中之重,我这个阶段也不奢望能把他 ...

  8. Nodejs学习笔记(十六)--- Pomelo介绍&入门

    目录 前言&介绍 安装Pomelo 创建项目并启动 创建项目 项目结构说明 启动 测试连接 聊天服务器 新建gate和chat服务器 配置master.json 配置servers.json ...

  9. Nodejs学习笔记(十六)—Pomelo介绍&入门

    前言&介绍 Pomelo:一个快速.可扩展.Node.js分布式游戏服务器框架 从三四年前接触Node.js开始就接触到了Pomelo,从Pomelo最初的版本到现在,总的来说网易出品还算不错 ...

  10. 微信小程序把玩(十六)form组件

    原文:微信小程序把玩(十六)form组件 form表单组件 是提交form内的所有选中属性的值,注意每个form表单内的组件都必须有name属性指定否则提交不上去,button中的type两个subm ...

随机推荐

  1. 不规则的Ifc构件顶点提取方法

    BIM模型中有很多不规则的构件,在IFC中这些不规则的构件一般用顶点的形式表示,顶点坐标提取路径:  IfcObject->IfcProductDefinitionShape->IfcSh ...

  2. sysfile20191122

    ass_s_ccp_ft:-108; ass_s_ccp_all:-108; ass_tag_ft:-105; ass_tag_all:-105; rept_port:9000; Q_value:0. ...

  3. SDN实验---Ryu的安装

    一:Ryu是主流SDN开源控制器之一 (一)推文(摘录自) https://ryu.readthedocs.io/en/latest/ https://www.sdnlab.com/1785.html ...

  4. 用Vue2.0实现简单的分页及跳转

    用Vue2.0实现简单的分页及跳转 2018年07月26日 20:29:51 Freya_yyy 阅读数 3369    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog ...

  5. Jenkins - 构建流水线

    1 - 以流水线的方式进行构建 关联多任务形成流水线的两种方法 通过定义项目的后续项目,将项目直接关联起来按顺序执行, 另外定义一个用于统筹管理的项目,定义各项目之间的关联性,然后以流水线的方式执行 ...

  6. Tomcat启动原理/使用tomcat的应用是如何从tomcat的main函数开始运行的

    从main方法开始打断点,逐步调试,了解程序运行过程 全局唯一的public static void main(String[] args)main Springboot* 内置tomcat,开发的时 ...

  7. 转载:Python Web开发最难懂的WSGI协议,到底包含哪些内容?

    原文:PSC推出的第二篇文章-<Python Web开发最难懂的WSGI协议,到底包含哪些内容?>-2017.9.27 我想大部分Python开发者最先接触到的方向是WEB方向(因为总是有 ...

  8. AutoResetEvent 学生考试,老师阅卷,学生等待考试结果

    class Program { static void Main(string[] args) { )); t.Start(); Console.WriteLine("老师等待提交试卷&qu ...

  9. IDEA修改Servlet的代码生成模板

    file--->settings,打开settings面板

  10. C++的派生类构造函数是否要带上基类构造函数

    //public:Student(int s_age):People(s_age) //C++的派生类构造函数后面是否带上基类构造函数,取决于基类构造函数是否需要传入参数,如果要参数,就一定带上:不需 ...