当前位置: 代码迷 >> Android >> Android学习札记-20_采用ContentProvider对外共享数据, UriMatcher类使用介绍 ,ContentUris类使用介绍,使用ContentResolver操作Conte
  详细解决方案

Android学习札记-20_采用ContentProvider对外共享数据, UriMatcher类使用介绍 ,ContentUris类使用介绍,使用ContentResolver操作Conte

热度:90   发布时间:2016-05-01 11:14:26.0
Android学习笔记---20_采用ContentProvider对外共享数据, UriMatcher类使用介绍 ,ContentUris类使用介绍,使用ContentResolver操作Conte
20_采用ContentProvider对外共享数据
------------------------------------------
1.比如通讯录,就是通过ContentProvider,实现的,通讯录就是要获得应用中的数据,可以把
  项目中的,xml,文本,数据库中的等,任意类型的数据进行共享;
-----------------------
2.文件的生成模式:readable,wirteable
--------------------------------
3.ContentProvider安卓的一个应用组件
 <provider android:name=".PersonProvider"//.表示当前的包下:
            android:authorities="com.credream.providers.personprovider"/>内容提供


者的唯一标识
------------------------------
4.当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其


他应用共享其数据。以前我们学习过文件的操作模式,通过指定文件的操作模式为


Context.MODE_WORLD_READABLE 或Context.MODE_WORLD_WRITEABLE同样可以对外共享数据,


但数据的访问方式会因数据存储的方式而不同,如:采用xml文件对外共享数据,需要进行


xml解析来读写数据;采用sharedpreferences共享数据,需要使用sharedpreferences API读


写数据。而使用ContentProvider共享数据的好处是统一了数据访问方式。
当应用需要通过ContentProvider对外共享数据时,第一步需要继承ContentProvider并重写


下面方法:
public class PersonContentProvider extends ContentProvider{
   public boolean onCreate()
   public Uri insert(Uri uri, ContentValues values)
   public int delete(Uri uri, String selection, String[] selectionArgs)
   public int update(Uri uri, ContentValues values, String selection, String[] 


selectionArgs)
   public Cursor query(Uri uri, String[] projection, String selection, String[] 


selectionArgs, String sortOrder)
   public String getType(Uri uri)}
第二步需要在AndroidManifest.xml使用<provider>对该ContentProvider进行配置,为了能


让其他应用找到该ContentProvider , ContentProvider 采用了authorities(主机名/域名


)对它进行唯一标识,你可以把 ContentProvider看作是一个网站(想想,网站也是提供数


据者),authorities 就是他的域名:
<manifest .... >
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <provider android:name=".PersonContentProvider" 


android:authorities="cn.itcast.providers.personprovider"/>
    </application>
</manifest>
注意:一旦应用继承了ContentProvider类,后面我们就会把这个应用称为ContentProvider


(内容提供者)。
------------------------
5.Uri代表了要操作的数据,Uri主要包含了两部分信息:1》需要操作的ContentProvider ,


2》对ContentProvider中的什么数据进行操作,一个Uri由以下几部分组成:
---------------------
6.ContentProvider(内容提供者)的scheme已经由Android所规定, scheme为:content://
主机名(或叫Authority)用于唯一标识这个ContentProvider,外部调用者可以根据这个标


识来找到它。
路径(path)可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:
要操作person表中id为10的记录,可以构建这样的路径:/person/10
要操作person表中id为10的记录的name字段, person/10/name
要操作person表中的所有记录,可以构建这样的路径:/person
要操作xxx表中的记录,可以构建这样的路径:/xxx
当然要操作的数据不一定来自数据库,也可以是文件、xml或网络等其他存储方式,如下:
要操作xml文件中person节点下的name节点,可以构建这样的路径:/person/name
如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下:
Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person")
--------------------
7.uri:http://,ftp://,content://就是这个道理
---------------------------------------------
8.UriMatcher类使用介绍
因为Uri代表了要操作的数据,所以我们经常需要解析Uri,并从Uri中获取数据。Android系


