Content Provider 详解,实例演示

一、ContentProvider简介
       当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据。虽然使用其他方法也可以对外共享数据,但数据访问方式会因数据存储的方式而不同,如:采用文件方式对外共享数据,需要进行文件操作读写数据;采用sharedpreferences共享数据,需要使用sharedpreferences API读写数据。而使用ContentProvider共享数据的好处是统一了数据访问方式。
二、Uri类简介
       Uri代表了要操作的数据,Uri主要包含了两部分信息:1.需要操作的ContentProvider ,2.对ContentProvider中的什么数据进行操作,一个Uri由以下几部分组成:

       1.scheme:ContentProvider(内容提供者)的scheme已经由Android所规定为:content://。
       2.主机名(或Authority):用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。
       3.路径(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、ContentUrist和ContentResolver简介
       因为Uri代表了要操作的数据,所以我们很经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher 和ContentUris 。掌握它们的使用,会便于我们的开发工作。

       UriMatcher:用于匹配Uri,它的用法如下:
       1.首先把你需要匹配Uri路径全部给注册上,如下:
       //常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码(-1)。
       UriMatcher  uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
       //如果match()方法匹配content://com.changcheng.sqlite.provider.contactprovider/contact路径,返回匹配码为1
       uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact”, 1);//添加需要匹配uri,如果匹配就会返回匹配码
       //如果match()方法匹配   content://com.changcheng.sqlite.provider.contactprovider/contact/230路径,返回匹配码为2
       uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact/#”, 2);//#号为通配符
      
       2.注册完需要匹配的Uri后,就可以使用uriMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码,匹配码是调用addURI()方法传入的第三个参数,假设匹配content://com.changcheng.sqlite.provider.contactprovider/contact路径,返回的匹配码为1。

       ContentUris:用于获取Uri路径后面的ID部分,它有两个比较实用的方法:
•         withAppendedId(uri, id)用于为路径加上ID部分

•         parseId(uri)方法用于从路径中获取ID部分

ContentUris类使用介绍

ContentUris类用于操作Uri路径后面的ID部分,它有两个比较实用的方法:
withAppendedId(uri, id)
用于为路径加上ID部分:

Uri uri = Uri.parse("content://com.ljq.provider.personprovider/person")
Uri resultUri = ContentUris.withAppendedId(uri, 10);
//生成后的Uri为:content://com.ljq.provider.personprovider/person/10

parseId(uri)方法用于从路径中获取ID部分:

Uri uri = Uri.parse("content://com.ljq.provider.personprovider/person/10")
long personid = ContentUris.parseId(uri);//获取的结果为:10



       ContentResolver:当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver 类来完成,要获取ContentResolver 对象,可以使用Activity提供的getContentResolver()方法。 ContentResolver使用insert、delete、update、query方法,来操作数据。


ContentProviders实例:

1.创建一个ContentProviderMetaData implements BaseColumns
,建立表结构;

2.BookProvider extends ContentProvider,重写增删改查

创建数据库:创建内部类 private static class DatabaseHelper extends SQLiteOpenHelper 。构造函数DatabaseHelper、重写onCreate(

db.execSQL("CREATE TABLE "))、onUpgrade方法;

3.MainActivity:“getContentResolver().insert()”从而调用ContentProvider的增删改查;

演示的UI如图所示:



最后在控制台的效果如图所示:


一共三个类:

第一个:

BookProviderMetaData

package com.example.bookprovider;

import android.net.Uri;
import android.provider.BaseColumns;
//Planning a database
public class BookProviderMetaData {
	public static final String AUTHORITY = "com.francis.provider.BookProvider";
	
	public static final String DATABASE_NAME = "book.db";
	public static final int DATABASE_VERSION = 1;
	public static final String DATABASE_TABLE_NAME = "books";
	
	private BookProviderMetaData(){}
	//planning a table
	public static final class BookTableMetaData implements BaseColumns{
		//_id is provided by implementing BaseColumns
		public static final String TABLE_NAME = "books";
		public static final Uri CONTENT_URI = Uri.parse("content://"+AUTHORITY+"/books");
		//getType()是时候用到
		//for a collection of records,the MIME type looks like this:
		//"vnd.android.cursor.dir/vnd.yourcompanyname.contenttype";
		public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.francis.books";
		//for a single record,the MIME type looks like this:
		//"vnd.android.cursor.item/vnd.yourcompanyname.contenttype";
		public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.francis.books";
		public static final String DEFAULT_SORT_ORDER = "modified DESC";
		
