背景:
阅读新闻

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。 


Java代码  收藏代码
  1. public class DatabaseHelper extends SQLiteOpenHelper {  
  2.    
  3. //构造,调用父类构造,数据库名字,版本号(传入更大的版本号可以让数据库升级,onUpgrade被调用)  
  4. public DatabaseHelper(Context context) {  
  5.  super(context, DatabaseConstant.DATABASE_NAME, null,     DatabaseConstant.DATABASE_VERSION);  
  6. }  
  7.    
  8. //数据库创建时调用,里面执行表创建语句.  
  9. @Override  
  10. public void onCreate(SQLiteDatabase db) {  
  11.  db.execSQL(createVoucherTable());  
  12. }  
  13.    
  14. //数据库升级时调用,先删除旧表,在调用onCreate创建表.  
  15. @Override  
  16. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {  
  17.  db.execSQL("DROP TABLE IF EXISTS " + DatabaseConstant.TABLE_NAME);  
  18.  onCreate(db);  
  19. }  
  20. //生成 创建表的SQL语句  
  21. private String createVoucherTable() {  
  22.  StringBuffer sb = new StringBuffer();  
  23.  sb.append(" CREATE TABLE ").append(DatabaseConstant.TABLE_NAME).append("( ").append(“ID”)  
  24.    .append(" TEXT PRIMARY KEY, ")  
  25.    .append(“USER_ID”).append(" INTEGER, ").append(“SMS_CONTENT”).append(" TEXT ) ");  
  26.  return sb.toString();  
  27. }  
  28. }  

继承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文件中的<activity>标签之前(作为<application>的子标签)。 

Java代码  收藏代码
  1. <application android:icon="@drawable/icon" android:label="@string/app_name">  
  2.         <provider android:name="RegionContentProvider"  
  3.             android:authorities="cn.eoe.regioncontentprovider" />  
  4.         <activity android:name=".Main" android:label="@string/app_name">  
  5.             <intent-filter>  
  6.                 <action android:name="android.intent.action.MAIN" />  
  7.                 <category android:name="android.intent.category.LAUNCHER" />  
  8.             </intent-filter>  
  9.         </activity>  
  10.   
  11.     </application>  

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


