一、ContentProvider简介
       当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据。虽然使用其他方法也可以对外共享数据,但数据访问方式会因数据存储的方式而不同,如:采用文件方式对外共享数据,需要进行文件操作读写数据;采用sharedpreferences共享数据,需要使用sharedpreferences API读写数据。而使用ContentProvider共享数据的好处是统一了数据访问方式。

二、如何实现ContentProvider

  1、继承抽象类ContentProvider实现一系列针对于数据的增删改查等方法;

  测试代码:

package com.example.contentproviderdemo1;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri; public class MyContentProvider extends ContentProvider{ @Override //创建后被触发
public boolean onCreate() {
// TODO Auto-generated method stub
return false;
} @Override //根据uri查询出selection指定条件所匹配的记录,可以指定列,和排序方式
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
// TODO Auto-generated method stub
return null;
} @Override //返回当前Uri的MIME类型,如果URI对应的数据可能包括多条记录,
//那么MIME类型字符串就是以vnd.android.dir/开头。
//如果该URI对应的数据只有一条记录,那么MIME类型字符串就是以vnd.android.cursor.item/开头。
public String getType(Uri uri) {
// TODO Auto-generated method stub
return null;
} @Override //根据Uri插入values对应的数据
public Uri insert(Uri uri, ContentValues values) {
// TODO Auto-generated method stub
return null;
} @Override //根据uri删除selection指定的条件所匹配的记录
public int delete(Uri uri, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
} @Override //根据uri修改selection指定条件所匹配的记录
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
}
}

  2、需要在AndroidMainfest.xml中完成对ContentProvider的注册;  

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.contentproviderdemo1.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- name:contentprovider的名字,authorities:全局的包名,不允许有重复 -->
<provider android:name="myprovider" android:authorities="com.example.contentproviderdemo1"></provider>
</application>

三、Uri类简介

  Uri代表了要操作的数据,Uri主要包含了两部分信息:1.需要操作的ContentProvider ,2.对ContentProvider中的什么数据进行操作.  一个Uri由以下几部分组成:

  1.scheme:ContentProvider(内容提供者)的scheme已经由Android所规定为:content://。

  2.主机名(或Authority):用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它,必须和配置文件中的android:authorities名称一致。

  3.路径(path):可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:
    1)要操作contact表中id为10的记录,可以构建这样的路径:/contact/10
    2)要操作contact表中id为10的记录的name字段, contact/10/name
    3)要操作contact表中的所有记录,可以构建这样的路径:/contact

  要操作的数据不一定来自数据库,也可以是文件等他存储方式,如下:
  要操作xml文件中contact节点下的name节点,可以构建这样的路径:/contact/name
  如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下:
  Uri uri = Uri.parse("content://com.changcheng.provider.contactprovider/contact")

   

 四、UriMatcher、ContentUrist和ContentResolver简介
       因为Uri代表了要操作的数据,所以我们很经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher 和ContentUris 。掌握它们的使用,会便于我们的开发工作。

UriMatcher:用于匹配Uri,它的用法如下:
       1.首先把你需要匹配Uri路径全部给注册上,如下:
       //常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码(-1)。
       UriMatcher  uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
       //如果match()方法匹配content://com.changcheng.sqlite.provider.contactprovider/contact路径,返回匹配码为1
       uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact”, 1);//添加需要匹配uri,如果匹配就会返回匹配码
       //如果match()方法匹配   content://com.changcheng.sqlite.provider.contactprovider/contact/230路径,返回匹配码为2
       uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact/#”, 2);//#号为通配符
      
       2.注册完需要匹配的Uri后,就可以使用uriMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码,匹配码是调用addURI()方法传入的第三个参数,假设匹配content://com.changcheng.sqlite.provider.contactprovider/contact路径,返回的匹配码为1。

ContentUris:用于获取Uri路径后面的ID部分,它有两个比较实用的方法:
•         withAppendedId(uri, id)用于为路径加上ID部分
•         parseId(uri)方法用于从路径中获取ID部分

ContentResolver:当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver 类来完成,要获取ContentResolver 对象,可以使用Activity提供的getContentResolver()方法。 ContentResolver使用insert、delete、update、query方法,来操作数据。

五、ContentProvider示例程序

  实现添加联系人和查询联系人