统提供了两个用于操作Uri的工具类,分别为UriMatcher 和ContentUris 。掌握它们的使用


,会便于我们的开发工作。
UriMatcher类用于匹配Uri,它的用法如下:
首先第一步把你需要匹配Uri路径全部给注册上,如下:
//常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码
UriMatcher  sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//如果match()方法匹配content://cn.itcast.provider.personprovider/person路径,返回


匹配码为1
sMatcher.addURI(“cn.itcast.provider.personprovider”, “person”, 1);//添加需要


匹配uri,如果匹配就会返回匹配码
//如果match()方法匹配content://cn.itcast.provider.personprovider/person/230路径,


返回匹配码为2
sMatcher.addURI(“cn.itcast.provider.personprovider”, “person/#”, 2);//#号为通


配符
switch (sMatcher.match(Uri.parse


("content://cn.itcast.provider.personprovider/person/10"))) { 
   case 1
    break;
   case 2
    break;
   default://不匹配
    break;
}
注册完需要匹配的Uri后,就可以使用sMatcher.match(uri)方法对输入的Uri进行匹配,如果


匹配就返回匹配码,匹配码是调用addURI()方法传入的第三个参数,假设匹配


content://cn.itcast.provider.personprovider/person路径,返回的匹配码为1
-----------------------------------------
9.ContentUris类使用介绍
ContentUris类用于获取Uri路径后面的ID部分,它有两个比较实用的方法:
withAppendedId(uri, id)用于为路径加上ID部分:
Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person")
Uri resultUri = ContentUris.withAppendedId(uri, 10); 
//生成后的Uri为:content://cn.itcast.provider.personprovider/person/10


parseId(uri)方法用于从路径中获取ID部分:
Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person/10")
long personid = ContentUris.parseId(uri);//获取的结果为:10
-------------------------------------------------------
8.使用ContentProvider共享数据
ContentProvider类主要方法的作用:
public boolean onCreate()
该方法在ContentProvider创建后就会被调用, Android开机后, ContentProvider在其它应


用第一次访问它时才会被创建。
public Uri insert(Uri uri, ContentValues values)
该方法用于供外部应用往ContentProvider添加数据。
public int delete(Uri uri, String selection, String[] selectionArgs)
该方法用于供外部应用从ContentProvider删除数据。
public int update(Uri uri, ContentValues values, String selection, String[] 


selectionArgs)
该方法用于供外部应用更新ContentProvider中的数据。
public Cursor query(Uri uri, String[] projection, String selection, String[] 


selectionArgs, String sortOrder)
该方法用于供外部应用从ContentProvider中获取数据。
public String getType(Uri uri)
该方法用于返回当前Url所代表数据的MIME类型。如果操作的数据属于集合类型,那么MIME类


型字符串应该以vnd.android.cursor.dir/开头,例如:要得到所有person记录的Uri为


content://cn.itcast.provider.personprovider/person,那么返回的MIME类型字符串应该


为:“vnd.android.cursor.dir/person”。如果要操作的数据属于非集合类型数据,那么


MIME类型字符串应该以vnd.android.cursor.item/开头,例如:得到id为10的person记录,


Uri为content://cn.itcast.provider.personprovider/person/10,那么返回的MIME类型字


符串应该为:“vnd.android.cursor.item/person”。
--------------------------
9.使用ContentResolver操作ContentProvider中的数据
当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用


ContentResolver 类来完成,要获取ContentResolver 对象,可以使用Activity提供的


getContentResolver()方法。 ContentResolver 类提供了与ContentProvider类相同签名的


四个方法:
public Uri insert(Uri uri, ContentValues values)
该方法用于往ContentProvider添加数据。
public int delete(Uri uri, String selection, String[] selectionArgs)
该方法用于从ContentProvider删除数据。
public int update(Uri uri, ContentValues values, String selection, String[] 


selectionArgs)
该方法用于更新ContentProvider中的数据。
public Cursor query(Uri uri, String[] projection, String selection, String[] 


selectionArgs, String sortOrder)
该方法用于从ContentProvider中获取数据。


这些方法的第一个参数为Uri,代表要操作的ContentProvider和对其中的什么数据进行操作


,假设给定的是: Uri.parse


(“content://cn.itcast.providers.personprovider/person/10”),那么将会对主机名为


cn.itcast.providers.personprovider的ContentProvider进行操作,操作数据为person表中


id为10的记录。
------------------------------
10.使用ContentResolver操作ContentProvider中的数据
使用ContentResolver对ContentProvider中的数据进行添加、删除、修改和查询操作:
ContentResolver resolver =  getContentResolver();
Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person");
//添加一条记录
ContentValues values = new ContentValues();
values.put("name", "itcast");
values.put("age", 25);
resolver.insert(uri, values);
//获取person表中所有记录
Cursor cursor = resolver.query(uri, null, null, null, "personid desc");
while(cursor.moveToNext()){
Log.i("ContentTest", "personid="+ cursor.getInt(0)+ ",name="+ 


cursor.getString(1));
}
//把id为1的记录的name字段值更改新为liming
ContentValues updateValues = new ContentValues();
updateValues.put("name", "liming");
Uri updateIdUri = ContentUris.withAppendedId(uri, 2);
resolver.update(updateIdUri, updateValues, null, null);
//删除id为2的记录
Uri deleteIdUri = ContentUris.withAppendedId(uri, 2);
resolver.delete(deleteIdUri, null, null);
----------------------
11.当ContentProvider中的数据发生变化时可以向其用户发出通知
如果ContentProvider的访问者需要得知ContentProvider中的数据发生了变化,可以在


ContentProvider 发生数据变化时调用getContentResolver().notifyChange(uri, null)来


通知注册在此URI上的访问者,例子如下:
public class PersonContentProvider extends ContentProvider {
public Uri insert(Uri uri, ContentValues values) {
db.insert("person", "personid", values);
getContext().getContentResolver().notifyChange(uri, null);
}
}
如果ContentProvider的访问者需要得到数据变化通知,必须使用ContentObserver对数据(


数据采用uri描述)进行监听,当监听到数据变化通知时,系统就会调用ContentObserver的


onChange()方法:
getContentResolver().registerContentObserver(Uri.parse


("content://cn.itcast.providers.personprovider/person"),
        true, new PersonObserver(new Handler()));
public class PersonObserver extends ContentObserver{
public PersonObserver(Handler handler) {
super(handler);
  }
public void onChange(boolean selfChange) {
   //此处可以进行相应的业务处理
}
}
------------------------
11.数据共享者测试的所有代码:
--------------------------------------------------
a.新建项目:ContentProviderDBSQLIte这个项目是从DBSQLIte项目拷贝然后添加如下类:
/ContentProviderDBSQLIte/src/com/credream/db/PersonProvider.java
package com.credream.db;


import com.credream.service.DBOpenHelter;


import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;


public class PersonProvider extends ContentProvider
{
private DBOpenHelter dbOpenHelter;
private static final UriMatcher MATCHER=new UriMatcher


(UriMatcher.NO_MATCH);//UriMatcher.NO_MATCH返回-1
private static final int PERSONS=1;
private static final int PERSON=2;
//参数代表,如果跟输入进去的uri不匹配的时候返回的不匹配码
//UriMatcher.NO_MATCH为-1
static{
MATCHER.addURI("com.credream.providers.personprovider", "person", 


PERSONS);
MATCHER.addURI("com.credream.providers.personprovider", "person/#", 


PERSON);
//在android中#代表数字,
//"com.credream.providers.personprovider"表示uri "person"表示的表, 


PERSONS匹配码1;

}


@Override
public boolean onCreate()//由系统调用,只执行一次,适合进行数据初始化操作
{
dbOpenHelter=new DBOpenHelter(this.getContext());
return true;
}
//可以供外部的应用查询,从内容提供者中删除数据
@Override
public int delete(Uri uri, String selection, String[] selectionArgs)
{SQLiteDatabase db=dbOpenHelter.getWritableDatabase();
int num=0;  
switch (MATCHER.match(uri))
{
case 1:
num=db.delete("person", selection, selectionArgs);
break;
case 2:
long rowid=ContentUris.parseId(uri);
String where="personid="+rowid;
if(selection!=null&&!"".equals(selection.trim())){
where+=" and "+selection;
}
num=db.delete("person", where, selectionArgs);
break;
default:
throw new IllegalArgumentException("this is Unknow 


Uri"+uri);
 
}
return num;
}
//返回要操作的内容类型,比如txt,html plain/text, html/text
@Override
public String getType(Uri uri)
{//这种操作很多数据MATCHER.addURI


("com.credream.providers.personprovider", "person", PERSONS);
     //这种操作单个数据MATCHER.addURI("com.credream.providers.personprovider", 


"person/#", PERSON);
/* public String getType(Uri uri)
该方法用于返回当前Url所代表数据的MIME类型。如果操作的数据属于集合


类型,
那么MIME类型字符串应该以vnd.android.cursor.dir/开头
               例如:要得到所有person记录的Uri为
               content://cn.itcast.provider.personprovider/person,
               那么返回的MIME类型字符串应该为:“vnd.android.cursor.dir/person”



               如果要操作的数据属于非集合类型数据,
               那么MIME类型字符串应该以vnd.android.cursor.item/开头,
               例如:得到id为10的person记录,Uri为
               content://cn.itcast.provider.personprovider/person/10,
               那么返回的MIME类型字符串应该为:“vnd.android.cursor.item/person”



*/

switch(MATCHER.match(uri)){
case 1:
return "vnd.android.cursor.dir/person";
case 2:
return "vnd.android.cursor.item/person";
default:
throw new IllegalArgumentException("this is 


unknow uri:"+uri);
}
}
//可以供外部的应用查询,往内容提供者中插入数据
//ContentValues用于存放各个字段的值
@Override
public Uri insert(Uri uri, ContentValues values)
{
//往数据库中插入数据
SQLiteDatabase db=dbOpenHelter.getWritableDatabase();
switch(MATCHER.match(uri)){
case 1:
long rowid=db.insert("person", "name", values);//行号,如


果主键是整形的,并且是增长的话,那么这个是值就是主键值;
//第二个参数,外面values如果传一个null,或者是空集合,这时候


第二个参数采用的上,给一个默认值
//返回的事uri



//content://com.credream.providers.personprovider/person/10
//第一种获得这一行的uri的方法
//Uri insertUri=Uri.parse


("content://com.credream.providers.personprovider/person/"+rowid);
//content://com.credream.providers.personprovider/person/
//第二种获得这一行的uri的方法
Uri insertUri=ContentUris.withAppendedId(uri, rowid);
return insertUri;
//break;//ResNo不是行号,
default:
throw new IllegalArgumentException("this is Unknow 


Uri"+uri);
}
}
/*public Cursor query(Uri uri, String[] projection, String selection, 


String[] 
* selectionArgs, String sortOrder)
该方法用于供外部应用从ContentProvider中获取数据。
*/

//可以供外部的应用查询,从内容提供者中查询
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder)
{SQLiteDatabase db=dbOpenHelter.getWritableDatabase();

switch (MATCHER.match(uri)){
case 1:
return db.query("person", projection, selection, selectionArgs, 


null, null, sortOrder);
case 2:
long rowid=ContentUris.parseId(uri);
String where="personid="+rowid;
if(selection!=null&&!"".equals(selection.trim())){
where+=" and "+selection;
}
return db.query("person", projection, selection, 


selectionArgs, null, null, sortOrder);
default :
throw new IllegalArgumentException("this is Unknown 


Uri:"+uri);
}
}
//可以供外部的应用查询,往内容提供者中更新数据
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs)
{
//更新所有的数据,更新某列数据
SQLiteDatabase db=dbOpenHelter.getWritableDatabase();
int num=0;  
switch (MATCHER.match(uri))
{
case 1:
num=db.update("person",values, selection, selectionArgs);
break;
case 2:
long rowid=ContentUris.parseId(uri);
String where="personid="+rowid;
if(selection!=null&&!"".equals(selection.trim


())){
where+=" and "+selection;
}
num=db.update("person",values, where, 


selectionArgs);
break;
default:
throw new IllegalArgumentException("this is 


Unknow Uri"+uri);
 
}
return num;
}


}
---------------------
b./ContentProviderDBSQLIte/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.credream.db"
    android:versionCode="1"
    android:versionName="1.0" >


    <uses-sdk android:minSdkVersion="8" />


    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
      ---------------------添加了这个部分---------------------------------
        <provider android:name=".PersonProvider"
            android:authorities="com.credream.providers.personprovider"/>
 ------------------------------------------   


    
        
        <activity
            android:label="@string/app_name"
            android:name=".DBSQLIteActivity" >
            <intent-filter >
                <action android:name="android.intent.action.MAIN" />


                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    <uses-library android:name="android.test.runner" />
            </application>
 <instrumentation android:name="android.test.InstrumentationTestRunner"
  android:targetPackage="com.credream.db" android:label="Tests for My App" />
</manifest>
-----------------------------
c.接下来在OherFile项目中新建一个测试类,通过这个项目来操作,ContentProviderDBSQLIte
  项目中的ContentProvider中的内容:
-------------------------------------------
/OherFile/src/com/credream/contentProveder/AccessContentProviderTest.java
package com.credream.contentProveder;


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 AccessContentProviderTest extends AndroidTestCase
{
private static final String TAG="Content Provider Query";
public void testInsert()throws Exception{
Uri uri=Uri.parse("content://com.credream.providers.personprovider/person/");
ContentResolver resolver=this.getContext().getContentResolver();
ContentValues values=new ContentValues();
values.put("name", "lidewei");
values.put("phone", "15354568451");
values.put("amount", "50000000000");
resolver.insert(uri, values);//在insert内部会调用内容提供者的insert方法


}




public void testDelete()throws Exception{
Uri uri=Uri.parse("content://com.credream.providers.personprovider/person/20");
ContentResolver resolver=this.getContext().getContentResolver();
resolver.delete(uri, null, null);
}


public void testUpdate()throws Exception{
Uri uri=Uri.parse("content://com.credream.providers.personprovider/person/22");
ContentResolver resolver=this.getContext().getContentResolver();
ContentValues values=new ContentValues();
values.put("name", "lideweinihao");
resolver.update(uri, values, null, null);


resolver.delete(uri, null, null);
}


public void testQuery()throws Exception{
Uri uri=Uri.parse("content://com.credream.providers.personprovider/person");//查询表中的所有数据
ContentResolver resolver=this.getContext().getContentResolver();
Cursor cursor=resolver.query(uri, null, null, null, "personid asc");
//这里第二个是
/*这里是参数的相关说明
Cursor android.content.ContentResolver.query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
public final Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) 
Since: API Level 1 


Query the given URI, returning a Cursor over the result set. 


For best performance, the caller should follow these guidelines: 


Provide an explicit projection, to prevent reading data from storage that aren't going to be used. 
Use question mark parameter markers such as 'phone=?' instead of explicit values in the selection parameter, so that queries that differ only by those values will be recognized as the same for caching purposes. 
Parameters
uri  The URI, using the content:// scheme, for the content to retrieve. 
projection  A list of which columns to return. Passing null will return all columns, which is inefficient. 
selection  A filter declaring which rows to return, formatted as an SQL WHERE clause (excluding the WHERE itself). Passing null will return all rows for the given URI. 
selectionArgs  You may include ?s in selection, which will be replaced by the values from selectionArgs, in the order that they appear in the selection. The values will be bound as Strings. 
sortOrder  How to order the rows, formatted as an SQL ORDER BY clause (excluding the ORDER BY itself). Passing null will use the default sort order, which may be unordered. 


Returns
A Cursor object, which is positioned before the first entry, or null
See Also
Cursor */
while (cursor.moveToNext())
{
String name= cursor.getString(cursor.getColumnIndex("name"));
Log.i(TAG,name);
}
cursor.close();




}
}
------------------------------------

  相关解决方案