content provider的使用(15章-Content Providers)

content provider 和content resolver提供了用于各个application之间互相访问数据但又保持独立的机制。android系统已经提供的一些content provider有:Media store, Browser, contact, calendar和call log.

  • content provider 创建步骤

Step #1: 创建SQLite数据库

如果手工创建数据库,要注意下面两点

注意1:在可被访问的表中将命名为_id的column定义为INTEGER PRIMARY KEY AUTOINCREMENT

注意2:在装入表后建立合适的索引并且使用ANALYZE命令


Step#2 创建content URI

例子: 

为stocksymbols表创建两个URI, 第一个用于获取所有数据,第二个用于获取一行数据

content:// com.example.andapp1. provider/stocksymbols 

content:// com.example.andapp1. provider/ stocksymbols/#


Step#3 创建MIME类型

例子:

与上面的URI相对应,一个表格有两个MIME类型

vnd.android.cursor.dir/ stocksymbols 

vnd.android.cursor.item/stocksymbols

与之对应的,在contract class里定义对应的整数,该整数可被方法getType()用于返回MIME类型

private static final int STOCKSYMBOLS_ALL = 1; // All stock symbols 

private static final int STOCKSYMBOLS_ID = 2; // All stock symbols specific ID


Step#4 创建contract class

为每个表创建一个contract class. 这个class包含与表格column名对应的public static final 变量,content URI 和MIME类型。通常,contract class实现BaseColumns 接口


例子:

public final class ContractClassSTOCKSYMBOLS implements BaseColumns { 
// This class should not be instantiated 
private ContractClassSTOCKSYMBOLS() { } 
// Define CONTENT_AUTHORITY 
public static final String CONTENT_AUTHORITY = "com.example.andapp1. provider"; 
// Define BASE_CONTENT_URI as a Uri object 
public static final Uri BASE_CONTENT_URI = Uri.parse(" content://" + CONTENT_AUTHORITY); 
/ Define CONTENT_URI as a Uri object 
public static final Uri CONTENT_URI = Uri.parse(" content://" + CONTENT_AUTHORITY + "/ stocksymbols"); 
// Define CONTENT_TYPE to represent the MIME Type for all rows in the table 
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/ stocksymbols"; 
// Define CONTENT_ITEM_TYPE to represent the MIME Type for an individual row in the table 
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/ stocksymbols"; 
// TABLE COLUMN DEFINITIONS: 
// _ID: Note that BaseColumns automatically brings in _ID set to "_id", 
// so we don't have to do that! 
// STOCK_SYMBOL 
public static final String STOCKSYMBOL = "STOCK_SYMBOL";
...
}

Step#5 创建content provider

创建一个继承自ContentProvider的类. 在这个类里面override delete(), insert(), update(), query(), getType() 和onCreate()方法 . 

例子:

// All stock symbols 
private static final int STOCKSYMBOLS_ALL = 1; 
// All stock symbols specific _ID 
private static final int STOCKSYMBOLS_ID = 2;

// PACKAGE_NAME 
private static final String PACKAGE_NAME = "com.example.andapp1"; 
// CONTENT_AUTHORITY 
private static final String CONTENT_AUTHORITY = "com.example.andapp1. provider";

// UriMatcher used to compare requested content URI with those that are 
// allowed by this content provider. 
UriMatcher umStock = new UriMatcher( UriMatcher.NO_MATCH);

@Override 
public String getType( Uri uri) { 
	String sType = ""; 
	switch( umStock.match( uri)) { 
		case STOCKSYMBOLS_ALL: 
			sType =" vnd.android.cursor.dir/ stocksymbol"; 
			break; 
		case STOCKSYMBOLS_ID: 
			sType =" vnd.android.cursor.item/ stocksymbol/#"; 
			break; 
		default: 
			sType = null; 
			break; 
		} 
		return sType; 
}

