文档章节

Android四大组件-ContentProvider

北ing
 北ing
发布于 2015/10/20 19:23
字数 1975
阅读 20
收藏 1

ContentProvider:内容提供者

ContentProvider简介:
当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据。虽然使用其他方法也可以对外共享数据,但数据访问方式会因数据存储的方式而不同,如:采用文件方式对外共享数据,需要进行文件操作读写数据;采用sharedpreferences共享数据,需要使用sharedpreferences API读写数据。而使用ContentProvider共享数据的好处是统一了数据访问方式。
Uri类简介
Uri代表了要操作的数据,Uri主要包含了两部分信息:1.需要操作的ContentProvider ,2.对ContentProvider中的什么数据进行操作,一个Uri由以下几部分组成:
1.scheme:ContentProvider(内容提供者)的scheme已经由Android所规定为:content://。
2.主机名(或Authority):用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。
3.路径(path):可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:
• 要操作contact表中id为10的记录,可以构建这样的路径:/contact/10
• 要操作contact表中id为10的记录的name字段, contact/10/name
• 要操作contact表中的所有记录,可以构建这样的路径:/contact

本篇主要围绕通话记录和联系人讲解ContentProvider的使用。

首先来了解一下通话记录和联系人的表结构。
这是手机中部分表:
这里写图片描述
通话记录在calls表中,联系人表主要有三个:raw_contacts、data、mimetype表。
–联系人记录
–存放联系人信息的表(注意表结构):
联系人信息表:raw_contacts
–_id
–display_name联系人名称

联系人数据表:data
–_id
–raw_contact_id(外键,raw_contacts表的_id)
–data1
–data2
–mimetype_id(数据类型,如电话,邮箱,地址 外键(mimeypes))

数据类型表:mimeypes
–_id
–mimetype
这里写图片描述
数据类型表中需要注意的是name、phone_v2、email_v2字段,对应id是7、5、1;


一、ContentResolver的使用

1)定义ContentProvieder组件提供的内容的Uri接口
2)定义被访问的表中的字段
3)添加访问权限

简单使用1:查询最近联系人记录

// 访问拨号应用下的ContentProvieder组件提供的内容的Uri接口
private Uri callUri = CallLog.Calls.CONTENT_URI;
// 被访问的表中的字段
private String[] columns = { CallLog.Calls._ID, CallLog.Calls.NUMBER,
CallLog.Calls.DATE, CallLog.Calls.TYPE };

private void loadData() {
        // 使用ContentResolver访问拨号记录应用下的ContentProvider组件提供的数据库中表的数据
        // 得到ContentResolver对象
        ContentResolver resolver = getContentResolver();
        // 查询uri代表的资源(从 Uri代表的表中进行查询)
        Cursor cursor = resolver.query(callUri, columns, null, null, null);
        while (cursor.moveToNext()) {
            long id = cursor.getLong(0);
            String number = cursor.getString(1);
            long time = cursor.getLong(2);
            int type = cursor.getInt(3);
            String date = new SimpleDateFormat("yyyy-MM-dd E HH:mm:ss")
                    .format(new Date(time));
            String types = (type == 1 ? "拨入" : (type == 2 ? "拨出" : "未接"));
            datas.add(new CallInfo(id, number, date, types));
        }
        adapter.notifyDataSetChanged();
    }

简单使用2:查询手机联系人,然后执行增删改操作
需要了解联系人数据库中有哪些表及表的结构:通过adb shell可以查看。
–联系人记录
–存放联系人信息的表(注意表结构):
联系人信息表:raw_contacts
–_id
–display_name联系人名称
联系人数据表:data
–_id
–raw_contact_id(外键,raw_contacts表的_id)
–data1:电话、邮箱、姓名等信息
–data2
–mimetype_id(数据类型,如电话,邮箱,地址 外键(mimeypes))
数据类型表:mimeypes
–_id
–mimetype
– mimetype_id=1:邮箱
– mimetype_id=5:电话
– mimetype_id=7:姓名

// 访问raw_contacts这张表的Uri
    private Uri contactUri = Uri            .parse("content://com.android.contacts/raw_contacts");
    private String[] conColumn = { "_id", "display_name" };
    // //访问data这张表的Uri
    private Uri dataUri = Uri.parse("content://com.android.contacts/data");
    private String[] dataColumn = { "data1" };

—>增删该查操作都是第一步得到ContentResolver操作对象,第二步执行已经定义好的方法。

<!-- 访问联系人的ContentProvider组件的权限 -->
    <uses-permission android:name="android.permission.READ_CONTACTS"/>
    <uses-permission android:name="android.permission.WRITE_CONTACTS"/>