		//columns start here
		//String type
		public static final String BOOK_NAME = "name";
		//String type
		public static final String BOOK_ISBN = "isbn";
		//String type
		public static final String BOOK_AUTHOR = "author";
		//Integer from System.currentTimerMIlls()
		public static final String CREATED_DATE = "created";
		//Integer from System.currentTimerMIlls()
		public static final String MODIFIED_DATE = "modified";
		
	}
	

}

第一个:

BookProvider:

package com.example.bookprovider;

import java.sql.SQLException;
import java.util.HashMap;

import com.example.bookprovider.BookProviderMetaData.BookTableMetaData;

import android.R.id;
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.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;

public class BookProvider extends ContentProvider {
	private static final String TAG = "BookProviderClass";

	// Setup projection Map
	private static HashMap<String, String> sBooksProjectionMap;
	static {
		sBooksProjectionMap = new HashMap<String, String>();
		// name,isbn,author
		// sBooksProjectionMap.put("nameCallerPassed", nameOfDatabaseColumn);
		sBooksProjectionMap.put(BookTableMetaData.BOOK_NAME, BookTableMetaData.BOOK_NAME);
		sBooksProjectionMap.put(BookTableMetaData.BOOK_ISBN, BookTableMetaData.BOOK_ISBN);
		sBooksProjectionMap.put(BookTableMetaData.BOOK_AUTHOR, BookTableMetaData.BOOK_AUTHOR);
		// created date, motified date
		sBooksProjectionMap.put(BookTableMetaData.CREATED_DATE, BookTableMetaData.CREATED_DATE);
		sBooksProjectionMap.put(BookTableMetaData.MODIFIED_DATE,
				BookTableMetaData.MODIFIED_DATE);
	}

	// Set Uris
	// provide a mechanism to identify all the incoming uri patterns
	private static final UriMatcher sUri_mathcer;
	private static final int INCOMING_BOOK_COLLECTION_URI_INDICATOR = 1;
	private static final int INCOMING_BOOK_SINGLE_BOOK_URI_INDICATOR = 2;
	static {
		sUri_mathcer = new UriMatcher(UriMatcher.NO_MATCH);
		sUri_mathcer.addURI(BookProviderMetaData.AUTHORITY, "books",
				INCOMING_BOOK_COLLECTION_URI_INDICATOR);
		// #match numbers,获取第n条数据使用:
		// new Uri().getPathSegments().get(n);
		// *match any text。
		sUri_mathcer.addURI(BookProviderMetaData.AUTHORITY, "books/#",
				INCOMING_BOOK_SINGLE_BOOK_URI_INDICATOR);
	}

	// Setup Database
	private static class DatabaseHelper extends SQLiteOpenHelper {

		public DatabaseHelper(Context context) {
			super(context, BookProviderMetaData.DATABASE_NAME, null,
					BookProviderMetaData.DATABASE_VERSION);
			// TODO Auto-generated constructor stub
		}

