现在的位置: 首页 > 综合 > 正文

android ContentProvider

2017年10月23日 ⁄ 综合 ⁄ 共 15162字 ⁄ 字号 评论关闭

ContentProvider简介:

ContentProvider(数据提供者)是在应用程序间共享数据的一种接口机制

ContentProvider提供了更为高级的数据共享方法,应用程序可以指定需要共享的数据,而其他应用程序则可以在不知数据来源、路径的情况下,对共享数据进行查询、添加、删除和更新等操作

许多Android系统的内置数据也通过ContentProvider提供给用户使用,例如通讯录、音视频文件和图像文件等
在创建ContentProvider时,需要首先使用数据库、文件系统或网络实现底层存储功能,然后在继承ContentProvider的类中实现基本数据操作的接口函数,包括添加、删除、查找和更新等功能

调用者不能够直接调用ContentProvider的接口函数,而需要使用ContentResolver对象,通过URI间接调用ContentProvider。

使用ContentProvider可以在不同的应用程序之间共享数据。 它为存储和获取数据提供了统一的接口。

ContentProvide对数据进行封装,不用关心数据存储的细节。 

Android系统提供了大量的ContentProvider,允许开发者来操作这些contentprovider所暴露的接口。

系统包:http://developer.android.com/intl/zh-cn/reference/android/provider/package-summary.html

联系人管理的Uri:

ContactsContract.Contacts.CONTENT_URI:管理联系人
ContactsContract.CommonDataKinds.Phone.CONTENT_URI:管理联系人的电话
ContactsContract.CommonDataKinds.Email.CONTENT_URI:管理联系人的E-mail.

多媒体内容管理的Uri:

MediaStore.Audio.Media.EXTERNAL_CONTENT_URI:外部存储器上的音频文件
MediaStore.Audio.Media.INTERNAL_CONTENT_URI:内部存储器上的音频文件
MediaStore.Images.Media.EXTERNAL_CONTENT_URI:外部存储器上的图片文件
MediaStore.Images.Media.INTERNAL_CONTENT_URI:内部存储器上的图片文件
MediaStore.Video.Media.EXTERNAL_CONTENT_URI:外部存储器上的视频文件
MediaStore.Video.Media.INTERNAL_CONTENT_URI:内部存储器上的视频文件


URI的简介:

Uri代表了要操作的数据,它为系统的每一个资源给其一个名字,比方说通话记录。每一个ContentProvider都拥有一个公共的URI,这个URI用于表示这个ContentProvider所提供的数据。


URI的格式 :


A:标准前缀,用来说明一个Content Provider控制这些数据,无法改变的;"content://"

B:URI 的标识,它定义了是哪个Content Provider提供这些数据。对于第三方应用程序,为了保证URI标识的唯一性,它必须是一个完整的、小写的类名。这个标识在元素的 authorities属性中说明:一般是定义该ContentProvider的包.类的名称; "content://hx.android.text.myprovider",这个部分就是ContentProvider的authority.

C:路径,通俗的讲就是你要操作的数据库中表的名字;"content://hx.android.text.myprovider/tablename"

D:如果URI中包含表示需要获取的记录的ID;则就返回该id对应的数据,如果没有ID,就表示返回全部; "content://hx.android.text.myprovider/tablename/#" #表示数据id,动态改变

注意:

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

要操作的数据不一定来自数据库,也可以是文件等他存储方式,如下: 要操作xml文件中contact节点下的name节点,可以构建这样的路径:/contact/name

如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下: Uri uri = Uri.parse("content://com.changcheng.provider.contactprovider/contact")


工具类:UriMatcher :

为了确定该ContentProvider实际能处理的Uri,以及确定每个方法中Uri参数所操作的数据,Android提供了UriMacher工具类,用法如下:   

1.首先把你需要匹配Uri路径全部给注册上(便于ContentProvider判断具体的操作,一般是确定对单个记录操作还是多个记录操作),如:

uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact”, 1);
uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact/#”, 2);