2.1添加联系人:
// 向联系人表raw_contacts中添加新的联系人信息

ContentValues value = new ContentValues();
value.put("display_name", name);
value.put("display_name_alt", name);
// 返回新插入的记录Uri,Uri中包含了_id
// content://com.android.contacts/raw_contacts/#8
    Uri datasUri = getContentResolver().insert(contactUri,value);

这个方法值得注意的是返回的是一个uri,也就是新增的这条数据的uri,如果想得到该条记录的id可以调用这个方法:
long _id = ContentUris.parseId(datasUri);

–姓名:
value.put(“data1”, name);
value.put(“mimetype”,”vnd.android.cursor.item/name”);
–电话:
value.put(“data1”, phone);
value.put(“mimetype”,”vnd.android.cursor.item/phone_v2”);
–邮件:
value.put(“data1”, email);
value.put(“mimetype”,”vnd.android.cursor.item/email_v2”);

2.2删除联系人:都是很简单的操作
// 再从联系人表中删除信息
getContentResolver().delete(contactUri, “_id=” + id,null);

2.3修改联系人:

value.put("display_name", name);
value.put("display_name_alt", name);
long id = Long.parseLong(String.valueOf(datas.get(curItemPosition).get("id")));
// 更新联系人信息
getContentResolver().update(contactUri, value,"_id=" + id, null);

2.4查询所有联系人

ContentResolver resolver = getContentResolver();
// 先从联系人表中查询所有人的信息
Cursor cursor = resolver.query(contactUri, conColumn, null, null, null);

二、自定义ContentProvider

1.步骤:
1)声明该contentProvider的唯一标识,通常使用包名加数据库名,必须小写
2)为该组件中可以被外界访问的数据库中的资源定义Code标识,不对外界开放的不用定义
3)定义访问资源的Uri的匹配器对象–使用该类生成被访问的资源的Uri
4)UriMatcher添加访问uri
5)清单文件中注册组件 name authorities
6)声明访问该组件的权限
7)重写provider的增删改查方法

2.实现
1)自定义数据库

public class DBHelper extends SQLiteOpenHelper {
    public DBHelper(Context context) {
        super(context, "users.db", null, 1);
    }
    @Override
    public void onCreate(SQLiteDatabase db) {
        // TODO 初始化数据库
        db.execSQL("create table t_user(_id integer primary key,uname,upass,money)");
        db.execSQL("create table t_order(_id integer primary key,user_id,price,productname)");
        db.execSQL("insert into t_user(uname,upass,money) values('lisa','123',200)");
        db.execSQL("insert into t_user(uname,upass,money) values('zhangsan','1234',2000)");
    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // TODO 数据库升级时执行该方法
        if (newVersion > oldVersion) {
            db.execSQL("drop table if exists t_user");
            db.execSQL("drop table if exists t_order");
            onCreate(db);
        }
    }
}

2)按上述步骤定义ContentProvider

public class UserContentProvider extends ContentProvider {
    // 声明该ContentProvider的唯一标识--通常使用包名+数据库名--必须小写
    public static final String AUTHORITY = "com.beiing.contentprovider_selfdefine.users";
    // 为该组件中可以被外界访问的数据库中的资源定义Code标识
    public static final int CODE_USER = 1;
    public static final int CODE_ORDER = 2;
    // 定义访问资源的Uri的匹配器对象--使用该类生成被访问的资源的Uri
    private static UriMatcher uriMatcher;
    static {
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        // content://com.beiing.contentprovider_selfdefine.users/user
        uriMatcher.addURI(AUTHORITY, "user", CODE_USER);
        // content://com.beiing.contentprovider_selfdefine.users/order
        uriMatcher.addURI(AUTHORITY, "order", CODE_ORDER);
    }
    private DBHelper dbHelper;
    @Override
    public boolean onCreate() {
        // TODO 初始化 数据库操作的工具类
        dbHelper = new DBHelper(getContext());
        return false;
    }
    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {
        SQLiteDatabase db = dbHelper.getReadableDatabase();
        Cursor cursor = null;
        int code = uriMatcher.match(uri);
        switch (code) {
        case CODE_USER:
            cursor = db.query("t_user", projection, selection, selectionArgs,
                    null, null, sortOrder);
            break;
        case CODE_ORDER:
            break;
        }
        return cursor;
    }
    @Override
    public Uri insert(Uri uri, ContentValues values) {
        // TODO 向数据库中插入数据
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        if (uriMatcher.match(uri) == CODE_USER) {
            long id = db.insert("t_user", null, values);
            // 返回新插入的记录的 Uri,回忆插入新数据时可以通过返回的uri得到id
            // content://com.beiing.contentprovider_selfdefine.users/user/6
            return ContentUris.withAppendedId(uri, id);
        }
        return null;
    }
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        // TODO 删除数据库中的数据
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        int num = 0;
        if (uriMatcher.match(uri) == CODE_USER) {
            num = db.delete("t_user", selection, selectionArgs);
        }
        return num;
    }
    @Override
    public int update(Uri uri, ContentValues values, String selection,
            String[] selectionArgs) {
        // TODO 修改数据库中的数据
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        if (uriMatcher.match(uri) == CODE_USER) {
            return db.update("t_user", values, selection, selectionArgs);
        }
        return 0;
    }
    @Override
    public String getType(Uri uri) {
        return null;
    }
}