		@Override
		public void onCreate(SQLiteDatabase db) {
			Log.d(TAG, "inner oncreate called");
			db.execSQL("CREATE TABLE "
					+ BookProviderMetaData.DATABASE_TABLE_NAME + " ("
					+ BookTableMetaData._ID + " INTEGER PRIMARY KEY,"
					+ BookTableMetaData.BOOK_NAME + " TEXT,"
					+ BookTableMetaData.BOOK_ISBN + " TEXT,"
					+ BookTableMetaData.BOOK_AUTHOR + " TEXT,"
					+ BookTableMetaData.CREATED_DATE + " INTEGER,"
					+ BookTableMetaData.MODIFIED_DATE + " INTEGER" + ");");
		}

		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
			Log.d(TAG, "inner onupdate called");
			Log.w(TAG, "Upgrade database from version " + oldVersion + " to "
					+ newVersion + ",which will destroy all old data");
			db.execSQL("DROP TABLE IF EXISTS " + BookTableMetaData.TABLE_NAME);
			onCreate(db);
		}
	}

	private DatabaseHelper mOpenHelper;

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		SQLiteDatabase db = mOpenHelper.getWritableDatabase();
		int count;
		switch (sUri_mathcer.match(uri)) {
		case INCOMING_BOOK_COLLECTION_URI_INDICATOR:
			count = db.delete(BookTableMetaData.TABLE_NAME, selection,
					selectionArgs);
			break;
		case INCOMING_BOOK_SINGLE_BOOK_URI_INDICATOR:
			String rowId = uri.getPathSegments().get(1);
			count = db.delete(
					BookTableMetaData.TABLE_NAME,
					BookTableMetaData._ID
							+ "="
							+ rowId
							+ (!TextUtils.isEmpty(selection) ? " AND("
									+ selection + ")" : ""), selectionArgs);
			break;

		default:
			throw new IllegalArgumentException("Unknow URI " + uri);
		}
		getContext().getContentResolver().notifyChange(uri, null);
		return count;
	}

	@Override
	public String getType(Uri uri) {
		switch (sUri_mathcer.match(uri)) {
		case INCOMING_BOOK_COLLECTION_URI_INDICATOR:
			return BookTableMetaData.CONTENT_TYPE;
		case INCOMING_BOOK_SINGLE_BOOK_URI_INDICATOR:
			return BookTableMetaData.CONTENT_ITEM_TYPE;
		default:
			throw new IllegalArgumentException("Unknown Uri " + uri);
		}
	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		Log.d(TAG, "insert()");
		// check the uri whether it is used to insert into a table or, to
		// "inster into a single book" which is wrong
		
		if (sUri_mathcer.match(uri) != INCOMING_BOOK_COLLECTION_URI_INDICATOR) {
			throw new IllegalArgumentException("Unkown URI " + uri);
		}
		// ContentValues存放一个个键值对,用于插入:name-francis;age-23...
		ContentValues contentValues;
		if (values != null) {
			contentValues = values;
		} else {
			contentValues = new ContentValues();
		}
		// insert into name,isbn,author,created_date,motified_date
		// bookname is necessary
		if (contentValues.containsKey(BookTableMetaData.BOOK_NAME) == false) {
			try {
				throw new SQLException(
						"Failed to insert row because book name is needed "
								+ uri);
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		if (contentValues.containsKey(BookTableMetaData.BOOK_ISBN) == false) {
			contentValues.put(BookTableMetaData.BOOK_ISBN, "Unknown ISBN");
		}
		if (contentValues.containsKey(BookTableMetaData.BOOK_AUTHOR) == false) {
			contentValues.put(BookTableMetaData.BOOK_ISBN, "Unknown AUTHOR");
		}
		// Long.valueOf() : return a Long instance for a specified long value
		Long now = Long.valueOf(System.currentTimeMillis());
		if (contentValues.containsKey(BookTableMetaData.CREATED_DATE) == false) {
			contentValues.put(BookTableMetaData.CREATED_DATE, now);
		}
		if (contentValues.containsKey(BookTableMetaData.MODIFIED_DATE) == false) {
			contentValues.put(BookTableMetaData.MODIFIED_DATE, now);
		}
		SQLiteDatabase db = mOpenHelper.getWritableDatabase();
		//如果传入empty row ,(这是不可以的,但如果这么做的话)BOOK_NAME=null
		Long rowId = db.insert(BookTableMetaData.TABLE_NAME,
				BookTableMetaData.BOOK_NAME, contentValues);
		if (rowId > 0) {
			Uri insertedBookUri = ContentUris.withAppendedId(
					BookTableMetaData.CONTENT_URI, rowId);
			getContext().getContentResolver().notifyChange(insertedBookUri,
					null);
			return insertedBookUri;
		}
		try {
			throw new SQLException("Failed to insert row into " + uri);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}// ?return ??
		return uri;
	}

	@Override
	public boolean onCreate() {
		Log.d(TAG, "main oncreate called");
		mOpenHelper = new DatabaseHelper(getContext());
		return true;
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
		switch (sUri_mathcer.match(uri)) {
		case INCOMING_BOOK_COLLECTION_URI_INDICATOR:
			qb.setTables(BookTableMetaData.TABLE_NAME);
			qb.setProjectionMap(sBooksProjectionMap);
			break;
		case INCOMING_BOOK_SINGLE_BOOK_URI_INDICATOR:
			qb.setTables(BookTableMetaData.TABLE_NAME);
			qb.setProjectionMap(sBooksProjectionMap);
			qb.appendWhere(BookTableMetaData._ID + "="
					+ uri.getPathSegments().get(1));
			break;
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}
		String orderBy;
		if (TextUtils.isEmpty(sortOrder)) {
			orderBy = BookTableMetaData.DEFAULT_SORT_ORDER;
		} else {
			orderBy = sortOrder;
		}
		// get the database and run the query
		SQLiteDatabase db = mOpenHelper.getReadableDatabase();
		Cursor cursor = qb.query(db, projection, selection, selectionArgs,
				null, null, orderBy);
		// example of getting a count
		int i = cursor.getCount();
		// tell the cursor what uri to watch so it knows when its source data
		// changes
		cursor.setNotificationUri(getContext().getContentResolver(), uri);
		return cursor;
	}

	// update,delete分两种情况,1.对整个表;2.对表中的一条数据
	// 通过switch (sUri_mathcer.match(uri)) 判断实现
	// 如果是整个表,不需要考虑where与_id是否矛盾(无法根据uri得到_id);如果是一条数据(根据uri得到_id),需要考虑where与_id是否矛盾
	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		SQLiteDatabase db = mOpenHelper.getWritableDatabase();
		int count;
		switch (sUri_mathcer.match(uri)) {
		case INCOMING_BOOK_COLLECTION_URI_INDICATOR:
			count = db.update(BookTableMetaData.TABLE_NAME, values, selection,selectionArgs);
			break;
		case INCOMING_BOOK_SINGLE_BOOK_URI_INDICATOR:
			String rowId =  uri.getPathSegments().get(1);
			count = db.update(BookTableMetaData.TABLE_NAME, values, BookTableMetaData._ID+"="+rowId
					+(!TextUtils.isEmpty(selection)?" AND("+selection+")":""), selectionArgs); 
			break;
		default:
			throw new IllegalArgumentException("Unknown Uri "+uri);
		}
		getContext().getContentResolver().notifyChange(uri, null);
		return count;
	}
}

