SQLiteOpenHelper和ContentProvider区别

阅读更多
Android中操作数据库主要有两种方法:使用SQLiteOpenHelper 和使用ContentProvider。
(一)使用SQLiteOpenHelper:一个抽象类,用于提供管理数据库版本并维护创建数据库的接口。其子类必须实现onCreate(SQLiteDatabase)和onUpdate(SQLiteDatabase, int, int)方法,也可以实现可选方法onOpen(SQLiteDatabase)。另外,也必须重写父类的构造函数。
如果数据库存在则这个类将负责打开数据库,如果不存在则创建一个新的数据库。当Android检测到你在引用一个旧数据库(根据版本号判断)时,它将调用onUpdate()方法。
1.添加数据:
》实例化一个继承了SQLiteOpenHelper抽象类的类,(例如为events);
》获取SQLiteDatabase对象:SQLiteDatabase db = events.getWritableDatabase();
》定义ContentValues的一个对象用于存储数据:ContentValues values = new ContentValues();
》调用ContentValues的put方法装载数据;
》将数据插入数据库中:db.insertOrThrow(TABLE_NAME, null, values);
其中SQLiteOpenHelper类中的getReadableDatabase()和getWritableDatabase()及close()方法都是同步方法。
顾名思义,如果insertOrThrow()执行失败,它可以抛出一个SQLException类型的异常。无需使用一个throws关键字来声明该异常,因为它是一个RuntimeException,而不是一个检查异常。但是,如果你喜欢,仍然可以在一个try/catch块中处理它,就像处理任何其他异常一样。如果未处理它并且存在一个错误,程序将终止,并将一条回溯信息转储到Android日志中。
2.查询数据:
因为无需因查询而修改数据库,所以可以只调用getReadableDatabase()获得一个只读句柄。
》SQLiteDatabase db = events.getReadableDatabase();
》Cursor cursor = db.query(TABLE_NAME, FROM, null,null,null,null,ORDER_BY);
》startManagingCursor(cursor);
其中startManagerCursor():告诉活动应根据该活动的生命周期来管理光标的生命周期。例如:当活动被暂停时,它将自动停止用光标,然后在活动重启时重新查询该光标。当活动终止时,所有托管的光标都将关闭。
3:数据绑定
用于数据表中存在大量数据的情况下,可以提高程序的运行速度。
如果要将大量的数据显示在View中,并将这些数据追加在一个字符串中,则可能耗尽所有内存。
ListView与Adapter的结合使用。
如果数据源是在XML中定义的一个数组,则使用ArrayAdapter;如果数据源是一个来自于数据库查询的Cursor对象,则使用SimpleCursorAdapter。


public class DatabaseHelper extends SQLiteOpenHelper {
 
//构造,调用父类构造,数据库名字,版本号(传入更大的版本号可以让数据库升级,onUpgrade被调用)
public DatabaseHelper(Context context) {
 super(context, DatabaseConstant.DATABASE_NAME, null,     DatabaseConstant.DATABASE_VERSION);
}
 
//数据库创建时调用,里面执行表创建语句.
@Override
public void onCreate(SQLiteDatabase db) {
 db.execSQL(createVoucherTable());
}
 
//数据库升级时调用,先删除旧表,在调用onCreate创建表.
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
 db.execSQL("DROP TABLE IF EXISTS " + DatabaseConstant.TABLE_NAME);
 onCreate(db);
}
//生成 创建表的SQL语句
private String createVoucherTable() {
 StringBuffer sb = new StringBuffer();
 sb.append(" CREATE TABLE ").append(DatabaseConstant.TABLE_NAME).append("( ").append(“ID”)
   .append(" TEXT PRIMARY KEY, ")
   .append(“USER_ID”).append(" INTEGER, ").append(“SMS_CONTENT”).append(" TEXT ) ");
 return sb.toString();
}
}

继承SQLiteOpenHelper并实现里面的方法.

之后:
//得到数据库助手类
helper = new DatabaseHelper(context);
//通过助手类,打开一个可读写的数据库连接
SQLiteDatabase database = helper.getReadableDatabase();
//查询表中所有记录
database.query(DatabaseConstant.TABLE_NAME, null, null, null, null, null, null);