void addUri(String authority,String path,int code):该方法用于向UriMacher对象注册Uri.其中authority和path组合成一个Uri,而code则代表对应的标识码。标识码匹配Uri的类型,需要注册多少个Uri则根据业务需要。

2.注册完需要匹配的Uri后,就可以使用uriMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码.

//如果match()匹配路径,返回匹配码为1
content://com.changcheng.sqlite.provider.contactprovider/contact
//如果match()匹配路径,返回匹配码为2
content://com.changcheng.sqlite.provider.contactprovider/contact/23

int match(Uri uri):根据前面注册的Uri来判断指定Uri对应的标识码。如果找不到匹配的标识码,该方法将会返回-1。

用来解析来自ContentResolver传递过来的Uri则能知道这个Uri具体操作的类型,由uriMatcher.addURI指定,则根据返回的标识码就知道了要操作的类型(一般是确定对单个记录操作还是多个记录操作)


工具类:ContentUris :

ContentUris类用于操作Uri字符串的工具类,它有两个比较实用的方法:

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

ContentProvider的编程方法 :

程序开发人员通过继承ContentProvider类可以创建一个新的数据提供者,过程可以分为三步 :

继承ContentProvider,并重载六个函数

delete():删除数据集,返回被删除的记录条数
insert():添加数据集,返回新插入的记录的Uri
qurey():查询数据集,返回查询得到的Cursor
update():更新数据集,返回被更新的记录条数
onCreate():初始化底层数据集和建立数据连接等工作
getType():返回指定URI的MIME数据类型,
如果URI是单条数据,则返回的MIME数据类型应以vnd.android.cursor.item开头
如果URI是多条数据,则返回的MIME数据类型应以vnd.android.cursor.dir/开头

声明CONTENT_URI,实现UriMatcher

注册ContentProvider

<application android:icon="@drawable/icon" android:label="@string/app_name">
	<provider android:name = ".PeopleProvider"
			android:authorities = "edu.hrbeu.peopleprovider"/>
</application>

属性:

 name:ContentProvider的实现类的类名

    authorities:指定该ContentProvider对应的Uri(域名)

    android:exported:指定该ContentProvider是否允许其他应用调用



ContentResolver的编程方法:

使用ContentProvider是通过Android组件都具有的ContentResolver对象,通过URI进行数据操作

程序开发人员只需要知道URI和数据集的数据格式,则可以进行数据操作,解决不同应用程序之间的数据共享问题

每个Android组件都具有一个ContentResolver对象,获取ContentResolver对象的方法是调用getContentResolver()函数

ContentResolver resolver = getContentResolver();

调用ContentResolver的如下方法:

insert(Uri url,ContentValues values):

delete(Uri url,String where String[] selectionArgs):

update(Uri uri,ContentValues values,String where,String[] selectionArgs):

query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder):


实例代码如下:

ContentProviderDemo:

工具类:(用来暴露给使用者,用作说明文档)

package edu.hrbeu.ContentProviderDemo;

import android.net.Uri;

public class People{
	
	public static final String MIME_DIR_PREFIX = "vnd.android.cursor.dir";
	public static final String MIME_ITEM_PREFIX = "vnd.android.cursor.item";
	public static final String MINE_ITEM = "vnd.hrbeu.people";
	
	public static final String MINE_TYPE_SINGLE = MIME_ITEM_PREFIX + "/" + MINE_ITEM;
	public static final String MINE_TYPE_MULTIPLE = MIME_DIR_PREFIX + "/" + MINE_ITEM;
	
	public static final String AUTHORITY = "edu.hrbeu.peopleprovider";
	public static final String PATH_SINGLE = "people/#";
	public static final String PATH_MULTIPLE = "people";
	public static final String CONTENT_URI_STRING = "content://" + AUTHORITY + "/" + PATH_MULTIPLE;
	public static final Uri  CONTENT_URI = Uri.parse(CONTENT_URI_STRING); 
	
	public static final String KEY_ID = "_id";
	public static final String KEY_NAME = "name";
	public static final String KEY_AGE = "age";
	public static final String KEY_HEIGHT = "height";
}


