使用ContentProvider(内容提供者)共享数据

l 使用 ContentProvider (内容提供者)共享数据

/* ContentProvider 在android中的作用是对外共享数据,也就是说你可以通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider 对你应用中的数据进行添删改查。关于数据共享,以前我们学习过文件操作模式,知道通过指定文件的操作模式为Context.MODE_WORLD_READABLE 或Context.MODE_WORLD_WRITEABLE同样也可以对外共享数据。那么,这里为何要使用ContentProvider 对外共享数据呢?是这样的,如果采用文件操作模式对外共享数据,数据的访问方式会因数据存储的方式而不同,导致数据的访问方式无法统一,如:采用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> */


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

使用ContentProvider(内容提供者)共享数据_第1张图片



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")


l 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

l 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

l 使用 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
l
l
l
l
l
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 的记录。

使用 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);



package com.zyq.service; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; public class DBOpenHelper extends SQLiteOpenHelper { /** * 如果想额外的增加一个字段(需求) * 可以把版本号更改掉 但必须 >=1 * 更改版本号之后 会根据版本号判断是不是上次创建的时候 (目前的版本号和传入的版本号是否一致 ) * 如果不是会执行 onUpgrade() 方法 * @param context */ public DBOpenHelper(Context context) { super(context, "zyq.db", null, 5); } /** * 在数据库创建的时候第一个调用的方法 * 适合创建表结构 */ @Override public void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE person (personid integer primary key autoincrement, name varchar(20),phone VARCHAR(12) NULL)");//创建表 } /** * 更新表结构 在数据库版本号发生改变的时候调用 * 应用升级 */ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("ALTER TABLE person ADD amount integer"); //往表中增加一列 } }

package com.zyq.voo; public class Person { public Integer getAmount() { return amount; } public void setAmount(Integer amount) { this.amount = amount; } private Integer id; private String name; private String phone; private Integer amount; public Person(int personid, String name, String phone) { this.id=personid; this.name=name; this.phone=phone; } public Person(String name, String phone) { this.name = name; this.phone = phone; } public String toString() { return "Person [id=" + id + ", name=" + name + ", phone=" + phone + "]"; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } }

package com.zyq.main; import java.util.List; import android.test.AndroidTestCase; import android.util.Log; import com.zyq.service.DBOpenHelper; import com.zyq.service.PersonService; import com.zyq.voo.Person; /** * 测试方法 通过Junit 单元测试 * 1.>实例化测试类 * 2.>把与应用有关的上下文信息传入到测试类实例 * 3.>运行测试方法 * @author Administrator * */ public class PersonServiceTest extends AndroidTestCase { private final static String TAG="PersonServiceTest"; /** * 测试创建数据库 * @throws Throwable */ public void testCreateDB() throws Throwable { DBOpenHelper dbOpenHelper=new DBOpenHelper(this.getContext()); dbOpenHelper.getReadableDatabase(); //Create and/or open a database. } /** * 测试新增一条记录 * @throws Throwable */ public void testSave() throws Throwable { PersonService personService=new PersonService(this.getContext()); personService.save(new Person("","1360215320")); personService.save(new Person("lisi","13563985632")); personService.save(new Person("lili","232")); personService.save(new Person("wangda","123123")); personService.save(new Person("laozhu","234532")); } /** * 查找一条记录 * @throws Throwable */ public void testFind() throws Throwable { PersonService personService=new PersonService(this.getContext()); Person person=personService.find(1); Log.i(TAG,person.toString()); } /** * 测试更新一条记录 * @throws Throwable */ public void testUpdate() throws Throwable { PersonService personService=new PersonService(this.getContext()); Person person=personService.find(1); person.setName("lisi"); personService.update(person); } /** * 测试得到所有记录数 * @throws Throwable */ public void testGetCount() throws Throwable { PersonService personService=new PersonService(this.getContext()); Log.i(TAG, personService.getCount()+"********"); } /** * 测试分页 * @throws Throwable */ public void testScroll() throws Throwable { PersonService personService=new PersonService(this.getContext()); List<Person> persons=personService.getScrollData(0, 30); for(Person person:persons) { Log.i(TAG, person.toString()); } } /** * 测试删除一条记录 * @throws Throwable */ public void testDelete() throws Throwable { PersonService personService=new PersonService(this.getContext()); personService.delete(5); } }

package com.zyq.main; import com.zyq.service.DBOpenHelper; 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; import android.util.Log; public class PersonProvider extends ContentProvider { private static final UriMatcher MATCHER=new UriMatcher(UriMatcher.NO_MATCH); private static final int PERSONS=1; private static final int PERSON=2; private DBOpenHelper helper; static { MATCHER.addURI("com.zyq.providers.personprovider", "person", PERSONS); MATCHER.addURI("com.zyq.providers.personprovider", "person/#", PERSON); } /** * 完成数据的初始化工作 */ public boolean onCreate() { helper=new DBOpenHelper(this.getContext()); return true; } /** * 查询PERSON数据库数据 * /person 代表查询所有的数据 * /person/# 代表查询person表指定ID的数据 */ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteDatabase db=helper.getWritableDatabase(); switch (MATCHER.match(uri)) { case PERSONS: return db.query("person", projection, selection, selectionArgs, null, null, sortOrder); case PERSON: long id=ContentUris.parseId(uri); String where="personid="+id; if(selection!=null && !"".equals(selection.trim())) { where=where+" and "+selection; } return db.query("person", projection, where, selectionArgs, null, null, sortOrder); default: throw new IllegalArgumentException("Unknown Uri:" +uri); } } /** * */ public String getType(Uri uri) { switch (MATCHER.match(uri)) { case PERSONS: return "vnd.android.cursor.dir/person"; case PERSON: return "vnd.android.cursor.item/person"; default: throw new IllegalArgumentException("Unknown Uri:" +uri); } } /** * 往PERSON表添加数据 * /person 为URI */ public Uri insert(Uri uri, ContentValues values) { SQLiteDatabase db=helper.getWritableDatabase(); Log.i("*********", MATCHER.match(uri)+""); switch (MATCHER.match(uri)) { case PERSONS: long rowid=db.insert("person", "personid", values);// return ContentUris.withAppendedId(uri, rowid); default: throw new IllegalArgumentException("Unknown Uri:" +uri); } } /** * 删除PERSON表中的数据 * /person 代表删除所有的数据 * /person/# 代表删除某一条数据 */ public int delete(Uri uri, String selection, String[] selectionArgs) { SQLiteDatabase db=helper.getWritableDatabase(); int num=0; switch (MATCHER.match(uri)) { case PERSONS: num=db.delete("person", selection, selectionArgs); break; case PERSON: long id=ContentUris.parseId(uri); String where="personid="+id; if(selection!=null && !"".equals(selection.trim())) { where=where+" and "+selection; } num=db.delete("person", where, selectionArgs); break; default: throw new IllegalArgumentException("Unknown Uri:" +uri); } return num; } /** * 更新PERSON表中的数据 * /person 代表更新所有的数据 * /person/# 代表更新person表指定ID的数据 */ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { SQLiteDatabase db=helper.getWritableDatabase(); int num=0; switch (MATCHER.match(uri)) { case PERSONS: num=db.update("person", values, selection, selectionArgs); break; case PERSON: long id=ContentUris.parseId(uri); String where="personid="+id; if(selection!=null && !"".equals(selection.trim())) { where=where+" and "+selection; } num=db.update("person", values, where, selectionArgs); break; default: throw new IllegalArgumentException("Unknown Uri:" +uri); } return num; } }

package com.zyq.service; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import com.zyq.voo.Person; public class PersonService { private DBOpenHelper helper; public PersonService(Context context) { helper=new DBOpenHelper(context); } /** * 新增一条记录 * @param person */ public void save(Person person) { SQLiteDatabase db=helper.getWritableDatabase();//Create and/or open a database that will be used for reading and writing db.execSQL("INSERT INTO person(name,phone) values(?,?)",new Object[]{person.getName().trim(),person.getPhone().trim()});//使用占位符进行转译 // db.close(); 不关数据库连接 。可以提高性能 因为创建数据库的时候的操作模式是私有的。 // 代表此数据库,只能被本应用所访问 单用户的,可以维持长久的链接 } /** * 更新某一条记录 * @param person */ public void update(Person person) { SQLiteDatabase db=helper.getWritableDatabase(); db.execSQL("update person set phone=?,name=? where personid=?", new Object[]{person.getPhone().trim(),person.getName().trim(),person.getId()}); } /** * 根据ID查询某条记录 * @param id * @return */ public Person find(Integer id) { SQLiteDatabase db=helper.getReadableDatabase(); Cursor cursor=db.rawQuery("select * from person where personid=?", new String[]{id.toString()});//Cursor 游标和 ResultSet 很像 if(cursor.moveToFirst())//Move the cursor to the first row. This method will return false if the cursor is empty. { int personid=cursor.getInt(cursor.getColumnIndex("personid")); String name=cursor.getString(cursor.getColumnIndex("name")); String phone=cursor.getString(cursor.getColumnIndex("phone")); return new Person(personid,name,phone); } return null; } /** * 删除某一条记录 * @param id */ public void delete(Integer id) { SQLiteDatabase db=helper.getWritableDatabase(); db.execSQL("delete from person where personid=?", new Object[]{id}); } /** * 得到记录数 * @return */ public long getCount() { SQLiteDatabase db=helper.getReadableDatabase(); Cursor cursor=db.rawQuery("select count(*) from person", null); cursor.moveToFirst(); return cursor.getLong(0); } /** * 分页查询方法 SQL语句跟MySQL的语法一样 * @return */ public List<Person> getScrollData(int offset,int maxResult) { List<Person> persons=new ArrayList<Person>(); SQLiteDatabase db=helper.getReadableDatabase(); Cursor cursor=db.rawQuery("select * from person limit ?,?", new String[]{String.valueOf(offset),String.valueOf(maxResult)}); while (cursor.moveToNext()) { int personid=cursor.getInt(cursor.getColumnIndex("personid")); String name=cursor.getString(cursor.getColumnIndex("name")); String phone=cursor.getString(cursor.getColumnIndex("phone")); persons.add(new Person(personid,name,phone)); } return persons; } } <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.zyq.main" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <uses-library android:name="android.test.runner" /> <activity android:name=".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> <provider android:name=".PersonProvider" android:authorities="com.zyq.providers.personprovider"/> </application> <uses-sdk android:minSdkVersion="8" /> <instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.zyq.main" android:label="Tests for My App" /> </manifest>

这是另外一个项目 测试得类

package com.zyq.junit; import android.content.ContentResolver; import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; import android.test.AndroidTestCase; import android.util.Log; import android.webkit.WebChromeClient.CustomViewCallback; public class AccessContentProvider extends AndroidTestCase { private static final String TAG="AccessContentProvider"; /** * 测试内容提供者的 添加数据方法 * @throws Throwable */ public void testInsert() throws Throwable { ContentResolver resolver=this.getContext().getContentResolver(); Uri uri=Uri.parse("content://com.zyq.providers.personprovider/person"); ContentValues values = new ContentValues(); values.put("name", "朱元璋"); values.put("phone", "1356398546"); values.put("amount", 50); resolver.insert(uri, values); } /** * 测试内容提供者的 查找数据方法 * @throws Throwable */ public void testFind() throws Throwable { ContentResolver resolver=this.getContext().getContentResolver(); Uri uri=Uri.parse("content://com.zyq.providers.personprovider/person/1"); Cursor cursor=resolver.query(uri, null, null, null, null); if(cursor.moveToFirst()) { String name=cursor.getString(cursor.getColumnIndex("name")); Log.i(TAG, name+"*******"); } } /** * 测试内容提供者的更新数据方法 * @throws Throwable */ public void testUpdate() throws Throwable { ContentResolver resolver=this.getContext().getContentResolver(); Uri uri=Uri.parse("content://com.zyq.providers.personprovider/person/1"); ContentValues values = new ContentValues(); values.put("name", "中国"); resolver.update(uri, values, null, null); } /** * 测试内容提供者的删除数据方法 * @throws Throwable */ public void testDelete() throws Throwable { ContentResolver resolver=this.getContext().getContentResolver(); Uri uri=Uri.parse("content://com.zyq.providers.personprovider/person/6"); resolver.delete(uri, null, null); } }


 先运行好数据库 定义好 ContentProdvider  用 单元测试 来 测试数据  !

 信息全打印在控制台中


l

你可能感兴趣的:(android,数据库,String,测试,null,Integer)