(二)使用ContentProvider
在Android安全模型中,一个应用程序编写的文件无法被其他任何应用程序所读写。每个程序都有自己的Linux用户ID和数据目录(data/data/包名),以及其受保护的内存空间。Android程序可通过下面两种方式进行彼此间的通信。
1.IPC(Inter-Process Communication,进程间通信):一个进程使用AIDL(接口定义语言)和Ibinder接口声明一个任意的API。调用该API时,将在进程间安全且有效地对参数进行编组,这项先进技术用于对后台Service线程进行远程过程调用。
2.ContentProvider:进程中系统中将它们本身注册为某些数据类型的提供者。请求信息时,Android就会通过一个固定的API调用这些进程,以它们认为合适的方式查询或修改内容。
3.URI格式:content://authority/path/id 
其中:
》content://是标准要求的前缀;
》authority是提供者的名称,建议你使用完全限定包名称,避免出现名称冲突;
》path是提供者内部的一个虚拟目录,用于标识被请求的数据类型;
》id是被请求的特定记录的主键,要请求获得具有特定类型的所有记录,可以省略此参数以及后面的斜杠。
例如:content://org.example.events/events/3
4.实现ContentProvider
ContentProvider是一个类似于Activity的高级对象,需要向系统进行声明。因此,实现ContentProvider的第一步是将其添加到AndroidManifest.xml文件中的标签之前(作为的子标签)。


		
		
			
				
				
			
		

	

android:name是类名,android:authorities是在内容URI中使用的字符串。
根据约定,使用MIME类型中的vnd.example而不是org.example。


import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.util.Log;

public class RegionContentProvider extends ContentProvider{
	private static UriMatcher uriMatcher;
	private static final String AUTHORITY = "cn.eoe.regioncontentprovider";
	private static final int CITIES = 1;
	private static final int CITY_CODE = 2;
	private static final int CITY_NAME = 3;
	private static final int CITIES_IN_PROVINCE = 4;
	private SQLiteDatabase database;

	static{

		uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
		// content://cn.eoe.regioncontentprovider/cities
		uriMatcher.addURI(AUTHORITY, "cities", CITIES);
		//  content://cn.eoe.regioncontentprovider/code/024
		uriMatcher.addURI(AUTHORITY, "code/#", CITY_CODE);
		//  content://cn.eoe.regioncontentprovider/name/北京
		uriMatcher.addURI(AUTHORITY, "name/*", CITY_NAME);
		//  content://cn.eoe.regioncontentprovider/cities_in_province/辽宁
		uriMatcher
				.addURI(AUTHORITY, "cities_in_province/*", CITIES_IN_PROVINCE);

	}

	private SQLiteDatabase openDatabase(){
		try{
			String databaseFilename = "/sdcard/region.db";
			if (!(new File(databaseFilename)).exists()){
				InputStream is = getContext().getResources().getAssets()
						.open("region.db");
				FileOutputStream fos = new FileOutputStream(databaseFilename);
				byte[] buffer = new byte[8192];
				int count = 0;
				while ((count = is.read(buffer)) > 0){
					fos.write(buffer, 0, count);
				}

				fos.close();
				is.close();
			}
			SQLiteDatabase database = SQLiteDatabase.openOrCreateDatabase(
					databaseFilename, null);
			return database;
		}
		catch (Exception e){
			Log.d("error", e.getMessage());
		}
		return null;
	}

	@Override
	public boolean onCreate()
	{
		database = openDatabase();
		return true;
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder){
		Cursor cursor = null;

		switch (uriMatcher.match(uri)){
			case CITIES:

				cursor = database.query("v_cities_province", projection,
						selection, selectionArgs, null, null, sortOrder);
				break;
			case CITY_CODE:
				String cityCode = uri.getPathSegments().get(1);
				if (selection == null)
					selection = "city_code='" + cityCode + "'";
				else
					selection += " and (city_code='" + cityCode + "')";
				cursor = database.query("t_cities", projection, selection,
						selectionArgs, null, null, sortOrder);

				break;
			case CITY_NAME:
				String cityName = uri.getPathSegments().get(1);
				if (selection == null)
					selection = "city_name='" + cityName + "'";
				else
					selection += " and (city_name='" + cityName + "')";
				cursor = database.query("t_cities", projection, selection,
						selectionArgs, null, null, sortOrder);

				break;
			case CITIES_IN_PROVINCE:
				String provinceName = uri.getPathSegments().get(1);
				if (selection == null)
					selection = "province_name='" + provinceName + "'";
				else
					selection += " and (province_name='" + provinceName + "')";
				cursor = database.query("v_cities_province", projection, selection,
						selectionArgs, null, null, sortOrder);				
				break;
			
			default:
				throw new IllegalArgumentException("<" + uri + ">格式不正确.");
		}
		return cursor;

	}