Java代码  收藏代码
  1. import java.io.File;  
  2. import java.io.FileOutputStream;  
  3. import java.io.InputStream;  
  4.   
  5. import android.content.ContentProvider;  
  6. import android.content.ContentValues;  
  7. import android.content.UriMatcher;  
  8. import android.database.Cursor;  
  9. import android.database.sqlite.SQLiteDatabase;  
  10. import android.net.Uri;  
  11. import android.util.Log;  
  12.   
  13. public class RegionContentProvider extends ContentProvider{  
  14.     private static UriMatcher uriMatcher;  
  15.     private static final String AUTHORITY = "cn.eoe.regioncontentprovider";  
  16.     private static final int CITIES = 1;  
  17.     private static final int CITY_CODE = 2;  
  18.     private static final int CITY_NAME = 3;  
  19.     private static final int CITIES_IN_PROVINCE = 4;  
  20.     private SQLiteDatabase database;  
  21.   
  22.     static{  
  23.   
  24.         uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);  
  25.         // content://cn.eoe.regioncontentprovider/cities  
  26.         uriMatcher.addURI(AUTHORITY, "cities", CITIES);  
  27.         //  content://cn.eoe.regioncontentprovider/code/024  
  28.         uriMatcher.addURI(AUTHORITY, "code/#", CITY_CODE);  
  29.         //  content://cn.eoe.regioncontentprovider/name/北京  
  30.         uriMatcher.addURI(AUTHORITY, "name/*", CITY_NAME);  
  31.         //  content://cn.eoe.regioncontentprovider/cities_in_province/辽宁  
  32.         uriMatcher  
  33.                 .addURI(AUTHORITY, "cities_in_province/*", CITIES_IN_PROVINCE);  
  34.   
  35.     }  
  36.   
  37.     private SQLiteDatabase openDatabase(){  
  38.         try{  
  39.             String databaseFilename = "/sdcard/region.db";  
  40.             if (!(new File(databaseFilename)).exists()){  
  41.                 InputStream is = getContext().getResources().getAssets()  
  42.                         .open("region.db");  
  43.                 FileOutputStream fos = new FileOutputStream(databaseFilename);  
  44.                 byte[] buffer = new byte[8192];  
  45.                 int count = 0;  
  46.                 while ((count = is.read(buffer)) > 0){  
  47.                     fos.write(buffer, 0, count);  
  48.                 }  
  49.   
  50.                 fos.close();  
  51.                 is.close();  
  52.             }  
  53.             SQLiteDatabase database = SQLiteDatabase.openOrCreateDatabase(  
  54.                     databaseFilename, null);  
  55.             return database;  
  56.         }  
  57.         catch (Exception e){  
  58.             Log.d("error", e.getMessage());  
  59.         }  
  60.         return null;  
  61.     }  
  62.   
  63.     @Override  
  64.     public boolean onCreate()  
  65.     {  
  66.         database = openDatabase();  
  67.         return true;  
  68.     }  
  69.   
  70.     @Override  
  71.     public Cursor query(Uri uri, String[] projection, String selection,  
  72.             String[] selectionArgs, String sortOrder){  
  73.         Cursor cursor = null;  
  74.   
  75.         switch (uriMatcher.match(uri)){  
  76.             case CITIES:  
  77.   
  78.                 cursor = database.query("v_cities_province", projection,  
  79.                         selection, selectionArgs, nullnull, sortOrder);  
  80.                 break;  
  81.             case CITY_CODE:  
  82.                 String cityCode = uri.getPathSegments().get(1);  
  83.                 if (selection == null)  
  84.                     selection = "city_code='" + cityCode + "'";  
  85.                 else  
  86.                     selection += " and (city_code='" + cityCode + "')";  
  87.                 cursor = database.query("t_cities", projection, selection,  
  88.                         selectionArgs, nullnull, sortOrder);  
  89.   
  90.                 break;  
  91.             case CITY_NAME:  
  92.                 String cityName = uri.getPathSegments().get(1);  
  93.                 if (selection == null)  
  94.                     selection = "city_name='" + cityName + "'";  
  95.                 else  
  96.                     selection += " and (city_name='" + cityName + "')";  
  97.                 cursor = database.query("t_cities", projection, selection,  
  98.                         selectionArgs, nullnull, sortOrder);  
  99.   
  100.                 break;  
  101.             case CITIES_IN_PROVINCE:  
  102.                 String provinceName = uri.getPathSegments().get(1);  
  103.                 if (selection == null)  
  104.                     selection = "province_name='" + provinceName + "'";  
  105.                 else  
  106.                     selection += " and (province_name='" + provinceName + "')";  
  107.                 cursor = database.query("v_cities_province", projection, selection,  
  108.                         selectionArgs, nullnull, sortOrder);                
  109.                 break;  
  110.               
  111.             default:  
  112.                 throw new IllegalArgumentException("<" + uri + ">格式不正确.");  
  113.         }  
  114.         return cursor;  
  115.   
  116.     }  
  117.   
  118.     @Override  
  119.     public String getType(Uri uri){  
  120.         // TODO Auto-generated method stub  
  121.         return null;  
  122.     }  
  123.   
  124.     @Override  
  125.     public Uri insert(Uri uri, ContentValues values){  
  126.         // TODO Auto-generated method stub  
  127.         return null;  
  128.     }  
  129.   
  130.     @Override  
  131.     public int delete(Uri uri, String selection, String[] selectionArgs){  
  132.         // TODO Auto-generated method stub  
  133.         return 0;  
  134.     }  
  135.   
  136.     @Override  
  137.     public int update(Uri uri, ContentValues values, String selection,  
  138.             String[] selectionArgs){  
  139.         // TODO Auto-generated method stub  
  140.         return 0;  
  141.     }  
  142.   
  143. }  