3)清单文件中注册内容提供器

<!-- 注册 ContentProvider组件 android:authorities:声明该组件的唯一标识 android:permission:声明该组件的权限 android:exported="true":声明该组件可以被外界应用访问 -->
<provider android:name="com.beiing.contentprovider_selfdefine.contentprovider.UserContentProvider" android:authorities="com.beiing.contentprovider_selfdefine.users" android:permission="com.beiing.contentprovider_selfdefine.READ_WRITE" android:exported="true" />

注意:还需要添加访问该provider的权限和修改的操作权限,否则其他程序不能访问或操作

<!-- 声明访问该组件的权限 -->
    <permission android:name="com.beiing.contentprovider_selfdefine.READ_WRITE"/>

4)在其他程序中使用
和上面使用类似,不赘述了。

源码

版权声明:本文为博主原创文章,未经博主允许不得转载。

© 著作权归作者所有

共有 人打赏支持
北ing
粉丝 0
博文 12
码字总数 17332
作品 0
海淀
Android 自定义权限详解

一、自定义权限与使用 在用户app中,自定义权限往往设定在 四大组件上Activity,Service,BroadcastReceiver,ContentProvider,作为app的一部分,如果不允许组件被其他调用,设置权限也是一种保...

IamOkay
2014/11/24
0
0
android四大组件--ContentProvider详解

一、相关ContentProvider概念解析: 1、ContentProvider简介 在Android官方指出的Android的数据存储方式总共有五种,分别是:Shared Preferences、网络存储、文件存储、外储存储、SQLite。但...

大凉龙雀
2015/10/31
0
0
Android 进阶学习笔记整理

一.android系统架构图及各层介绍 1. 应用层:应用是用java语言编写的运行在虚拟机上的程序,比如通讯录,日历,电话,短信,浏览器等。 2. 应用框架层:这一层是编写Google发布的核心应用时所...

FunCode
07/22
0
0
Android中的组件安全漏洞介绍和检测

第一部分 activity组件安全 首先我们介绍下我们常见的Android的activity组件: Activity是Android四大组件之一,它用于展示界面。Activity是一个应用程序组件,提供一个屏幕,用户可以用来交...

老鹰a
06/29
0
0
个帖子学会Android开发四大组件

黑色幽默Lion 方向比努力重要,能力比知识重要,情商比智商重要! 首页 新闻 新随笔 管理 随笔- 43 文章- 0 评论- 12 一个帖子学会Android开发四大组件 注:本文来自“友盟杯”,仅在此阅读,学...

wsl_Mr
2015/09/02
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

jetbrains系产品IDEA:mac上面提示快捷键设置

原因 由于Mac上面的Ctrl+空格变成输入法切换的快捷键,在使用IDEA的过程中,代码提示很不方便,需要使用option+/这种传统eclipse上面的代码提示快捷键作为主要快捷键。 怎么修改? 移除【opt...

亚林瓜子
30分钟前
0
0
Exclipse 输出结果时换行

System.out.println(f1 + "\n" + d1 + "\n" + d2);

笑丶笑
31分钟前
1
0
怎样治疗标签不能触发onblur事件

I realize this was over a year ago, but it showed up for me in Google while trying to solve this same issue. It seems Chrome does not consider some elements, like body and ancho......

Weijuer
34分钟前
0
0
vue常见库安装

移动设备上的浏览器默认会在用户点击屏幕大约延迟300毫秒后才会触发点击事件,这是为了检查用户是否在做双击。为了能够立即响应用户的点击事件,才有了FastClick。 安装fastclick npm insta...

林夏夕
36分钟前
0
0
kafka 教程(三) kafka Java API 编程

下午写

MrPei
37分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部