android中ContentProvider学习心得

ContentProvider-内容提供者是android中四大组件之一,可见是比较重要的。他可以在不同app之间(进程之间)提供数据共享,且可以进行增删改查,当然在自己进程里也同样可以的。要实现数据共享,必定离不开ContentResolver-内容解决者。ContentProvider内部实现了增删改查的方法,并向外提供了若干个URI;ContentResolver也有增删改查方法,各方法都需传入URI,通过URI就可以找到正确的ContentProvider,并执行对应的方法。

自定义内容提供者,需继承ContentProvider抽象类,并重写增删改查方法,其中数据需要保存到数据库中,必定需要用到SQLite数据库,android创建数据库一般都用SQLiteOpenHelper。以下是测试代码,TestContentProvider.java:

package com.test.contprovider;

import java.util.ArrayList;

import android.content.ContentProvider;
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.OperationApplicationException;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import android.text.TextUtils;

public class TestContentProvider extends ContentProvider {
	
	/*外部通过这个类拿URI及相关字段等常量*/
	public static class TestWords{
		
		/*内容提供者主机头,全局唯一,要跟AndroidMainifast.xml注册的一致*/
		public static final String AUTHORITY = "com.test.content.provider";
		
		/*外部调用时的URI*/
		public static final Uri CONTENT_ALL_URI = Uri.parse("content://"+AUTHORITY+"/all");
		public static final Uri CONTENT_ONE_URI = Uri.parse("content://"+AUTHORITY+"/one");
		
		 
		/*数据库表字段*/
		public static final String COLUMN_ID = "_id";
		public static final String COLUMN_WORD = "word";
		
	}
	
	private TestSQLiteOpenHelper sqlhelper;
	private String TABLE = "words";
	
	/*URI匹配器,检查外部调用的是哪个URI*/
	private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
	private static int ALL = 1;
	private static int ONE = 2;
	
	static{
		matcher.addURI(TestWords.AUTHORITY, "all", ALL);
		/* ‘#’号代表可以是任意数字,通常是_id字段值 */
		matcher.addURI(TestWords.AUTHORITY, "one/#", ONE);
	}
	
	@Override
	public boolean onCreate() {
		/*创建数据库words.db*/
		sqlhelper = new TestSQLiteOpenHelper(getContext(), "words.db", null,1);
		
		return true ;
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		SQLiteDatabase db
		= sqlhelper.getWritableDatabase();
		
		//匹配uri
		if(matcher.match(uri)==ALL){
			return db.query(TABLE, projection, selection, selectionArgs, null, null, sortOrder);
		}else if(matcher.match(uri)==ONE){
			long _id = ContentUris.parseId(uri);
			//设置查询条件
			String where = TestWords.COLUMN_ID +"=" + _id + " ";
			if(!TextUtils.isEmpty(selection)){
				where+=selection;
			}
			return db.query(TABLE, projection, where, selectionArgs, null, null, sortOrder);
			
		}
		return null;
	}

	@Override
	public String getType(Uri uri) {
		//…………
		return null;
	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		SQLiteDatabase db = sqlhelper.getWritableDatabase();
		long _id = db.insert(TABLE, "_id", values);
		if(_id>0){
			uri = ContentUris.withAppendedId(uri, _id);
			//通知内容解决者,数据发生改变
			getContext().getContentResolver().notifyChange(uri, null);
			return uri;
		}
		return null;
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		//…………
		return 0;
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		//…………
		return 0;
	}
	
	/*批量更新,可以提高执行效率,可以跟进源码父类applyBatch方法没有进行事务处理
	 *为了保正操作一致性,可以重写该方法,加上事务处理 
	 */
	@Override 
	public ContentProviderResult[] applyBatch(ArrayList operations) 
	            throws OperationApplicationException{ 
          SQLiteDatabase db = sqlhelper.getWritableDatabase(); 
          //开始事务 
          db.beginTransaction();
          try{ 
	           ContentProviderResult[] results = super.applyBatch(operations); 
	           //设置事务标记为successful 
	           db.setTransactionSuccessful();
	           return results; 
          }finally { 
        	  //结束事务 
              db.endTransaction();
          } 
	} 


	
	public class TestSQLiteOpenHelper extends SQLiteOpenHelper{

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

		@Override
		public void onCreate(SQLiteDatabase db) {
			 /*创建表words,字段两个:_id , word */
			 String sql = "create table words(_id integer primary key autoincrement,word text) ";
			 db.execSQL(sql);
		}

		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
			
		}
		
	}

}
android四大组件都需要在AndroidManifest.xml中注册,当然ContentProvider也不例外。


        
简单的注册如上就可以了。当然了注册时还牵涉到访问权限的问题,还需待进一步研究。

内容解决者可以对感兴趣的内容提供者进行监听,当有数据发生改变时,可以收到通知,当然了这需要内容提供者发送通知才行 getContext().getContentResolver().notifyChange(uri, null);

注册收到通知代码如下:

		getContentResolver().registerContentObserver(
				TestWords.CONTENT_ONE_URI, true, 
				new ContentObserver(handler) {

					@Override
					public boolean deliverSelfNotifications() {
						System.out.println("--------deliverSelfNotification-----");
						return super.deliverSelfNotifications();
					}

					@Override
					public void onChange(boolean selfChange) {
						System.out.println("--------onChange-----"+selfChange);
						super.onChange(selfChange);
					}

					@Override
					public void onChange(boolean selfChange, Uri uri) {
						super.onChange(selfChange, uri);
						System.out.println("--------onChange-----"+selfChange+","+uri);
					}
					
		});


内容解决者可以访问内容提供者暴露出来的URI,进行数据共享操作。在Activity中获取ContentResolver:

ContentResolver cr = getContentResolver();
		/*非自己进程写入URI*/
		//Uri uri = Uri.parse("content://com.test.content.provider/all");
		/*自己进程中获取URI*/
		Uri uri = TestWords.CONTENT_ALL_URI;
		
		Cursor cursor = cr.query(uri, null,  null, null, null);
		


批量操作的话,可以使用操作列表:

void batchAdd(){
		ArrayList ops = new ArrayList();
		    
		ops.add(ContentProviderOperation.newInsert(TestWords.CONTENT_ONE_URI)
		    .withValue(TestWords.COLUMN_WORD, "one")
		    .build());
		ops.add(ContentProviderOperation.newInsert(TestWords.CONTENT_ONE_URI)
				.withValue(TestWords.COLUMN_WORD, "two")
				.build());
		ops.add(ContentProviderOperation.newInsert(TestWords.CONTENT_ONE_URI)
				.withValue(TestWords.COLUMN_WORD, "three")
		    		.build());
		   
		ContentResolver cr = getContentResolver();
		try {
			ContentProviderResult[] cpr = cr.applyBatch(TestWords.AUTHORITY, ops);
			
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (OperationApplicationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	        
	}



你可能感兴趣的:(android,android开发,ContentProvider,ContentRelover,UriMatcher)