android ContentProvider讲解

来源:互联网 发布:海遇软件 编辑:程序博客网 时间:2024/05/16 02:08

ContentProvider讲解

当应用A需要通过contentProvider共享数据时,应按如下顺序进行操作:

一.  定义一个MyProviderextends android.content.ContentProvider并重写里面的onCreate,getType,insert,delete,query,update六个方法。将定义好的MyProvider在manifest.xml中进行声明注册。

 

1. MyProvider中需要定义一个UriMatcher对象,并在其上注册Provider提供的Uri,返回对应的匹配码,若无匹配,则返回-1;具体如下:

public static UriMatcher uriMatcher;static{    uriMatcher= new UriMatcher(UriMatcher.NO_MATCH);    uriMatcher.addURI(AUTHORITY,"user", MATCH_DIR);// 添加需要匹配uri,如果匹配就会返回匹配码,没有匹配的,返回-1    uriMatcher.addURI(AUTHORITY,"user/#", MATCH_ITEM);// 如果match()方法匹配content://com.unj.myprovider/user/230路径,返回匹配码为2}

 2.对于重写的增删查改四个方法,sql语句对应的相应方法的参数参照如下:

/*** select id, name from user where age = ? order by name 对应下面的参数为 * projection = new String{"id","name"}; * selection = "age = ?"; * selectionArgs = new String{"23"}; * sortOrder = "name";*/@Overridepublic Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder)

3. 我们可以根据Uri来添加查询条件:

switch (uriMatcher.match(uri)) {case MATCH_DIR:break;case MATCH_ITEM:long id = ContentUris.parseId(uri);if (selection != null && !"".equals(selection)) {selection += " and ";}selection += " id = " + id;break;default:throw new IllegalArgumentException("Unkonw URI" + uri);}


4. 当增删查改操作使数据发生变化时,可调用如下方法通知调用此ContentProvider的ContentResolver,数据发生了变化。

getContext().getContentResolver().notifyChange(uri, null);//通知,调用此uri的resolver,数据已经发生变化,调用端的ContentObserver会回调onChange方法。

5.如下是我自定义的操纵数据库的一个Provider:MyDBUserProvider.java

