有时候我们自己的程序也需要向外接提供数据,那么就需要我们自己实现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

package cn.lixyz.mycontentprovider;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri; public class MyContentProvider extends ContentProvider { public static final int STUDENTS_DIR = 0;
public static final int STUDENTS_ITEM = 1;
public static final int CLASSES_DIR = 2;
public static final int CLASSES_ITEM = 3; private static UriMatcher uriMatcher; private MyDBHelper myDBHelper;
private SQLiteDatabase database; private static final String AUTHORITY = "cn.lixyz.mycontentprovider.cp"; static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI("cn.lixyz.mycontentprovider.cp", "students", STUDENTS_DIR);
uriMatcher.addURI("cn.lixyz.mycontentprovider.cp", "students/#", STUDENTS_ITEM);
uriMatcher.addURI("cn.lixyz.mycontentprovider.cp", "classes", CLASSES_DIR);
uriMatcher.addURI("cn.lixyz.mycontentprovider.cp", "classes/#", CLASSES_ITEM);
} @Override
public boolean onCreate() {
myDBHelper = new MyDBHelper(getContext(), "school.db", null, 1);
return true;
} @Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { database = myDBHelper.getReadableDatabase();
Cursor cursor = null;
switch (uriMatcher.match(uri)) {
case STUDENTS_DIR:
cursor = database.query("students", projection, selection, selectionArgs, null, null, sortOrder);
break;
case STUDENTS_ITEM:
String studentID = uri.getPathSegments().get(1);
cursor = database.query("students", projection, "_id=?", new String[] { studentID }, null, null, sortOrder);
break;
case CLASSES_DIR:
cursor = database.query("classes", projection, selection, selectionArgs, null, null, sortOrder);
break;
case CLASSES_ITEM:
String classID = uri.getPathSegments().get(1);
cursor = database.query("classes", projection, "_id=?", new String[] { classID }, null, null, sortOrder);
break;
} return cursor;
} @Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)) {
case STUDENTS_DIR:
return "vnd.android.cursor.dir/vnd.cn.lixyz.mycontentprovider.cp.students";
case STUDENTS_ITEM:
return "vnd.android.cursor.item/vnd.cn.lixyz.mycontentprovider.cp.students";
case CLASSES_DIR:
return "vnd.android.cursor.dir/vnd.cn.lixyz.mycontentprovider.cp.classes";
case CLASSES_ITEM:
return "vnd.android.cursor.item/vnd.cn.lixyz.mycontentprovider.cp.classes";
}
return null;
} @Override
public Uri insert(Uri uri, ContentValues values) { database = myDBHelper.getWritableDatabase();
Uri returnUri = null;
switch (uriMatcher.match(uri)) {
case STUDENTS_DIR:
case STUDENTS_ITEM:
long newStudent = database.insert("students", null, values);
returnUri = Uri.parse("content://" + AUTHORITY + "/students/" + newStudent);
break;
case CLASSES_DIR:
case CLASSES_ITEM:
long newClass = database.insert("classes", null, values);
returnUri = Uri.parse("content://" + AUTHORITY + "/classes/" + newClass);
break; }
return returnUri;
} @Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
} @Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
} class MyDBHelper extends SQLiteOpenHelper { private Context mContext; public MyDBHelper(Context context, String name, CursorFactory factory, int version) {
super(context, name, factory, version);
this.mContext = context; } @Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(
"create table if not exists students (_id integer primary key autoincrement,studentName text,studentAge integer,class text)");
db.execSQL("create table if not exists classes (_id integer primary key autoincrement,className text)");
} @Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub } } }

AndroidManifest.xml

<provider
android:name="MyContentProvider"
android:authorities="cn.lixyz.mycontentprovider.cp"
android:exported="true" >
</provider>

MyContentResolver

MainActivity.java

package cn.lixyz.mycontentresolver;