ContentProvider:

package edu.hrbeu.ContentProviderDemo;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.net.Uri;

public class PeopleProvider extends ContentProvider{
	
	private static final String DB_NAME = "people.db";
	private static final String DB_TABLE = "peopleinfo";
	private static final int DB_VERSION = 1;
	
	private SQLiteDatabase db;
	private DBOpenHelper dbOpenHelper;
	
	private static final int MULTIPLE_PEOPLE = 1;
	private static final int SINGLE_PEOPLE = 2;
	private static final UriMatcher uriMatcher;
	
	static {
		 uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
		 uriMatcher.addURI(People.AUTHORITY, People.PATH_MULTIPLE, MULTIPLE_PEOPLE);
		 uriMatcher.addURI(People.AUTHORITY, People.PATH_SINGLE, SINGLE_PEOPLE);
	}
	
	@Override
	public String getType(Uri uri) {
		switch(uriMatcher.match(uri)){
			case MULTIPLE_PEOPLE:
				return People.MINE_TYPE_MULTIPLE;
			case SINGLE_PEOPLE:
				return People.MINE_TYPE_SINGLE;
			default:
				throw new IllegalArgumentException("Unkown uri:"+uri);
		}
	}
	
	@Override
	public boolean onCreate() {
		Context context = getContext();
		dbOpenHelper = new DBOpenHelper(context, DB_NAME, null, DB_VERSION);
		db = dbOpenHelper.getWritableDatabase();

		if (db == null)
			return false;
		else 
			return true;	
	}

	
	@Override
	public Uri insert(Uri uri, ContentValues values) {
		long id = db.insert(DB_TABLE, null, values);
		if ( id > 0 ){
			Uri newUri = ContentUris.withAppendedId(People.CONTENT_URI, id);
			getContext().getContentResolver().notifyChange(newUri, null);
			return newUri;
		}
		throw new SQLException("Failed to insert row into " + uri);
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		int count = 0;
		switch(uriMatcher.match(uri)){
			case MULTIPLE_PEOPLE:
				count = db.delete(DB_TABLE, selection, selectionArgs);
				break;
			case SINGLE_PEOPLE:
				String segment = uri.getPathSegments().get(1);
				count = db.delete(DB_TABLE, People.KEY_ID + "=" + segment, selectionArgs);
				break;
			default:
				throw new IllegalArgumentException("Unsupported URI:" + uri);
		}
		getContext().getContentResolver().notifyChange(uri, null);
		return count;
	}
	
	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
		qb.setTables(DB_TABLE);
		switch(uriMatcher.match(uri)){
			case SINGLE_PEOPLE:
				qb.appendWhere(People.KEY_ID + "=" + uri.getPathSegments().get(1));
				break;
			default:
				break;
		}
		Cursor cursor = qb.query(db, 
				projection, 
				selection, 
				selectionArgs, 
				null, 
				null, 
				sortOrder);
		cursor.setNotificationUri(getContext().getContentResolver(), uri);
		return cursor;
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		int count;
		switch(uriMatcher.match(uri)){
			case MULTIPLE_PEOPLE:
				count = db.update(DB_TABLE, values, selection, selectionArgs);
				break;
			case SINGLE_PEOPLE:
				String segment = uri.getPathSegments().get(1);
				count = db.update(DB_TABLE, values, People.KEY_ID+"="+segment, selectionArgs);
				break;
			default:
				throw new IllegalArgumentException("Unknow URI:" + uri);	
		}
		getContext().getContentResolver().notifyChange(uri, null);
		return count;
	}
	
	
	  private static class DBOpenHelper extends SQLiteOpenHelper {

		  public DBOpenHelper(Context context, String name, CursorFactory factory, int version) {
		    super(context, name, factory, version);
		  }

		  private static final String DB_CREATE = "create table " + 
		    DB_TABLE + " (" + People.KEY_ID + " integer primary key autoincrement, " +
		    People.KEY_NAME+ " text not null, " + People.KEY_AGE+ " integer," + People.KEY_HEIGHT + " float);";

		  @Override
		  public void onCreate(SQLiteDatabase _db) {
		    _db.execSQL(DB_CREATE);
		  }

		  @Override
		  public void onUpgrade(SQLiteDatabase _db, int _oldVersion, int _newVersion) {		    
		    _db.execSQL("DROP TABLE IF EXISTS " + DB_TABLE);
		    onCreate(_db);
		  }
		}
	  
	 
}