Manifest.xml中的代码:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.contentproviderdemo2"
android:versionCode="1"
android:versionName="1.0" > <uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" /> <application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.contentproviderdemo2.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<!-- 读取联系人信息 -->
<uses-permission android:name="android.permission.READ_CONTACTS" />
<!-- 添加联系人信息 -->
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
</manifest>

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" > <Button android:id="@+id/btnquery"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="查询联系人"/> <Button android:id="@+id/btnadd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="增加联系人"/> </LinearLayout>

main.java

package com.example.contentproviderdemo2;

import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.RawContacts;
import android.renderscript.Element.DataType;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button; public class MainActivity extends Activity { Button btnquery;
Button btnadd;
Uri contract_uri;
Uri phone_uri;
Uri email_uri; Uri raw_contract_uri;
ContentResolver cr; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); btnquery = (Button) findViewById(R.id.btnquery);
btnadd = (Button) findViewById(R.id.btnadd); cr = getContentResolver(); // 获取联系人的URI对象,由系统本身内置提供
contract_uri = ContactsContract.Contacts.CONTENT_URI;
// 获取联系人电话的URI对象
phone_uri = Phone.CONTENT_URI;
//获取联系人Email的URI对象
email_uri = Email.CONTENT_URI; //插入联系人uri;
raw_contract_uri = RawContacts.CONTENT_URI; btnquery.setOnClickListener(new OnClickListener() { @Override
public void onClick(View v) {
// 设置查询的联系人字段
String[] pros = new String[] { Contacts._ID, Contacts.DISPLAY_NAME, Contacts.PHONETIC_NAME };
// 查询方法
Cursor cur = cr.query(contract_uri, pros, null, null, null);
if (cur != null) {
while (cur.moveToNext()) {
// 获取ID
int id = cur.getInt(cur.getColumnIndex("_ID"));
// 获取联系人姓名
String name = cur.getString(cur.getColumnIndex("DISPLAY_NAME")); // 根据联系人ID 查询联系人的手机号码
Cursor cur1 = cr.query(phone_uri, new String[] { Phone.NUMBER, Phone.TYPE }, Phone.CONTACT_ID + "=" + id, null, null);
if (cur1 != null) {
while (cur1.moveToNext()) {
// 获取电话类型
int type = cur1.getInt(cur1.getColumnIndex(Phone.TYPE)); // 判断是否为家庭号码
if(type==Phone.TYPE_HOME){
Log.i("家庭电话 ", name + ":" + cur1.getString(cur1.getColumnIndex(Phone.NUMBER)));
}
else if(type == Phone.TYPE_MOBILE){ //判断是否为手机
Log.i("手机 ", name + ":" + cur1.getString(cur1.getColumnIndex(Phone.NUMBER)));
} }
}
cur1.close(); //根据联系人ID,获取联系人电子邮件
Cursor cur2 = cr.query(email_uri, new String[]{ Email.DATA, }, Email.CONTACT_ID + "=" + id, null, null);
if (cur2 != null) {
while (cur2.moveToNext()) {
Log.i("Email:",cur2.getString(cur2.getColumnIndex(Email.DATA1)));
}
}
}
}
cur.close();
}
}); btnadd.setOnClickListener(new OnClickListener() { @Override
public void onClick(View v) {
//添加联系人
ContentValues values = new ContentValues();
//调用插入联系人方法
Uri uri = cr.insert(raw_contract_uri, values);
//获取最新插入的id
Long rawid = ContentUris.parseId(uri);
values.clear(); //清空 //插入人名
values.put(StructuredName.RAW_CONTACT_ID, rawid); //指定联系人id
values.put(StructuredName.DISPLAY_NAME, "张无忌"); //指定联系人姓名
values.put(StructuredName.MIMETYPE,StructuredName.CONTENT_ITEM_TYPE); //表示插入一条记录
uri = cr.insert(Data.CONTENT_URI, values);
values.clear(); //插入电话信息
values.put(Phone.RAW_CONTACT_ID, rawid);
values.put(Phone.NUMBER, "13713803014");
values.put(Phone.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
uri = cr.insert(Data.CONTENT_URI, values);
}
});
} }

