一、概述

ContentProvider(内容提供者)管理对结构化数据集的访问,它们封装数据,并提供用于定义数据安全性的机制。其他应用,通过Context的ContentResolver对象 作为客户端 与ContentProvider进行通信,访问操作数据。

Android本身的ContentProvider,我们比较常见的有,视频、音频、图像、个人信息等数据。

下面通过简单例子进行说明(数据存储形式为SQLite数据库).

二、基础知识

1.Uri

通用资源标识符(Universal Resource Identifer),标明了一个数据操作的地址。

content://<authority>/<path>:指向表的路径

content://<authority>/<path>/<id>:指向单行的路径

包括整个提供程序的符号名称(其授权authority)和一个指向表或文件的名称(路径path),可选 ID 部分指向表中的单个行。

授权:ContentProvider都有单一的授权,避免与其他的ContentProvider冲突,所以要唯一。建议如果Android 软件包名称为 com.example.<appname>,则应为提供程序提供 com.example.<appname>.provider 授权。

路径:指向数据库的表或文件,如果你有数据库table1,则Uri:  授权/table1

Uri ID:ContentPorvider会将该 ID 值与表的 _ID 列进行匹配,并对匹配的行执行请求的访问。

UriMatcher:它会通过addURI将授权和路径 映射到整型上,可以在后续通过switch对特定一个和多个Uri进行操作。match()方法会将Uri返回整型。

注:这里讲到的Uri只是关于ContentProvider使用到的相关部分,Uri远不止这一点。简单扩展一点:

关于文件存储部分,会涉及到Uri的scheme是file的,如:

file:///storage/emulated/0/beam/image_to_share.jpg

Uri(android.net.Uri),URI(java.net.URI):Uri可以看作andorid对java的URI的扩展,对于URI的组成结构可以查看API。

Uri的语法及组成,下面几个是一步步的划分:

[scheme:]scheme-specific-part[#fragment]  //基本组成
[scheme:][//authority][path][?query][#fragment] //进一步划分

依据:Uri构建和解析要符合RFC 2396

2.SQLiteDatabase

SQLiteDatabase是Android提供的管理SQLite database的对象,提供了数据库的基本的操作(增删改查)方法以及执行SQL语句。数据库名 在某应用里需要唯一,不需要在整个系统中唯一。

创建的数据库在/data/data/<package_name>/databases/xxx.db。 我们可以通过adb shell进入手机,通过sqlite3调试查看调试数据库里的数据。

sqlite3的基本操作:进入到对应应用的数据库文件夹后

(1)sqlite3  xxx.db:  键入这个命令后 你就能执行SQLite的各种命令了

(2). tables: 显示数据库中的表名,注意前面的.(点)啊

(3)知道表名后就能 通过SQL命令 操作对应的表了,如select * from TABLE1;(不要忘了分号)

(4) . quit  和 . exit:退出sqlite,  注意前面的.(点)啊

三、基本用法

下面通过具体例子 简单说明下 ContentProvider的简单应用。

1.通过provider在清单文件AndroidManifest.xml中 配置:

        <provider
android:authorities="com.flx.testapp.provider"
android:name=".MyContentProvider"
android:exported="true"/>

这里的授权名称 在后续都是很重要的。

2.通过继承SQLiteOpenHelper 创建数据库。MyDatabaseHelper.java

package com.flx.testcontentprovider;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper; public class MyDatabaseHelper extends SQLiteOpenHelper {
//_id, name, age final private static String DBNAME = "test.db";
final public static String TABLE1 = "table1";
final private static String SQL_CREATE_TAB = "CREATE TABLE TABLE1 " +
"(_ID INTEGER PRIMARY KEY, NAME VARCHAR(20), AGE INT(10))"; public MyDatabaseHelper(Context context) {
super(context, DBNAME, null, 1);
} @Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE_TAB);
} @Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    //TODO
}
}

从代码中可以看到,创建的数据库名叫test.db, 里面只有一个表table1. 表里面3个字段(id,name,age)。很简单的数据库。

