contentProvider作为android四大组件其地位也是不可忽视的。contentProvider实现是在Sqlite数据库基础上实现的。其数据存储使用Sqlite实现,上层使用URI进行数据操作,是数据存储变得更简单些。在简化数据存储的同时,contentProvider也提供数据共享功能,数据可以为其它程序提供读写功能。下面看一下具体使用。

创建数据源DBContent(通常是数据库进行存储)

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;public class DBContent extends SQLiteOpenHelper {private final static String DB_NAME = "emcElevator";  public final static String TABLE_SHUACARD = "shuaCard";  public final static int DB_VERSION = 1;  public final static String SID = "_id";public final static String CARD_IDNUM="card_id_number";public final static String CARD_PICTRUE="card_picture_path";public DBContent(Context context){super(context, DB_NAME, null, DB_VERSION); }public DBContent(Context context, String name, CursorFactory factory,int version) {super(context, name, factory, version);}@Overridepublic void onCreate(SQLiteDatabase db) {final String sql="CREATE TABLE " + TABLE_SHUACARD + "(" + SID  + " INTEGER PRIMARY KEY AUTOINCREMENT," + CARD_IDNUM+" TEXT,"+CARD_PICTRUE+" TEXT"+");";db.execSQL(sql);}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {db.execSQL("DROP TABLE IF EXISTS " + TABLE_SHUACARD);  }  }