package com.androidstudydemo.contentprovider;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;/** * 当应用需要通过ContentProvider对外共享数据时,第一步需要继承ContentProvider并重写下面六个方法 * 第二步需要在AndroidManifest.xml使用<provider>对该ContentProvider进行配置 * 详细参见:http://www.cnblogs.com/linjiqin/archive/2011/05/28/2061396.html *  * @author zkx016 *  */public class MyDBUserProvider extends ContentProvider {public static final String AUTHORITY = "com.unj.myprovider";public static final String TABLE_NAME = "user";public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY+ "/user");public static final int MATCH_DIR = 1;public static final int MATCH_ITEM = 2;MyDBHelper myDBHelper;/** * 该ContentProvider所返回的数据类型定义 */public static final String CONTENT_TYPE_DIR = "vnd.android.cursor.dir/user";// 返回集合类型的数据public static final String CONTENT_TYPE_ITEM = "vnd.android.cursor.item/user";// 返回非集合类型的数据/** * UriMatcher类用于匹配Uri,首先第一步把你需要匹配Uri路径全部给注册上, */public static UriMatcher uriMatcher;static {uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);uriMatcher.addURI(AUTHORITY, "user", MATCH_DIR);// 添加需要匹配uri,如果匹配就会返回匹配码uriMatcher.addURI(AUTHORITY, "user/#", MATCH_ITEM);// 如果match()方法匹配content://com.unj.myprovider/person/230路径,返回匹配码为2}/** * 该方法在ContentProvider创建后就会被调用,Android开机后,ContentProvider在其它应用第一次访问它时才会被创建。 */@Overridepublic boolean onCreate() {myDBHelper = new MyDBHelper(getContext());// 这里的实现,常见前篇关于Sqlite的文章。return true;}/** * 该方法用于返回当前Url所代表数据的MIME类型。 * 如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/开头, * 例如:要得到所有person记录的Uri为content://com.ljq.provider.personprovider/person, * 如果操作的数据不属于集合类型那么返回的MIME类型字符串应该为:"vnd.android.cursor.dir/person"。 * 如果要操作的数据属于非集合类型数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头, */@Overridepublic String getType(Uri uri) {switch (uriMatcher.match(uri)) {// 进行匹配case MATCH_DIR:return CONTENT_TYPE_DIR;case MATCH_ITEM:return CONTENT_TYPE_ITEM;default:throw new IllegalArgumentException("Unknown URI" + uri);}}/** * 该方法用于供外部应用往ContentProvider添加数据。 */@Overridepublic Uri insert(Uri uri, ContentValues values) {int type = uriMatcher.match(uri);if (type != MATCH_DIR) {throw new IllegalArgumentException("Unknown URI:" + uri);}SQLiteDatabase db = myDBHelper.getWritableDatabase();long rowId = db.insert(TABLE_NAME, null, values);// 返回的是受影响的那一行的行号,出错时返回-1;if (rowId > 0) {/** * withAppendedId(uri, id)用于为路径加上ID部分, * 生成后的Uri为:content://com.unj.myprovider/person/10 */Uri noteUri = ContentUris.withAppendedId(CONTENT_URI, rowId);/** * 如果ContentProvider的访问者需要知道ContentProvider中的数据发生变化, * 可以在ContentProvider发生数据变化时调用getContentResolver().notifyChange(uri, * null)来通知注册在此URI上的访问者, */getContext().getContentResolver().notifyChange(uri, null);db.close();return noteUri;} else {db.close();throw new IllegalArgumentException("Failed to insert row into"+ uri);}}@Overridepublic int delete(Uri uri, String selection, String[] selectionArgs) {SQLiteDatabase db = myDBHelper.getWritableDatabase();switch (uriMatcher.match(uri)) {case MATCH_DIR:break;case MATCH_ITEM:long id = ContentUris.parseId(uri);if (selection != null && !"".equals(selection)) {selection += " and ";}selection += " id = " + id;break;default:throw new IllegalArgumentException("Unkonw URI" + uri);}int rows = db.delete(TABLE_NAME, selection, selectionArgs);if (rows > 0) {getContext().getContentResolver().notifyChange(uri, null);db.close();return rows;} else {db.close();throw new IllegalArgumentException("Failed to delete row in" + uri);}}/** * select id, name from user where age = ? order by name 对应下面的参数为 projection * = new String{"id","name"}; selection = "age = ?"; selectionArgs = new * String{"23"}; sortOrder = "name"; */@Overridepublic Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) {switch (uriMatcher.match(uri)) {case MATCH_DIR:// tableName = uri.getLastPathSegment();break;case MATCH_ITEM:long id = ContentUris.parseId(uri);if (selection != null && !"".equals(selection)) {selection += " and ";}selection += "id = " + id;break;default:throw new IllegalArgumentException("Unkonw URI" + uri);}SQLiteDatabase db = myDBHelper.getReadableDatabase();Cursor cursor = db.query(TABLE_NAME, projection, selection,selectionArgs, null, null, sortOrder);cursor.setNotificationUri(getContext().getContentResolver(), uri);// @1return cursor;}@Overridepublic int update(Uri uri, ContentValues values, String selection,String[] selectionArgs) {switch (uriMatcher.match(uri)) {case MATCH_DIR:break;case MATCH_ITEM:long id = ContentUris.parseId(uri);if (selection != null && !"".equals(selection)) {selection += " and ";}selection += "id = " + id;break;default:throw new IllegalArgumentException("Unkonw URI" + uri);}SQLiteDatabase db = myDBHelper.getWritableDatabase();int rowsAffected = db.update(TABLE_NAME, values, selection,selectionArgs);//返回受影响的行数db.close();if (rowsAffected > 0) {getContext().getContentResolver().notifyChange(CONTENT_URI, null);// @2return rowsAffected;}return 0;}}


6.MyProvider定义完成之后,需要在manifest.xml中进行Provider的注册,具体在<application></application>内部:

<!-- 自定义contentProvider-->       <provider           android:name="com.androidstudydemo.contentprovider.MyDBUserProvider"           android:authorities="com.unj.myprovider" >       </provider>


 

二. 在其他应用(B)中可以对应的通过Context获得ContentResolver,ContentResolver里面有和ContentProvider相对应的增删查改四个方法,在B应用中直接调用contentResolver.insert()等方法就会获得A应用中提供的数据,B在调用时必须保证A应用同时在运行。


1. 新建一个android project,声明自己需要数据的Uri和authority:

public static final String AUTHORITY = "com.unj.myprovider";public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY+ "/user");

2.定义一个ContentObserver,重写里面的onChange(boolean selfChange, Uri uri)方法,它的作用是当Provider里面对应的Uri数据发生变化,此方法将会被回调。

private ContentObserver contentObserver = new ContentObserver(handler) {public void onChange(boolean selfChange, Uri uri) {Toast.makeText(MainActivity.this, "数据发生改变, uri is:" + uri,Toast.LENGTH_SHORT).show();queryClick();};};