3.清单里配置的ContentProvider的名字是MyContentProvider。代码如下:

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.util.Log; public class MyContentProvider extends ContentProvider {
private MyDatabaseHelper mMyDatabaseHelper;
final private static UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
final private static int TABLE1_CODE = 1; static {
mUriMatcher.addURI("com.flx.testapp.provider", "table1", TABLE1_CODE);
} @Override
public boolean onCreate() {
mMyDatabaseHelper = new MyDatabaseHelper(getContext());
return true;
} @Override
public Cursor query(Uri uri,String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteDatabase sqLiteDatabase = mMyDatabaseHelper.getWritableDatabase();
Cursor cursor = null;
if (mUriMatcher.match(uri) == TABLE1_CODE) {
cursor = sqLiteDatabase.query(MyDatabaseHelper.TABLE1, projection, selection,selectionArgs,null,null,sortOrder);
Log.d("flx_provider", "MyContentProvider->query()");
} else {
Log.d("flx_provider", "MyContentProvider->query() the patch is not match");
}
return cursor;
} @Override
public String getType(Uri uri) {
return null;
} @Override
public Uri insert( Uri uri, ContentValues values) {
SQLiteDatabase sqLiteDatabase = mMyDatabaseHelper.getWritableDatabase();
if(mUriMatcher.match(uri) == TABLE1_CODE) {
long rowNum = sqLiteDatabase.insert(MyDatabaseHelper.TABLE1, null, values);
Log.d("flx_provider", "MyContentProvider->insert() rowNum="+rowNum);
} else {
Log.d("flx_provider", "MyContentProvider->insert() the patch is not match");
}
return null;
} @Override
public int delete( Uri uri, String selection, String[] selectionArgs) {
return 0;
} @Override
public int update( Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
}

onCreate()中,通过创建MyDatabaseHelper对象 连接数据库,执行了创建数据的命令,数据库被创建了。

自定义的ContentPorvider要重写增(insert)删(delete)改(update)查(query)等方法,上述代码只实现了insert()和query(),依次两个为说明。

上述代码创建了UriMatcher, 定义了Uri规则(前面有简单介绍):addURI中是授权(清单文件中配置时设置的一致),路径(这里是表名),映射的整型。这里映射的整型 在重写的操作数据库方法中 操作哪个数据 是一个重要判断。

final private static UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
final private static int TABLE1_CODE = 1; static {
mUriMatcher.addURI("com.flx.testapp.provider", "table1", TABLE1_CODE);
}

  

4.上述部分,基本ContentProvider的内容都已经完成了。下面是具体的activity中如何去调用的(这里在同一个应用中调用的)

布局文件activity_main.xml,只有两个按钮,增 查

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" > <Button android:id="@+id/add_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="AddData"/> <Button android:id="@+id/query_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="QueryData" /> </LinearLayout>

MainActivity.java,具体操作待用代码

import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button; public class MainActivity extends AppCompatActivity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); Button addButton = findViewById(R.id.add_btn);
addButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("flx_provider", "ManiActivity->oncreate() addButton click");
Uri uri = Uri.parse("content://com.flx.testapp.provider/table1");
String names[] = {"AA", "BB", "CC"};
int ages[] = {18, 19, 20};
for (int i = 0;i < names.length;i++) {
ContentValues values = new ContentValues();
values.put("name", names[i]);
values.put("age", ages[i]);
getContentResolver().insert(uri, values);
}
}
}); Button queryBtn = findViewById(R.id.query_btn);
queryBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("flx_provider", "ManiActivity->oncreate() queryBtn click");
Uri uri = Uri.parse("content://com.flx.testapp.provider/table1");
Cursor cursor = getContentResolver().query(uri, null, "name=?",
new String[]{"AA"},null);
if (cursor != null && cursor.getCount() > 0) {
cursor.moveToFirst();
do {
Log.d("flx_provider", "ManiActivity->oncreate() query results:" + cursor.getString(0)
+ " " + cursor.getString(1) + " " + cursor.getString(2));
} while (cursor.moveToNext());
cursor.close();
}
}
});
}
}

