一、概述

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. 图论--差分约束--HDU\HDOJ 4109 Instrction Arrangement

    Problem Description Ali has taken the Computer Organization and Architecture course this term. He le ...

  2. HTTP请求头中的X-Forwarded-For介绍

    概述 我们在做nginx方向代理的时候,为了记录整个代理过程,我们往往会在配置文件中加上如下配置: location ^~ /app/download/ { ... proxy_set_header ...

  3. SecureCRT怎么将本级文件上传到CentOS

    进入到想要放文件的路径,不然会默认放在当前路径下: 输入 rz -------------------------------------------------------------------- ...

  4. D. Almost All Divisors(数学分解因子)

    其实这题并不难啊,但是分解因子的细节一定要小心. \(比如样例48,2是因子说明24也是因子,也就是说假如x存在\) \(那么x一定是因子中的最小数乘上最大数\) \(那我们现在去验证x是否存在,先拿 ...

  5. Spring官网阅读(十七)Spring中的数据校验

    文章目录 Java中的数据校验 Bean Validation(JSR 380) 使用示例 Spring对Bean Validation的支持 Spring中的Validator 接口定义 UML类图 ...

  6. OpenWrt R2020.3.11 去广告 抗污染 加速 PSW 无缝集成 UnPnP NAS

    近期更新:OpenWrt R2020.3.11版本2020.03.16编译. 按大家要求,新发布固件携带了编译时用到的全部软件包 加入了国内域名加速解析脚本 解决了原去广告,DNS优化方案与PSW冲突 ...

  7. 自己动手写RPC

    接下来2个月 给自己定个目标 年前  自己动手做个RPC 框架 暂时技术选型  是 dotcore + netty + zookeeper/Consul

  8. 随笔 - B树算法实现

    写代码之前,再回顾一下B树是什么,满足什么样的规则 B树规则: 排序方式:所有节点关键字是按递增次序排列,并遵循左小右大原则 子节点数:非叶节点的子节点数>1,且<=M ,且M>=2 ...

  9. 解决编码问题:AttributeError: 'str' object has no attribute 'decode'

    1. 问题发现: 出现:读取文件,对其进行解码,出现错误,AttributeError: 'str' object has no attribute 'decode' 解释:属性错误,str对象不包含 ...

  10. JDBC12 ORM01 Object[]存放一条记录

    ORM(Object Relationship Mapping)的基本思想 -表结构跟类对应:表中的字段和类的属性对应:表中记录和对象对应 让JavaBean的属性名和类型尽量和数据库保持一致 一条记 ...