import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText; public class MainActivity extends Activity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); initView();
} public void clickButton(View view) {
switch (view.getId()) {
case R.id.bt_addclass:
addClass();
break;
case R.id.bt_addstudent:
addStudent();
break;
case R.id.searchclass:
searchClass();
break;
case R.id.searchstudent:
searchStrudent();
break;
}
} // 搜索学生方法
private void searchStrudent() {
Uri uri = Uri.parse("content://cn.lixyz.mycontentprovider.cp/students");
ContentResolver contentResolver = getContentResolver();
Cursor cursor = contentResolver.query(uri, null, null, null, null);
if (cursor != null) {
cursor.moveToFirst();
while (cursor.moveToNext()) {
String tudentName = cursor.getString(cursor.getColumnIndex("studentName"));
int studentAge = cursor.getInt(cursor.getColumnIndex("studentAge"));
String className = cursor.getString(cursor.getColumnIndex("class"));
Log.d("TTTT", "学生姓名:" + tudentName + ",年龄 : " + studentAge + ",所在班级:" + className);
}
}
} // 搜索班级方法
private void searchClass() {
Uri uri = Uri.parse("content://cn.lixyz.mycontentprovider.cp/classes");
ContentResolver contentResolver = getContentResolver();
Cursor cursor = contentResolver.query(uri, null, null, null, null);
if (cursor != null) {
cursor.moveToFirst();
while (cursor.moveToNext()) {
String className = cursor.getString(cursor.getColumnIndex("className"));
Log.d("TTTT", "班级:" + className);
}
}
} // 添加学生方法
private void addStudent() {
String studentName = et_studentname.getText().toString().trim();
String studentAge = et_studentage.getText().toString().trim();
String studentClass = et_studentclass.getText().toString().trim();
Uri uri = Uri.parse("content://cn.lixyz.mycontentprovider.cp/students");
ContentResolver contentResolver = getContentResolver();
ContentValues cv = new ContentValues();
cv.put("studentName", studentName);
cv.put("studentAge", studentAge);
cv.put("class", studentClass);
Uri returnUri = contentResolver.insert(uri, cv); Log.d("TTTT", "returnUri:" + returnUri.toString());
} // 添加班级方法
private void addClass() {
ContentResolver contentResolver = getContentResolver();
Uri uri = Uri.parse("content://cn.lixyz.mycontentprovider.cp/classes");
String className = et_addclass.getText().toString().trim();
ContentValues cv = new ContentValues();
cv.put("className", className);
contentResolver.insert(uri, cv);
} private EditText et_addclass, et_studentname, et_studentage, et_studentclass;
private Button bt_addclass, bt_addstudent, searchclass, searchstudent; private void initView() {
et_addclass = (EditText) findViewById(R.id.et_addclass);
et_studentname = (EditText) findViewById(R.id.et_studentname);
et_studentage = (EditText) findViewById(R.id.et_studentage);
et_studentclass = (EditText) findViewById(R.id.et_studentclass);
bt_addclass = (Button) findViewById(R.id.bt_addclass);
bt_addstudent = (Button) findViewById(R.id.bt_addstudent);
searchclass = (Button) findViewById(R.id.searchclass);
searchstudent = (Button) findViewById(R.id.searchstudent);
}
}

activity_main.xml

<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"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="cn.lixyz.mycontentresolver.MainActivity" > <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="添加班级" /> <EditText
android:id="@+id/et_addclass"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入班级名称" /> <Button
android:id="@+id/bt_addclass"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="clickButton"
android:text="添 加" /> <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="添加学生" /> <EditText
android:id="@+id/et_studentname"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入学生姓名" /> <EditText
android:id="@+id/et_studentage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入学生年龄" /> <EditText
android:id="@+id/et_studentclass"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入学生班级" /> <Button
android:id="@+id/bt_addstudent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="clickButton"
android:text="添 加" /> <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="搜索" /> <Button
android:id="@+id/searchclass"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="clickButton"
android:text="点我搜索班级" /> <Button
android:id="@+id/searchstudent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="clickButton"
android:text="点我搜索学生" /> </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. 【转载】 【TensorFlow】static_rnn 和dynamic_rnn的区别

    原文地址: https://blog.csdn.net/qq_20135597/article/details/88980975 ----------------------------------- ...

  2. boost中g++ 链接undefined reference to `boost::system::generic_category()问题

    编译错误如下: g++ -std=c++11  tcp_session.cpp tcp_server.cpp test.cpp -o test -pthread/tmp/ccv4rZkD.o: In ...

  3. 如何基于EasyDSS流媒体RTMP、HLS(m3u8)、HTTP-FLV、RTSP服务器体系的全套SDK完成各种场景下的视频应用需求

    需求背景 回顾EasyDSS的发展过程,基本上保持的是先局部后系统.先组件后平台的发展方式,一步一步夯实每一个细节功能点,从最基础.最兼容的音视频数据的拉流获取,到高效的.全兼容的数据推流,再到流媒体 ...

  4. postgrelsql 的 wm_concat : string_agg

    string_agg,array_agg 这两个函数的功能大同小异,只不过合并数据的类型不同 array_agg(expression) 把表达式变成一个数组 一般配合 array_to_string ...

  5. [LeetCode] 80. Remove Duplicates from Sorted Array II 有序数组中去除重复项 II

    Given a sorted array nums, remove the duplicates in-place such that duplicates appeared at most twic ...

  6. C# 编译器 和 反编译器,你要哪个(歪头)? 我全都要(捏拳)!

    前言 从 C# 6.0 开始,C# 编译器就从以前由 C++ 实现的 csc.exe 换成了用 C# 重新实现的开放式 API 式编译服务 Roslyn.这个编译器到现在已经替代了老式编译器,从前 W ...

  7. [06]Go设计模式:适配器模式(Adapter Pattern)

    目录 适配器模式 一.简介 二.代码 三.参考资料 适配器模式 一.简介 适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁.这种类型的设计模式属于结构型模式,它结合了两个独 ...

  8. SQL中EXPLAIN命令详解---(转)

    MySQL Explain详解   在日常工作中,我们会有时会开慢查询去记录一些执行时间比较久的SQL语句,找出这些SQL语句并不意味着完事了,些时我们常常用到explain这个命令来查看一个这些SQ ...

  9. Linux下Python安装PyMySQL成功,但无法导入的问题

    今天使用 Nginx 部署 Django应用.安装python库都显示成功安装. 尝试启动 uwsgi 服务,竟然报错 Traceback (most recent call last): File ...

  10. 【LEETCODE】40、1051. Height Checker

    package y2019.Algorithm.array; /** * @ProjectName: cutter-point * @Package: y2019.Algorithm.array * ...