contentProvider实现类:

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.text.TextUtils;public class CardContentProvider extends ContentProvider {public static final String AUTHORITY = "com.ctsing.provider.shuacarddata";  public static final String ReadContentPermission="com.permission.allow.readcontent";public static final int ITEM = 1;  public static final int ITEM_ID = 2;  public static final String CONTENT_TYPE = "vnd.android.cursor.dir/" + DBContent.TABLE_SHUACARD;  public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/" + DBContent.TABLE_SHUACARD;   public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY  + "/item");  //匹配器  private static final UriMatcher mMatcher;  static{mMatcher = new UriMatcher(UriMatcher.NO_MATCH);  mMatcher.addURI(AUTHORITY, "item", ITEM);  mMatcher.addURI(AUTHORITY, "item/#", ITEM_ID);  }private DBContent dbHelper=null;@Overridepublic boolean onCreate() {dbHelper=new DBContent(getContext());return true;}@Overridepublic Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) {SQLiteDatabase sdb = dbHelper.getReadableDatabase();  Cursor cur;  switch (mMatcher.match(uri)) {  case ITEM:  cur = sdb.query(DBContent.TABLE_SHUACARD, projection, selection,  selectionArgs, null, null, sortOrder);  break;  case ITEM_ID:  long id = ContentUris.parseId(uri);    cur = sdb.query(DBContent.TABLE_SHUACARD, projection, DBContent.SID  + "="  + id  + (!TextUtils.isEmpty(selection) ? " AND (" + selection  + ")" : ""), selectionArgs, null, null, sortOrder);  break;  default:  //   Log.i("sMatcher.match(uri)", String.valueOf(mMatcher.match(uri)));  throw new IllegalArgumentException("Query with unknown URI: " + uri);  }  /* sdb.close();  sdb=null;  */cur.setNotificationUri(getContext().getContentResolver(), uri);  return cur;  }@Overridepublic String getType(Uri uri) {String matchType=null;switch(mMatcher.match(uri)){case ITEM:matchType=CONTENT_TYPE;break;case ITEM_ID:matchType=CONTENT_ITEM_TYPE;break;default:  throw new IllegalArgumentException("Unknown URI " + uri);  }return matchType;}@Overridepublic Uri insert(Uri uri, ContentValues values) {SQLiteDatabase db = dbHelper.getWritableDatabase();  if (mMatcher.match(uri) != ITEM) {  db.close();  db=null;  throw new IllegalArgumentException("Unknow URI " + uri);  }  long rowId = db.insert(DBContent.TABLE_SHUACARD, DBContent.SID, values);  if (rowId > 0) {  Uri noteUri = ContentUris.withAppendedId(CONTENT_URI, rowId);  this.getContext().getContentResolver().notifyChange(noteUri, null);  return noteUri;  }  db.close();  db=null;  throw new SQLException("Failed to insert row into " + uri);  }@Overridepublic int delete(Uri uri, String selection, String[] selectionArgs) {SQLiteDatabase sdb = dbHelper.getWritableDatabase();  int count;  switch (mMatcher.match(uri)) {  case ITEM:  count = sdb.delete(DBContent.TABLE_SHUACARD, selection, selectionArgs);  break;  case ITEM_ID:  //String id = uri.getPathSegments().get(1);  long id = ContentUris.parseId(uri);    count = sdb.delete(DBContent.TABLE_SHUACARD, DBContent.SID  + "=" + id  + (!TextUtils.isEmpty(selection) ? " AND (" + selection  + ")" : ""), selectionArgs);  break;  default:  throw new IllegalArgumentException("Unknown URI " + uri);  }  sdb.close();  sdb=null;  this.getContext().getContentResolver().notifyChange(uri, null);  return count;  }@Overridepublic int update(Uri uri, ContentValues values, String selection,String[] selectionArgs) {SQLiteDatabase db = dbHelper.getWritableDatabase();  int count;  switch (mMatcher.match(uri)) {  case ITEM:  count = db.update(DBContent.TABLE_SHUACARD, values, selection,  selectionArgs);  break;  case ITEM_ID:  String id = uri.getPathSegments().get(1);  count = db.update(DBContent.TABLE_SHUACARD, values, DBContent.SID  + "=" + id  + (!TextUtils.isEmpty(selection) ? " AND (" + selection  + ")" : ""), selectionArgs);  break;  default:  throw new IllegalArgumentException("Unknown URI " + uri);  }  db.close();  db=null;  this.getContext().getContentResolver().notifyChange(uri, null);  return count;  }}

配置ContentProvider

<provider  android:name="com.ctsing.content.CardContentProvider"  android:authorities="com.ctsing.provider.shuacarddata"/>  

单元测试进行功能测试:

import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.test.AndroidTestCase;
import android.util.Log;public class TestUse extends AndroidTestCase  {public void testInsert()throws Exception{   //插入数据    Uri uri = Uri.parse("content://" + CardContentProvider.AUTHORITY  + "/item");    ContentResolver resolver = this.getContext().getContentResolver();ContentValues values1 = new ContentValues();    values1.put(DBContent.CARD_IDNUM, "1001");    values1.put(DBContent.CARD_PICTRUE, "pro/elevater/11.jpeg");    resolver.insert(uri, values1);    ContentValues values2 = new ContentValues(); values2.put(DBContent.CARD_IDNUM, "1002");    values2.put(DBContent.CARD_PICTRUE, "pro/elevater/12.jpeg");resolver.insert(uri, values2);    ContentValues values3 = new ContentValues(); values3.put(DBContent.CARD_IDNUM, "1003");    values3.put(DBContent.CARD_PICTRUE, "pro/elevater/13.jpeg");  resolver.insert(uri, values3);    }    public void testUpdate()throws Exception{   //更新id=2的记录  Uri uri = Uri.parse("content://" + CardContentProvider.AUTHORITY  + "/item/2");   ContentResolver resolver = this.getContext().getContentResolver();    ContentValues values = new ContentValues();    values.put(DBContent.CARD_IDNUM, "1012");   values.put(DBContent.CARD_PICTRUE, "pro/elevater/102.jpeg"); resolver.update(uri, values, null, null);    }    public void testDelete()throws Exception{   //删除id=1的记录    Uri uri = Uri.parse("content://" + CardContentProvider.AUTHORITY  + "/item/1"); //删除id=1的记录    ContentResolver resolver = this.getContext().getContentResolver();    resolver.delete(uri, null, null);    }    public void testQuery()throws Exception{    //查询数据并显示    Uri uri = Uri.parse("content://" + CardContentProvider.AUTHORITY  + "/item");    //查询所有记录    ContentResolver resolver = this.getContext().getContentResolver();    Cursor cursor = resolver.query(uri, null, null, null, null);    while(cursor.moveToNext()){    //   StudentData person = new StudentData(cursor.getInt(cursor.getColumnIndex("id")),cursor.getString(cursor.getColumnIndex("name")),cursor.getInt(cursor.getColumnIndex("age")));    Log.v("ContentProvider", " NO.= "+cursor.getInt((cursor.getColumnIndex("_id")))+" card_id= "+cursor.getString(cursor.getColumnIndex(DBContent.CARD_IDNUM))+" pic_path= "+cursor.getString(cursor.getColumnIndex(DBContent.CARD_PICTRUE)));    }    }   }

这里简单说一下单元测试实现:

1,在配置文件内声明权限,测试目标工具(在application外部声明):

<uses-permission android:name="android.permission.RUN_INSTRUMENTATION" />
    <instrumentation
        android:name="android.test.InstrumentationTestRunner"
        android:targetPackage="com.ctsing.emca" >
    </instrumentation>

<application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

注意!在android:targetPackage所指的的包是应用程序包名,而不是测试类所在的包名称。

在application内部添加使用测试工具:

<applicationandroid:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name"android:theme="@style/AppTheme" ><uses-library android:name="android.test.runner" />

实现继承AndroidTestCase类,再要测试的方法名称前加test,例如测试Insert方法,则编写测试方法testInsert(),在右侧outline窗口选择要测试功能方法,
想要测试哪个方法,则在哪个测试方法上右键鼠标,选择Run As,然后再选择Android JUnit Test即可,如果有异常或者错误,左边测试台会显示红色,下边是错误提示。测试通过,测试条为绿色。

下面在介绍一下Content权限问题,为了数据安全性我们需要添加适当的读写权限

如果contentProvider要被第三方使用读写则需要添加android:exported="true"属性,设置为false时,只有同一个应用程序的组件或带有相同用户ID的应用程序才能启动或绑定该服务。默认为false。当被第三方访问时我们可以添加权限来控制局部或者全部数据使用。

例如设置读取数据权限

声明权限:

<permission android:name="com.permission.allow.readcontent"

android:label="Allow read contentProvider"

android:protectionLevel="normal" />

添加权限到contentProvider:

<provider  android:name="com.ctsing.content.CardContentProvider"  android:authorities="com.ctsing.provider.shuacarddata"android:exported="true"android:readPermission="com.permission.allow.readcontent"/>

t同样我们还可以设置写入权限,write android:witePermission权限,或者两者兼有permission。数据访问者需要添加权限声明

<uses-permission android:name="com.permission.allow.readcontent" />,才能正常访问数据内容,这在一定程度上起到保护数据功能。

部分权限功能:
实际使用中,provider可以只开放部分URI的权限,例如,我们可以只开放content://com.ctsing.provider.shuacarddata/item路径下权限,不允许访问其他路径,如下声明

<provider android:name="com.ctsing.content.CardContentProvider"android:name="com.ctsing.content.CardContentProvider"  android:authorities="com.ctsing.provider.shuacarddata"android:exported="true"android:readPermission="com.permission.allow.readcontent"><path-permission android:pathPrefix="/item" android:readPermission="READ_ITEM_CONTENTPROVIDER" />
</provider>

除了android:pathPrefix,还可以有android:path和android:pathPatten,例如android:pathPattern="/hello/.*"(注意,通配符*之前有个‘.’)。
如果要读取content:content://com.ctsing.content.CardContentProvider/item/1则需要声明整个provider的权限com.permission.allow.readcontent或者该路径的权限READ_ITM_CONTENTPROVIDER。

14.11.20更新,下面说一下数据变化监听问题:

当数据发生变化时,我们需要知道当数据变化时,希望能够得到通知,在android中已经设计了这种监听是用ContentObserver接口实现。联系人和短信内容发生变化时我们能够实现监听变化就是ContentObserver实现的。上述例子中我已经加入notifyChange方法进行内容变化通知,我们只有实现ContentObserver进行注册监听即可。

实现数据监听类:

public class ShuaCardContentObserver extends ContentObserver{private Context mContext;final String SHUACARD_ACTION="com.shuaCard.action";final String SHUACARD_DATA="getData";final String SHUACARD_KEYCARDNUM="card_num";final String SHUACARD_KEYCARDADDRESS="card_path";public ShuaCardContentObserver(Handler handler,Context ctx) {super(handler);this.mContext=ctx;}@Overridepublic void onChange(boolean selfChange) {      super.onChange(selfChange);}@TargetApi(Build.VERSION_CODES.JELLY_BEAN)@Overridepublic void onChange(boolean selfChange, Uri uri) {    super.onChange(selfChange, uri);dealChange();}void dealChange(){Uri uri = Uri.parse("content://" + CardContentProvider.AUTHORITY  + "/item");  ContentResolver resolver = mContext.getContentResolver();    Cursor cursor = resolver.query(uri, null, null, null, null);    List<Map<String,String>> cardList=null;if(cursor.getCount()>0)cardList=new ArrayList<Map<String,String>>();while(cursor.moveToNext()){    String cardNum=cursor.getString(cursor.getColumnIndex(DBContent.CARD_IDNUM));String cardAddress=cursor.getString(cursor.getColumnIndex(DBContent.CARD_PICTRUE_PATH));Map<String,String> map=new HashMap<String, String>();map.put(SHUACARD_KEYCARDNUM, cardNum);map.put(SHUACARD_KEYCARDADDRESS, cardAddress);cardList.add(map);}if(cursor!=null)cursor.close();if(cardList!=null){        Intent it=new Intent(SHUACARD_ACTION);Bundle b=new Bundle();b.putSerializable(SHUACARD_DATA, (Serializable)cardList);it.putExtras(b);mContext.sendBroadcast(it);}}

注册监听:

@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);cardChangeObserver=new ShuaCardContentObserver(new android.os.Handler(), this);getContentResolver().registerContentObserver(Uri.parse("content://" + CardContentProvider.AUTHORITY  + "/item"), true,cardChangeObserver);}

退出取消监听:

@Overrideprotected void onDestroy() {if(null!=cardChangeObserver)getContentResolver().unregisterContentObserver(cardChangeObserver);super.onDestroy();}

虽然我们可以知道数据发生变化,但是我们并不知道具体发生变化数据具体情况(删除哪些数据或是添加哪些),如何实现这一个需求呢?android并没有实现,这就需要我们自己实现了。有待后续研究,更新中。。。

转载于:https://www.cnblogs.com/happyxiaoyu02/archive/2012/09/01/6818982.html

Android ContentProvider 使用介绍相关推荐

  1. Android ContentProvider的介绍

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

  2. Android ContentProvider的介绍(很详细)

    2019独角兽企业重金招聘Python工程师标准>>> 一.ContentProvider的概念 ContentProvider:为存储和获取数据提供统一的接口.可以在不同的应用程序 ...

  3. 【Android数据存储】ContentProvider详细介绍(附实例源码)

    1.ContentProvider是什么? ContentProvider--内容提供者.它是一个类,这个类主要是对Android系统中进行共享的数据进行包装,并提供了一组统一的访问接口供其他程序调用 ...

  4. android contentprovider学习(遇到最满意的介绍)---阿冬专栏

    转自出处:http://blog.csdn.net/dmk877/article/details/50387741 1.什么是内容提供者? 首先我们必须要明白的是ContentProvider(内容提 ...

  5. Android Framework入门介绍

    Android Framework入门介绍 https://blog.csdn.net/fu_kevin0606/article/details/79532710 framework概述 Androi ...

  6. android contentprovider原理,ContentProvider原理分析

    前景知识:对于ContentProvider理解必须对IBinder有所了解(一个提供跨进程信息交换的一个工具),会ContentProvider的简单使用.本文是基于你已经具备以上知识点阅读 1.名 ...

  7. Android Fragment 基本介绍

    Android Fragment 基本介绍 Android Fragment 基本介绍 Fragment Android是在Android 3.0 (API level 11)开始引入Fragment ...

  8. Android Pmem相关介绍

    http://fangjian0518.blog.163.com/blog/#m=0 Android Pmem相关介绍 2011-10-18 09:40:26|  分类: Android PMEM | ...

  9. Kotlin on Android 开发环境介绍

    Kotlin 被 Google 采纳为 Android 开发一级编程语言,到现在也一年多了,我们团队从去年 10 月份开始部分项目尝试用 Kotlin 开发,到现在决定推广到全部项目,因为一旦用上 K ...

最新文章

  1. 北京python培训班价格-北京python培训一对一
  2. PHP 5.4 的新特性
  3. Git添加文件改动时出错
  4. Python报错:UnicodeDecodeError: 'gbk' codec can't decode byte 0xae in position 199: illegal multibyte s
  5. html本地路径图片转成base64,canvas-toDataURL()将图片转为dataURL(base64)
  6. MICCAI 2019 :纪录、风向与学术思考
  7. 华为Mate X2黄牛价已超两万,结果小伙子没拿稳,成全网首摔?
  8. Hadoop中Writable类
  9. [Usaco2015 dec]Breed Counting
  10. SAP License:SAP顾问是如何炼成的——SAP顾问的定义
  11. gradle配置到阿里云_通过图文步骤的方式,带你配置阿里云服务器搭建网站
  12. windows 服务的安装与卸载之bat脚本命令
  13. 涉及第三方支付接口,怎么测?
  14. win7 thinkpad 屏幕旋转 快捷键 与 eclipse冲突
  15. Android NDK篇-C++之 SLT 中的容器与函数谓词
  16. libero-soc许可证申请和环境配置
  17. 三星支付存在漏洞可导致黑客进行交易劫持
  18. 安装分区助手,总是显示“分区助手已安装到你的电脑中,怎么办
  19. i910980hk和r9 4900h哪个好
  20. set在MATLAB中什么意思,matlab中set函数怎么用,具体的,中文的?

热门文章

  1. java servlet 执行 多次_servlet 验证生命周期过程调用方法的次数
  2. 默认网关出现乱码_SpringCloudZuul服务网关
  3. 为什么我的modbus tcp server只能连一个client_TCP 协议概览
  4. 【ElasticSearch】ElasticSearch 中使用衰减函数来完美你的搜索结果
  5. 【SpringCloud】Spring cloud Alibaba Nacos 服务注册与配置中心 命名空间 Data Id
  6. 【Flink】Flink自带的测试类 AbstractStreamOperatorTestHarness
  7. 【Windows】Windows 下 使用 nc 命令 开启socket
  8. Netty : netty 3如何解决空轮询bug
  9. SpringBoot : SpringBoot自定义的ApplicationContext实现类
  10. Mac安装telnet