接下来讲述一下如何使用ContentProvider提供的数据 
Java代码  收藏代码
  1. import android.app.Activity;  
  2. import android.content.ContentResolver;  
  3. import android.database.Cursor;  
  4. import android.net.Uri;  
  5. import android.os.Bundle;  
  6. import android.view.View;  
  7. import android.widget.ListView;  
  8. import android.widget.SimpleCursorAdapter;  
  9. import android.widget.Toast;  
  10.   
  11. public class Main extends Activity  
  12. {  
  13.     /** Called when the activity is first created. */  
  14.     @Override  
  15.     public void onCreate(Bundle savedInstanceState)  
  16.     {    
  17.         super.onCreate(savedInstanceState);  
  18.         setContentView(R.layout.main);  
  19.     }  
  20.     
  21.     public void onClick_Show_Cities(View view)  
  22.     {  
  23.         ContentResolver contentResolver = getContentResolver();  
  24.         Uri uri = Uri  
  25.                 .parse("content://cn.eoe.regioncontentprovider/cities");  
  26.         Cursor cursor = contentResolver.query(uri, new String[]  
  27.         { "city_code as _id""city_name""province_code" }, nullnullnull);  
  28.   
  29.         SimpleCursorAdapter simpleCursorAdapter = new SimpleCursorAdapter(this,  
  30.                 android.R.layout.simple_list_item_1, cursor, new String[]  
  31.                 { "city_name" }, new int[]  
  32.                 { android.R.id.text1 });  
  33.   
  34.         ListView lvCities = (ListView) findViewById(R.id.lvCities);  
  35.         lvCities.setAdapter(simpleCursorAdapter);  
  36.   
  37.         uri = Uri  
  38.                 .parse("content://cn.eoe.regioncontentprovider/code/024");  
  39.         cursor = contentResolver.query(uri, nullnullnullnull);  
  40.         if (cursor.moveToFirst())  
  41.         {  
  42.             Toast.makeText(  
  43.                     this,  
  44.                     "024:"  
  45.                             + cursor.getString(cursor  
  46.                                     .getColumnIndex("city_name")),  
  47.                     Toast.LENGTH_LONG).show();  
  48.         }  
  49.   
  50.         uri = Uri  
  51.                 .parse("content://cn.eoe.regioncontentprovider/name/沈阳");  
  52.         cursor = contentResolver.query(uri, nullnullnullnull);  
  53.         if (cursor.moveToFirst())  
  54.         {  
  55.             Toast.makeText(  
  56.                     this,  
  57.                     "沈阳:"  
  58.                             + cursor.getString(cursor  
  59.                                     .getColumnIndex("city_code")),  
  60.                     Toast.LENGTH_LONG).show();  
  61.         }  
  62.     }  
  63.   
  64.     public void onClick_Show_Lining_Cities(View view)  
  65.     {  
  66.         ContentResolver contentResolver = getContentResolver();  
  67.         Uri uri = Uri  
  68.                 .parse("content://cn.eoe.regioncontentprovider/cities_in_province/辽宁");  
  69.         Cursor cursor = contentResolver.query(uri, new String[]  
  70.         { "city_code as _id""city_name""province_code" }, nullnull,  
  71.                 "city_code");  
  72.   
  73.         SimpleCursorAdapter simpleCursorAdapter = new SimpleCursorAdapter(this,  
  74.                 android.R.layout.simple_list_item_1, cursor, new String[]  
  75.                 { "city_name" }, new int[]  
  76.                 { android.R.id.text1 });  
  77.   
  78.         ListView lvCities = (ListView) findViewById(R.id.lvCities);  
  79.         lvCities.setAdapter(simpleCursorAdapter);  
  80.     }  
  81. }  

什么是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
来源:http://18767136122.iteye.com/blog/2100970
录入日期:[2017/06/19 2:24:00]
收藏 推荐 打印 | 录入:mikebai | 阅读:
文章评论      
正在加载评论列表...
评论表单加载中...