应用和应用之间的数据通常都不是孤立的,每个应用都需要与其他的应用来交换数据,例如,我们安装在手机上的安全软件提供了来电防火墙的功能,这个时候安全软件通常会需要访问我们手机自带通信录中数据。在android中采用了ContentProvider(内容提供者)这一组件实现不用应用之间数据的共享,这种数据的共享包括了不同的数据类型。一个应用程序可以通过ContentProvider来对外提供自己的数据,同时可以通过ContentResolver来操作其他应用内容提供者提供的数据。

作为android的四大组件之一,ContentProvider也需要在项目清单文件中进行配置


<provider android:name="com.example.database.MyContentProvider" android:authorities="com.example.dbapp"/>


第一个属性比较好理解,就是我们自己定义的内容提供者实现类,这个实现类需要放在应用所在包或者其子包下面,第二个参数参数指定了其他应用访问我这个内容提供者的标志,可以这样理解,www.sina.com.cn/index.html中的www.sina.com.cn指定我们访问的地址是新浪一样,authorities属性指定了访问自定义内容提供者的地址。

自己定义的内容提供者需要继承ContentProvider这个父类,同时需要重写其中的方法。其中的增删改查方法都需要我们自己根据具体的业务逻辑来实现,onCreate方法是在自定义的内容提供者被创建的时候由系统自动的调用。


package com.example.database;

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 MyContentProvider extends ContentProvider {
	private DBOpenHelper dbhelper;

	private static final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
	private static final String URI = "com.example.dbapp";
	
	/*
	 * 两个变量分别用来标示uri的匹配模式,一种是匹配所有的数据,一种是标示匹配单个数据。
	 *对外提供两种uri形式,满足不同操作
	 */
	
	private static final int PERSONS = 1;  
	private static final int PERSON = 2 ;
	
	static {
		matcher.addURI(URI, "person", PERSONS);
		matcher.addURI(URI, "person/#", PERSON);
		
	}
	
	@Override
	public boolean onCreate() {
	
		dbhelper = new DBOpenHelper(this.getContext());
		
		return true;
	}
	
	/*
	 *下面的四个方法分别实现了对contacts数据库中person表的增删改查 
	 * 
	 */
	
	
	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
	
		SQLiteDatabase db = dbhelper.getWritableDatabase();
		
		switch(matcher.match(uri)){
		case 1:
			Cursor cursor = db.query("person", null, null, null, null, null,null);
			return cursor;
		case 2:
			Cursor cursor2 = db.query("person", projection, selection, selectionArgs, null, null, sortOrder);
			return cursor2;
		}
		return null;
	}

	@Override
	public String getType(Uri uri) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		// TODO Auto-generated method stub
		SQLiteDatabase db = dbhelper.getWritableDatabase();
		switch(matcher.match(uri)){
		case 1 :
			db.execSQL("insert into person values(?,?)", new String[]{values.getAsString("name"),values.getAsString("phone")});
			break;
		default :
			throw new IllegalArgumentException(uri+ "无法匹配");
		}
		return null;
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		SQLiteDatabase db = dbhelper.getWritableDatabase();
		switch(matcher.match(uri)){
			case 1:
				int count = db.delete("person", selection, selectionArgs);
				return count;
			case 2:
				long id  = ContentUris.parseId(uri);
				  db.delete("person","person="+id + "and"+ selection, selectionArgs);
				break;
		}
		return 0;
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		
		SQLiteDatabase db = dbhelper.getWritableDatabase();
		switch(matcher.match(uri)){
			case 1:
			long count = db.update("person", values, null, null);
			return (int)count;
		
			case 2:
			long count2 =db.update("person", values, selection, selectionArgs);
			return (int)count2;
		}
		return 0;
	}
}

在完成了自定义的内容提供者之后,我们可以在其他的应用中完成对这个应用中数据的操作,下面是在hello应用中,通过单元测试的方法来完成对com.example.dbapp应用数据的增删改查


package com.example.test;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.test.AndroidTestCase;
import android.util.Log;

public class MyContentProviderTest extends AndroidTestCase {

	public void testInsert(){
		Uri uri = Uri.parse("content://com.example.dbapp/person");
		for(int i = 0;i<20 ; i++){
		ContentValues values = new ContentValues();
		values.put("name", "zhangsan"+i);
		values.put("phone", "130xxxxxxxx");
		this.getContext().getContentResolver().insert(uri, values);
		}
		
	}
	
	
	public void testDelete(){
		Uri uri = Uri.parse("content://com.example.dbapp/person");
		this.getContext().getContentResolver().delete(uri, null,null);//两个参数都为空表示删除所有的数据
	}
	
	public void testQuery(){
		Uri uri = Uri.parse("content://com.example.dbapp/person");
		Cursor cursor = this.getContext().getContentResolver().query(uri, new String []{"name"}, null, null, "order by name asc");
		while(cursor.moveToNext()){
			Log.i("PersonName",cursor.getString(cursor.getColumnIndex("name")));
		}
	}
	
	public void testUpdate(){
		Uri uri = Uri.parse("content://com.example.dbapp/person/15");
		ContentValues values = new ContentValues();
		values.put("phone", "131xxxxxxxx");
		this.getContext().getContentResolver().update(uri, values,"name=?", new String[]{"zhangsan0"});
	}
}


这样我们就通过内容提供者完成了一个应用对另一个应用数据的操作。