AndroidManifest.xml:

 <application android:icon="@drawable/icon" android:label="@string/app_name">
        <provider android:name = ".PeopleProvider"
    		android:authorities = "edu.hrbeu.peopleprovider"/>
    </application>

ContentResolverDemo:

工具类:

package edu.hrbeu.ContentResolverDemo;

import android.net.Uri;

public class People{
	
	public static final String MIME_DIR_PREFIX = "vnd.android.cursor.dir";
	public static final String MIME_ITEM_PREFIX = "vnd.android.cursor.item";
	public static final String MINE_ITEM = "vnd.hrbeu.people";
	
	public static final String MINE_TYPE_SINGLE = MIME_ITEM_PREFIX + "/" + MINE_ITEM;
	public static final String MINE_TYPE_MULTIPLE = MIME_DIR_PREFIX + "/" + MINE_ITEM;
	
	public static final String AUTHORITY = "edu.hrbeu.peopleprovider";
	public static final String PATH_SINGLE = "people/#";
	public static final String PATH_MULTIPLE = "people";
	public static final String CONTENT_URI_STRING = "content://" + AUTHORITY + "/" + PATH_MULTIPLE;
	public static final Uri  CONTENT_URI = Uri.parse(CONTENT_URI_STRING); 
	
	public static final String KEY_ID = "_id";
	public static final String KEY_NAME = "name";
	public static final String KEY_AGE = "age";
	public static final String KEY_HEIGHT = "height";
}


ContentResolver:

package edu.hrbeu.ContentResolverDemo;