Android学习(十二) ContentProvider的更多相关文章

  1. android学习十二(android的Content Provider(内容提供器)的使用)

    文件存储和SharePreference存储以及数据存储一般为了安全,最好用于当前应用程序中訪问和存储数据.内容提供器(Content Provider)主要用于在不同的应用程序之间实现数据共享的功能 ...

  2. Android学习十二---在android上实现图像匹配

    一.效果图及功能描述 效果图 点击ShowImg后 点击match,然后点击showmatch,可以不断点击showmatch. 主要功能描述:显示在SD卡上已经存在的图片test.jpg,根据图片在 ...

  3. Android学习十二:跑马灯程序实现(简单联系)

    package org.tonny; import java.util.Timer; import java.util.TimerTask; import android.app.Activity; ...

  4. Android学习十二:自定义控件学习

    自定义控件: 1.定义控件的属性,atts.xml 2.代码实现自定义控件的控制 3.引用该控件 首先定义相关的属性 <?xml version="1.0" encoding ...

  5. android学习十二 配置变化

    1.配置变化会终止当前活动,并重建活动 2.配置变化有    2.1  屏幕方向变化    2.2  语言变化    2.3   插到基座等   3. 配置变化应用程序不会清除,上下文对新活动依然有效 ...

  6. (转)SpringMVC学习(十二)——SpringMVC中的拦截器

    http://blog.csdn.net/yerenyuan_pku/article/details/72567761 SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter, ...

  7. Android Studio(十二):打包多个发布渠道的apk文件

    Android Studio相关博客: Android Studio(一):介绍.安装.配置 Android Studio(二):快捷键设置.插件安装 Android Studio(三):设置Andr ...

  8. Android学习十九:ContentProvider初步

    一.Content Provider基本概念 1.ContentProvider为存储和获取数据提供了统一的接口.ContentProvide对数据进行封装.不用关心数据存储的细节.使用表的形式来组织 ...

  9. Android入门(十二)SQLite事务、升级数据库

    原文链接:http://www.orlion.ga/610/ 一.事务 SQLite支持事务,看一下Android如何使用事务:比如 Book表中的数据都已经很老了,现在准备全部废弃掉替换成新数据,可 ...

  10. android学习笔记54——ContentProvider

    ContentProvider ContentProvider用于实现数据共享. ContentProvider是不同应用程序之间进行数据交换的标准API,其以某种Uri的形式对外提供数据,允许其他应 ...

随机推荐

  1. codechef AUG17 T1 Chef and Rainbow Array

    Chef and Rainbow Array Problem Code: RAINBOWA Chef likes all arrays equally. But he likes some array ...

  2. win7 iis 7.0 碰到 503错误,找到的解决方案

    Service Unavailable HTTP Error 503. The service is unavailable. 今天要布署一个网站,在自己的电脑上,结果碰到服务器503错误,找应用程序 ...

  3. OpenGL入门学习(三)

    http://developer.178.com/201103/94954704639.html 在第二课中,我们学习了如何绘制几何图形,但大家如果多写几个程序,就会发现其实还是有些郁闷之处.例如:点 ...

  4. electron 安装使用

    1.安装 node.js 链接:http://pan.baidu.com/s/1o7W7BIy 密码:y6od 一路next 我安装在F:\Program Files\node.js下 2.检查nod ...

  5. hbase异常:java.io.IOException: Unable to determine ZooKeeper ensemble

    项目中用到hbase,有时候可能会报一些异常,比如java.io.IOException: Unable to determine ZooKeeper ensemble 等等,当出现这个问题时,根据个 ...

  6. Python学习杂记_14_模块(二)_常用模块

    常用模块 random 模块 import random print(random.random()) # 随机浮点数,默认取0-1,不能指定范围 print(random.randint(1, 20 ...

  7. c++类的隐藏,覆盖和重载,using关键字使用

    转载一篇文章: http://www.cnblogs.com/ustc11wj/archive/2012/08/11/2637316.html 类的隐藏和重载不一样 类的隐藏是指 一个类继承自另外一个 ...

  8. MVC中路由器程序

    MVC中路由器程序编写方式如下例子 把地址:/home/add?id=1 改写成:/home/add/1 把地址:/home/edit?id=1&sid=2 改写成:/home/edit/1_ ...

  9. CF978B File Name【数组操作/序列判断连续出现>=3次的‘x’个数】

    CF978B File Name [分析]:设置计数器cnt,计数x的个数:遇到非x,若cnt>=3的话累加多出的个数,计数器清零:若最后cnt>=3说明没遇到非x无法清零,那后部分就都是 ...

  10. Codeforces Round #377 (Div. 2) A. Buy a Shovel【暴力/口袋里面有无限枚 10 元和一枚 r 面值的硬币,问最少可以买多少把价值为 k 的铁铲】

    A. Buy a Shovel time limit per test 1 second memory limit per test 256 megabytes input standard inpu ...