public boolean onCreate() { 
	// Add content URIs to the UriMatcher object 
	umStock.addURI( CONTENT_AUTHORITY, "stocksymbols", STOCKSYMBOLS_ALL); 
	umStock.addURI( CONTENT_AUTHORITY, "stocksymbols/#", STOCKSYMBOLS_ID); 

	// Open the database. YOU MAY NEED TO MODIFY THE FIRST PARAMETER!! 
	oSQLiteDB = SQLiteDatabase.openDatabase( "/ data/ data/" + PACKAGE_NAME + "/" + DATABASE_NAME, null, SQLiteDatabase.OPEN_READONLY); 
	return true; 
}

public Cursor query( Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
	String sSQL = ""; 
	String sID = ""; 
	Cursor oCSR = null; 
	
	switch( umStock.match( uri)) { 
		case STOCKSYMBOLS_ALL: 
			sSQL = "SELECT STOCK_SYMBOL, COMPANY_NAME FROM STOCK_SYMBOLS"; 
			if (selection != null) {
				sSQL + = " WHERE " + selection; 
			} 
			oCSR = oSQLiteDB.rawQuery( sSQL, null); 
			break; 
		case STOCKSYMBOLS_ID: 
			sID = uri.getLastPathSegment(); 
			sSQL = "SELECT STOCK_SYMBOL, COMPANY_NAME FROM STOCK_SYMBOLS WHERE _ID = " + sID; 
			oCSR = oSQLiteDB.rawQuery( sSQL, null); 
			break; 
	}			
	
	// resolver is notified!! 
	if (oCSR != null) { 
		oCSR.setNotificationUri( getContext(). getContentResolver(), uri); 
	} 
	
	return oCSR; 
}

...
}


注意:上述例子中query实现使用了SQL statement和rawQuery方法,这种方式存在潜在的SQL安全问题。例如sID可以包含一些恶意的代码从而造成对数据库的损害。Android推荐使用db.insert(), update()和SQLiteQueryBuilder的query()方法进行这些数据库操作。


Step#6 创建权限


权限一般定义:

< package-name>.provider.permission.<permission>

例子:

com.example.andapp1. provider.permission.READ_PROVIDER


Step#7 更新AndroidManifest.xml, 加上<provider>tag

1. 在<uses-sdk>和<application>tag间加入permission定义

< permission android:description ="@ string/ perm_desc" android:label =" Equity Database Read-Only" android:name = "com.example.andapp1.provider.permission.READ_PROVIDER" android:protectionLevel =" normal"/ > 

2. 在< application > tag内加入下面provider 定义

 < provider android:name =". MyContentProviderClass" android:label =" Equity Database Content Provider" android:authorities =" com.example.andapp1. provider" android:readPermission = "com.example.andapp1. provider.permission.READ_PROVIDER" android:syncable =" false"/ >


  • 使用Content Resolver的步骤

第一步:编译安装包含Content Provider的应用

第二步:准备好contract class,最好是打在一个lib里

第三步:创建test 应用,在AndroidManifest的<uses-sdk>和<application>之间加入要使用的访问权限

< uses-permission android:name =" com.example.andapp1. provider.permission.READ_PROVIDER"/ >
第四步:使用Content Resolver访问content provider提供的数据

例子:

  

// content resolver code goes here
ContentResolver oCR_EQDB = getContentResolver(); 

// Create a cursor to the data 
Cursor oCSR = oCR_EQDB.query(ContractClassSTOCKSYMBOLS.CONTENT_URI, 
	new String[] {ContractClassSTOCKSYMBOLS.STOCKSYMBOL, ContractClassSTOCKSYMBOLS.COMPANYNAME}, null, null, null); 
	
	// Show toasts for each of the entries 
	if (oCSR.getCount() > 0) { 
		while( oCSR.moveToNext()) { 
			sStockSymbol = oCSR.getString( oCSR.getColumnIndex( ContractClassSTOCKSYMBOLS.STOCKSYMBOL)); 
			sStockName = oCSR.getString( oCSR.getColumnIndex( ContractClassSTOCKSYMBOLS.COMPANYNAME)); 
			sStock = sStockSymbol + "/" + sStockName; 
			toast = Toast.makeText( getApplicationContext(), sStock, Toast.LENGTH_SHORT); toast.show(); 
		} 
	} 



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值