	@Override
	public String getType(Uri uri){
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Uri insert(Uri uri, ContentValues values){
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs){
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs){
		// TODO Auto-generated method stub
		return 0;
	}

}

接下来讲述一下如何使用ContentProvider提供的数据
import android.app.Activity;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.Toast;

public class Main extends Activity
{
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState)
	{  
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
	}
  
	public void onClick_Show_Cities(View view)
	{
		ContentResolver contentResolver = getContentResolver();
		Uri uri = Uri
				.parse("content://cn.eoe.regioncontentprovider/cities");
		Cursor cursor = contentResolver.query(uri, new String[]
		{ "city_code as _id", "city_name", "province_code" }, null, null, null);

		SimpleCursorAdapter simpleCursorAdapter = new SimpleCursorAdapter(this,
				android.R.layout.simple_list_item_1, cursor, new String[]
				{ "city_name" }, new int[]
				{ android.R.id.text1 });

		ListView lvCities = (ListView) findViewById(R.id.lvCities);
		lvCities.setAdapter(simpleCursorAdapter);

		uri = Uri
				.parse("content://cn.eoe.regioncontentprovider/code/024");
		cursor = contentResolver.query(uri, null, null, null, null);
		if (cursor.moveToFirst())
		{
			Toast.makeText(
					this,
					"024:"
							+ cursor.getString(cursor
									.getColumnIndex("city_name")),
					Toast.LENGTH_LONG).show();
		}

		uri = Uri
				.parse("content://cn.eoe.regioncontentprovider/name/沈阳");
		cursor = contentResolver.query(uri, null, null, null, null);
		if (cursor.moveToFirst())
		{
			Toast.makeText(
					this,
					"沈阳:"
							+ cursor.getString(cursor
									.getColumnIndex("city_code")),
					Toast.LENGTH_LONG).show();
		}
	}

	public void onClick_Show_Lining_Cities(View view)
	{
		ContentResolver contentResolver = getContentResolver();
		Uri uri = Uri
				.parse("content://cn.eoe.regioncontentprovider/cities_in_province/辽宁");
		Cursor cursor = contentResolver.query(uri, new String[]
		{ "city_code as _id", "city_name", "province_code" }, null, null,
				"city_code");

		SimpleCursorAdapter simpleCursorAdapter = new SimpleCursorAdapter(this,
				android.R.layout.simple_list_item_1, cursor, new String[]
				{ "city_name" }, new int[]
				{ android.R.id.text1 });

		ListView lvCities = (ListView) findViewById(R.id.lvCities);
		lvCities.setAdapter(simpleCursorAdapter);
	}
}

什么是URI?

将其分为A,B,C,D 4个部分:

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

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

C:路径,URI下的某一个Item,就像网站一样,主网页下包含很多小网页。这里通俗的讲就是你要操作的数据库中表的名      字,或者你也可以自己定义,记得在使用的时候保持一致就ok了;"content://com.android.calendar/calendars"

D:如果URI中包含表示需要获取的记录的ID;则就返回该id对应的数据,如果没有ID,就表示返回全部;                            "content://com.android.calendar/calendars/#" #表示数据id(#代表任意数字)
     "content://com.android.calendar/calendars/*" *来匹配任意文本

UriMatcher:用于匹配Uri,它的用法如下:

     1.首先把你需要匹配Uri路径全部给注册上。
        1.常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码(-1)。 UriMatcher                                       uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        2.如果match()方法匹content://com.android.calendar/calendars路径,返回匹配码为1
       uriMatcher.addURI(“content://com.android.calendar”, “calendars”, 1);
        3.添加需要匹配uri,如果匹配就会返回匹配码 //如果match()方法匹配
 
content://com.android.calendar/calendars/23路径,返回匹配码为2
uriMatcher.addURI(“content://com.android.calendar”, “calendars/#”, 2);

      2.注册完需要匹配的Uri后,就可以使用uriMatcher.match(uri)方法对输入的Uri进行匹配,如果匹
配就返回匹配码,匹配码是调用 addURI()方法传入的第三个参数,假设匹配
content://com.android.calendar/calendars路径,返回的匹配码为1。
       ContentUris:用于获取Uri路径后面的ID部分,它有两个比较实用的方法:
withAppendedId(uri, id)用于为路径加上ID部分
parseId(uri)方法用于从路径中获取ID部分

最后上场一个关于使用content provider使用的附件



  • 15.zip (144.2 KB)
  • 下载次数: 0

你可能感兴趣的:(SQLiteOpenHelper和ContentProvider区别)