3,在应用中通过getContext().getContentResolver() 获得ContentResolver,并注册ContentObserver

<span style="white-space:pre"></span>resolver = getContentResolver();/** * 如果ContentProvider的访问者需要得到数据变化通知,必须使用ContentObserver对数据(数据采用uri描述)进行监听 * ,当监听到数据变化通知时,系统就会调用ContentObserver的onChange()方法 */resolver.registerContentObserver(CONTENT_URI, false, contentObserver);
4. 如下是我自定义的Bproject,用来测试上方的Provider:

package com.example.providertest;import android.app.Activity;import android.content.ContentResolver;import android.content.ContentUris;import android.content.ContentValues;import android.database.ContentObserver;import android.database.Cursor;import android.net.Uri;import android.os.Bundle;import android.os.Handler;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;import android.widget.Toast;public class MainActivity extends Activity implements OnClickListener {public static final String AUTHORITY = "com.unj.myprovider";public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY+ "/user");private ContentResolver resolver;private TextView textView;private Button query;private int id = 0;Handler handler = new Handler();private ContentObserver contentObserver = new ContentObserver(handler) {public void onChange(boolean selfChange, Uri uri) {Toast.makeText(MainActivity.this, "数据发生改变, uri is:" + uri,Toast.LENGTH_SHORT).show();queryClick();};};@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);query = (Button) this.findViewById(R.id.button2);resolver = getContentResolver();/** * 如果ContentProvider的访问者需要得到数据变化通知,必须使用ContentObserver对数据(数据采用uri描述)进行监听 * ,当监听到数据变化通知时,系统就会调用ContentObserver的onChange()方法 */resolver.registerContentObserver(CONTENT_URI, false, contentObserver);textView = (TextView) findViewById(R.id.textView1);}public Uri insertClick() {ContentValues values = new ContentValues();values.put("id", id);values.put("name", "喻文杰" + id);Uri uri = resolver.insert(CONTENT_URI, values);id++;return uri;}public void deleteClick() {Cursor cursor = resolver.query(CONTENT_URI, null, null, null, null);int count = cursor.getColumnCount();if (count > 0 && cursor.moveToLast()) {int id = resolver.delete(CONTENT_URI, "id = ?",new String[] { cursor.getInt(cursor.getColumnIndex("id"))+ "" });} else {Toast.makeText(MainActivity.this, "删除失败",Toast.LENGTH_SHORT).show();}}public void updateClick() {Cursor cursor = resolver.query(CONTENT_URI, null, null, null, null);if (cursor.moveToFirst()) {ContentValues values = new ContentValues();int id = cursor.getInt(cursor.getColumnIndex("id"));values.put("name", "胡锦涛" + id);Uri uri = ContentUris.withAppendedId(CONTENT_URI, id);int result = resolver.update(uri, values, "", null);}if (!cursor.isClosed()) {cursor.close();}}public void queryClick() {textView.setText("");Cursor cursor = resolver.query(CONTENT_URI, null, null, null, null);while (cursor.moveToNext()) {textView.append("id : "+ cursor.getInt(cursor.getColumnIndex("id")) + "     ");textView.append("name : "+ cursor.getString(cursor.getColumnIndex("name")) + "\n");}if (!cursor.isClosed()) {cursor.close();}textView.append("getAuthority:" + CONTENT_URI.getAuthority()+ " \n********\n getEncodedAuthority:"+ CONTENT_URI.getEncodedAuthority()+ " \n********\n getEncodedFragment:"+ CONTENT_URI.getEncodedFragment()+ " \n********\ngetEncodedPath: "+ CONTENT_URI.getEncodedPath() + " \n********\ngetHost: "+ CONTENT_URI.getHost() + " \n********\ngetLastPathSegment: "+ CONTENT_URI.getLastPathSegment() + " \n********\ngetPath: "+ CONTENT_URI.getPath() + " \n********\ngetPort: "+ CONTENT_URI.getPort() + " \n********\ngetQuery: "+ CONTENT_URI.getQuery() + " \n********\ngetScheme: "+ CONTENT_URI.getScheme() + " \n********\ngetUserInfo: "+ CONTENT_URI.getUserInfo() + "\n********\n");}@Overridepublic void onClick(View arg0) {switch (arg0.getId()) {case R.id.button1:// 增insertClick();break;case R.id.button3:// 删deleteClick();break;case R.id.button2:// 查queryClick();break;case R.id.button4:// 改updateClick();break;default:break;}}}




0 0