两个按钮的功能很简单,增加按钮:插入3组数据了。 查询按钮:查询name为AA的数据并返回打印log了。

下面来看看真个内部数据库情况和log流程。

(1)当应用编译安装后,通过adb shell进入手机中看到,对应应用下数据库文件还不存在。

(2)首先我们点击查询(QueryData)按钮,这是数据库还不存在。点击后,log如下

2019-08-03 08:44:44.336 28711-28711/com.flx.testcontentprovider D/flx_provider: ManiActivity->oncreate() queryBtn click
2019-08-03 08:44:44.428 28711-28711/com.flx.testcontentprovider D/flx_provider: MyContentProvider->query()

  

从log看,执行到了MyContentProvider->query(),数据库创建被执行。我们进入数据库,看下数据库中是什么情况。

从下面看到此时的数据库里没有数据。

(3)点击增加(AddData)按钮。

2019-08-03 08:50:50.295 28711-28711/com.flx.testcontentprovider D/flx_provider: ManiActivity->oncreate() addButton click
2019-08-03 08:50:50.305 28711-28711/com.flx.testcontentprovider D/flx_provider: MyContentProvider->insert() rowNum=1
2019-08-03 08:50:50.312 28711-28711/com.flx.testcontentprovider D/flx_provider: MyContentProvider->insert() rowNum=2
2019-08-03 08:50:50.317 28711-28711/com.flx.testcontentprovider D/flx_provider: MyContentProvider->insert() rowNum=3

  通过log看,增加了3条数据,通过sqlite3查看如下,3条数据是插入成功的。

(4)点击查询(QueryData)按钮,查询OK的。

2019-08-03 09:01:57.995 28711-28711/com.flx.testcontentprovider D/flx_provider: ManiActivity->oncreate() queryBtn click
2019-08-03 09:01:58.001 28711-28711/com.flx.testcontentprovider D/flx_provider: MyContentProvider->query()
2019-08-03 09:01:58.005 28711-28711/com.flx.testcontentprovider D/flx_provider: ManiActivity->oncreate() query results:1 AA 18

  

(5)在点击依次增加按钮

2019-08-03 09:02:55.125 28711-28711/com.flx.testcontentprovider D/flx_provider: ManiActivity->oncreate() addButton click
2019-08-03 09:02:55.132 28711-28711/com.flx.testcontentprovider D/flx_provider: MyContentProvider->insert() rowNum=4
2019-08-03 09:02:55.138 28711-28711/com.flx.testcontentprovider D/flx_provider: MyContentProvider->insert() rowNum=5
2019-08-03 09:02:55.147 28711-28711/com.flx.testcontentprovider D/flx_provider: MyContentProvider->insert() rowNum=6

  

(6)点击查询,查询的数据是OK的。

2019-08-03 09:03:37.950 28711-28711/com.flx.testcontentprovider D/flx_provider: ManiActivity->oncreate() queryBtn click
2019-08-03 09:03:37.960 28711-28711/com.flx.testcontentprovider D/flx_provider: MyContentProvider->query()
2019-08-03 09:03:37.965 28711-28711/com.flx.testcontentprovider D/flx_provider: ManiActivity->oncreate() query results:1 AA 18
2019-08-03 09:03:37.965 28711-28711/com.flx.testcontentprovider D/flx_provider: ManiActivity->oncreate() query results:4 AA 18

  