import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class ContentResolverDemo extends Activity {
	
	private EditText nameText;
	private EditText ageText;
	private EditText heightText;
	private EditText idEntry;
	
	private TextView labelView;
	private TextView displayView;
	
	private ContentResolver resolver;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        nameText = (EditText)findViewById(R.id.name);
        ageText = (EditText)findViewById(R.id.age);
        heightText = (EditText)findViewById(R.id.height);
        idEntry = (EditText)findViewById(R.id.id_entry);
        
        labelView = (TextView)findViewById(R.id.label);
        displayView = (TextView)findViewById(R.id.display);
        
        
        
        Button addButton = (Button)findViewById(R.id.add);
        Button queryAllButton = (Button)findViewById(R.id.query_all);      
        Button clearButton = (Button)findViewById(R.id.clear);
        Button deleteAllButton = (Button)findViewById(R.id.delete_all);
        
        Button queryButton = (Button)findViewById(R.id.query);
        Button deleteButton = (Button)findViewById(R.id.delete);
        Button updateButton = (Button)findViewById(R.id.update);
        
        
        addButton.setOnClickListener(addButtonListener); 
        queryAllButton.setOnClickListener(queryAllButtonListener);     
        clearButton.setOnClickListener(clearButtonListener);
        deleteAllButton.setOnClickListener(deleteAllButtonListener);      
        
        queryButton.setOnClickListener(queryButtonListener);
        deleteButton.setOnClickListener(deleteButtonListener);
        updateButton.setOnClickListener(updateButtonListener);
        
        resolver = this.getContentResolver();
           
    }
    
    
    OnClickListener addButtonListener = new OnClickListener() {
		@Override
		public void onClick(View v) {

			ContentValues values = new ContentValues();
			  
			values.put(People.KEY_NAME, nameText.getText().toString());
			values.put(People.KEY_AGE, Integer.parseInt(ageText.getText().toString()));
			values.put(People.KEY_HEIGHT, Float.parseFloat(heightText.getText().toString()));
		    			
			Uri newUri = resolver.insert(People.CONTENT_URI, values);

			labelView.setText("添加成功,URI:" + newUri);

		}	
    };
    
    OnClickListener queryAllButtonListener = new OnClickListener() {
		@Override
		public void onClick(View v) {
			Cursor cursor = resolver.query(People.CONTENT_URI,
					new String[] { People.KEY_ID, People.KEY_NAME, People.KEY_AGE, People.KEY_HEIGHT},
					null, null, null);
			if (cursor == null){
				labelView.setText("数据库中没有数据");
				return;
			}
			labelView.setText("数据库:" + String.valueOf(cursor.getCount()) + "条记录");
			
			String msg = "";
			if (cursor.moveToFirst()){
				do{
					msg += "ID:" + cursor.getInt(cursor.getColumnIndex(People.KEY_ID)) + ",";
					msg += "姓名:" + cursor.getString(cursor.getColumnIndex(People.KEY_NAME))+ ",";
					msg += "年龄:" + cursor.getInt(cursor.getColumnIndex(People.KEY_AGE)) + ", ";
					msg += "身高:" + cursor.getFloat(cursor.getColumnIndex(People.KEY_HEIGHT)) + "\n";
				}while(cursor.moveToNext());
			  }

			displayView.setText(msg);
		}
    };
    
    
    
    OnClickListener clearButtonListener = new OnClickListener() {

		@Override
		public void onClick(View v) {
			displayView.setText("");
		}	
    };
    
    OnClickListener deleteAllButtonListener = new OnClickListener() {
		@Override
		public void onClick(View v) {
			resolver.delete(People.CONTENT_URI, null, null);
			String msg = "数据全部删除" ;
			labelView.setText(msg);
		}	
    };
    
    OnClickListener queryButtonListener = new OnClickListener() {
		@Override 
		public void onClick(View v) {
			Uri uri = Uri.parse(People.CONTENT_URI_STRING + "/" + idEntry.getText().toString());
			Cursor cursor = resolver.query(uri,
					new String[] { People.KEY_ID, People.KEY_NAME, People.KEY_AGE, People.KEY_HEIGHT},
					null, null, null);
			if (cursor == null){
				labelView.setText("数据库中没有数据");
				return;
			}
			
			String msg = "";
			if (cursor.moveToFirst()){
				msg += "ID:" + cursor.getInt(cursor.getColumnIndex(People.KEY_ID)) + ",";
				msg += "姓名:" + cursor.getString(cursor.getColumnIndex(People.KEY_NAME))+ ",";
				msg += "年龄:" + cursor.getInt(cursor.getColumnIndex(People.KEY_AGE)) + ", ";
				msg += "身高:" + cursor.getFloat(cursor.getColumnIndex(People.KEY_HEIGHT)) + "\n";
			  }

			labelView.setText("数据库:");
			displayView.setText(msg);
		}
    };
    
    OnClickListener deleteButtonListener = new OnClickListener() {
		@Override
		public void onClick(View v) {

			Uri uri = Uri.parse(People.CONTENT_URI_STRING + "/" + idEntry.getText().toString());
			int result = resolver.delete(uri, null, null);
			String msg = "删除ID为"+idEntry.getText().toString()+"的数据" + (result>0?"成功":"失败");
			labelView.setText(msg);
		}	
    };
    
    OnClickListener updateButtonListener = new OnClickListener() {
		@Override
		public void onClick(View v) {
			ContentValues values = new ContentValues();
			  
			values.put(People.KEY_NAME, nameText.getText().toString());
			values.put(People.KEY_AGE, Integer.parseInt(ageText.getText().toString()));
			values.put(People.KEY_HEIGHT, Float.parseFloat(heightText.getText().toString()));
		    			
			Uri uri = Uri.parse(People.CONTENT_URI_STRING + "/" + idEntry.getText().toString());
			int result = resolver.update(uri, values, null, null);
			
			String msg = "更新ID为"+idEntry.getText().toString()+"的数据" + (result>0?"成功":"失败");
			labelView.setText(msg);
		}
    };
}

抱歉!评论已关闭.