第三个:

MainActivity:

package com.example.bookprovider;

import javax.security.auth.PrivateCredentialPermission;

import com.example.bookprovider.BookProviderMetaData.BookTableMetaData;

import android.net.Uri;
import android.os.Bundle;
import android.R.string;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity implements OnClickListener {
	private static final String tagString = "Exercise BookProvider";
	private Button addBookButton, removeBookButton, showBookButton;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		findViewById(R.id.addBook).setOnClickListener(this);
		findViewById(R.id.removeBook).setOnClickListener(this);
		findViewById(R.id.showBook).setOnClickListener(this);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	private int getCount(Context context) {
		Uri uri = BookProviderMetaData.BookTableMetaData.CONTENT_URI;
//		Cursor cursor = ((Activity) context).managedQuery(uri, null, null,
//				null, null);
		Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
		int numOfRecords = cursor.getCount();
		return numOfRecords;
	}

	public void addBook(Context context) {
		Log.d(tagString, "Adding a book");
		ContentValues contentValues = new ContentValues();
		contentValues.put(BookTableMetaData.BOOK_NAME, "Pro Android 4");
		contentValues.put(BookTableMetaData.BOOK_ISBN, "sibn9001");
		contentValues.put(BookTableMetaData.BOOK_AUTHOR, "Francis");
		// return a ContentResolver instance for your application's package,so
		// you can interact with ContentProvider
		ContentResolver contentResolver = context.getContentResolver();
		Uri uri = BookProviderMetaData.BookTableMetaData.CONTENT_URI;
		Uri insertedUri = contentResolver.insert(uri, contentValues);
		Log.d(tagString, "insertedUri:" + insertedUri);

	}

	public void removeBook(Context context) {
		Log.d(tagString, "Removing a book");
		int numOfRecords = getCount(context);
		Uri uri = BookTableMetaData.CONTENT_URI;
		Uri delUri = Uri.withAppendedPath(uri, Integer.toString(numOfRecords));
		ContentResolver cr = getContentResolver();
		Log.d(tagString, "delUri:" + delUri);
		cr.delete(delUri, null, null);
	}

	public void showBook(Context context) {
		Log.d(tagString, "Showing a book");
		Uri uri = BookTableMetaData.CONTENT_URI;
		//getContentResolver.query();
		Cursor cursor = ((Activity) context).managedQuery(uri, null, null,
				null, null);
		int name = cursor.getColumnIndex(BookTableMetaData.BOOK_NAME);
		int author = cursor.getColumnIndex(BookTableMetaData.BOOK_AUTHOR);
		int isbn = cursor.getColumnIndex(BookTableMetaData.BOOK_ISBN);
		for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
			String idString = cursor.getString(1);
			String nameString = cursor.getString(name);
			String authorString = cursor.getString(author);
			String isbnString = cursor.getString(isbn);
			StringBuffer stringBuffer = new StringBuffer(idString);
			stringBuffer.append(",").append(nameString).append(",")
					.append(authorString).append(",").append(isbnString);
			Log.d(tagString, stringBuffer.toString());
		}
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.addBook:
			addBook(this);
			break;
		case R.id.removeBook:
			removeBook(this);
			break;
		case R.id.showBook:
			showBook(this);
			break;
		default:
			break;
		}

	}

}

再看看

Manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.bookprovider"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="19"
        android:targetSdkVersion="19" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.bookprovider.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>
        <!-- MetaData中的AUTHORITY -->
        <provider 
            android:name=".BookProvider"
            android:authorities="com.francis.provider.BookProvider">
        </provider>
    </application>

</manifest>







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值