Android_四大组件之ContentProvider的更多相关文章

  1. 四大组件之ContentProvider

    前言 ContentProvider作为Android的四大组件之一,是属于需要掌握的基础知识,可能在我们的应用中,对于Activity和Service这两个组件用的很常见,了解的也很多,但是对Con ...

  2. Android实训案例(五)——四大组件之一ContentProvider的使用,通讯录的实现以及ListView的优化

    Android实训案例(五)--四大组件之一ContentProvider的使用,通讯录的实现 Android四大组件是啥这里就不用多说了,看图吧,他们之间通过intent通讯 我们后续也会一一的为大 ...

  3. Android 四大组件之" ContentProvider "

    前言 ContentProvider作为Android的四大组件之一,是属于需要掌握的基础知识,可能在我们的应用中,对于Activity和Service这两个组件用的很常见,了解的也很多,但是对Con ...

  4. Android四大组件之——ContentProvider(一)

    Android四大组件之--ContentProvider(一) 本人邮箱:JohnTsai.Work@gmail.com,欢迎交流讨论. 欢迎转载,转载请注明网址:http://www.cnblog ...

  5. 【Android开发日记】之入门篇(九)——Android四大组件之ContentProvider

    数据源组件ContentProvider与其他组件不同,数据源组件并不包括特定的功能逻辑.它只是负责为应用提供数据访问的接口.Android内置的许多数据都是使用ContentProvider形式,供 ...

  6. 初学android:四大组件之contentprovider

    一.ContentProvider的概念ContentProvider:为存储和获取数据提供统一的接口.可以在不同的应用程序之间共享数据.Android已经为常见的一些数据提供了默认的ContentP ...

  7. Android四大组件之contentProvider

    Activity,Service,broadcast and Contentprovider android 4 大组件. ContentProvider:使用: public class Image ...

  8. Android_四大组件之Service

    一.概述 Service是四大组件之一.它主要用于在后台执行耗时的逻辑,即使用户切换到其他应用甚至退出应用,它也能继续在后台运行. 下面主要介绍了service的两种形式启动和绑定 ,并通过简单例子说 ...

  9. Android 四大组件之四(ContentProvider)

    ContentProvider调用关系: ContentProvider(数据提供者)是应用程序之间共享数据的一种接口机制,是一种更为高级的数据共享方法. ContentProvider可以指定需要共 ...

随机推荐

  1. Java采用反射技术创建对象后对目标类的成员变量和成员方法进行访问

    实现: package com.ljy; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * * @Class ...

  2. 布局问题杂(html和css)

    \(一.删除线可以用一对strike标签括起来\) <p><strike>删除线可以用一对strike标签括起来</strike></p> \(\col ...

  3. 字典树变形 A - Gaby And Addition Gym - 101466A

    A - Gaby And Addition Gym - 101466A 这个题目是一个字典树的变形,还是很难想到的. 因为这题目每一位都是独立的,不会进位,这个和01字典树求最大的异或和是不是很像. ...

  4. Java 常用API(二)

    目录 Java 常用API(二) 1. Object类 2. Date类 概述 构造方法和成员方法 3. DateFormat类 概述 SimpleDateFormat类 练习 4. Calendar ...

  5. spring表达式语言

    使用文本表达式 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http: ...

  6. jQuery的相关尺寸获取 - 学习笔记

    获取元素相对于文档的偏移量 获取当前元素相对于父级元素的偏移量 获取文档滚动距离 获取元素的宽度和高度 设置元素的宽度和高度 获取可视区域的宽度和高度 获取文档的宽度和高度 获取元素相对于文档的偏移量 ...

  7. leetCode刷题 | 两数之和

    两数之和: 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不能重复利用这个数 ...

  8. 201771010113 李婷华 《面向对象程序设计(Java)》第十三周总结

    一.理论知识部分 第十一章 事件处理 事件源 (event source):能够产生事件的对象都可 以成为事件源 ,如文本框 .按钮等 .一个事件源是一个能够注册监听器并向发送事件对象的对象. 监听器 ...

  9. Django 设置admin后台表和App(应用)为中文名

    设置表名为中文 1.设置Models.py文件 class Post(models.Model): name = models.CharField() --省略其他字段信息 class Meta: v ...

  10. python3语法学习第四天--字符串

    字符串:是python中的常用数据类型 Python 不支持单字符类型,单字符在 Python 中也是作为一个字符串使用 访问字符串的值: 下标和分片截取 字符串的连接:‘+’ 字符串内置函数挺多,选 ...