ContentResolver与ContentProvider

    写在转帖前:最近遇到个问题,使用ContentResolver插入数据然后取出该条数据,当时是正常的,但当把进程杀掉后,下次启动程序时,程序竟然重新调用ContentProvider新建数据库,导致数据丢失。以下仅是明确两者使用方法并不是问题答案。

 

   android中对数据操作包含有:
file, sqlite3, Preferences, ContectResolver与ContentProvider前三种数据操作方式都只是针对本应用内数据,程序不能通过这三种方法去操作别的应用内的数据。
android中提供ContectResolver与ContentProvider来操作别的应用程序的数据。

一、 使用方式
一个应用实现ContentProvider来提供内容给别的应用来操作,
一个应用通过ContentResolver来操作别的应用数据,当然在自己的应用中也可以。
1. ContentResolver的获取
   通过Context类:
  

Java代码
  1. public abstract ContentResolver getContentResolver();  
public abstract ContentResolver getContentResolver();


  
2. ContentResolver常用操作
  

Java代码
  1. //查询:   
  2. public final Cursor query(Uri uri, String[] projection,   
  3.            String selection, String[] selectionArgs, String sortOrder);   
  4. //新增   
  5. public final Uri insert(Uri url, ContentValues values)       
  6. //更新   
  7. public final int update(Uri uri, ContentValues values, String where,   
  8.              String[] selectionArgs)   
  9. //删除   
  10. public final int delete(Uri url, String where, String[] selectionArgs)   
  11.          
//查询:
public final Cursor query(Uri uri, String[] projection,
          String selection, String[] selectionArgs, String sortOrder);
//新增
public final Uri insert(Uri url, ContentValues values)    
//更新
 public final int update(Uri uri, ContentValues values, String where,
            String[] selectionArgs)
//删除
public final int delete(Uri url, String where, String[] selectionArgs)


       以上操作实际是通过Uri来匹配ContentProvider, 再由ContentProvider来进行具体操作的。
       操作的参数和操作sqlite各函数的参数意义是一样的。
      
二、实现ContentProvider提供给外界访问
调用者ContentResoler是通过一个Uri来找到相应的ContentProvider的来进行实际操作。
     1. Uri概念
        一个Uri的样子如:
     

Java代码
  1. scheme://authorities/path/id  
scheme://authorities/path/id


       如电话记录:
      

Java代码
  1. public static final Uri CONTENT_URI = Uri.parse("content://call_log/calls");  
public static final Uri CONTENT_URI = Uri.parse("content://call_log/calls");


       a.根据scheme不同调用不程序来处理, 常用的:content, android_resource, file, http等
       b.authorities是provider定义的,在AndroidManifest.xml中定义
       c.path和id就好理解的。
    
     2. Uri定义
       创建自己的Uri, 如:
      

Java代码
  1. content://com.shguo.statistic/sms  
content://com.shguo.statistic/sms


       一般数据中都有dir和item两种(当然可定义多个)。为ContentProvider创建息的UriMatcher并添加这两者:
      

Java代码
  1. String AUTHORITY = "com.shguo.statistics";   
  2. UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);   
  3. sUriMatcher.addURI(AUTHORITY, "sms",   SMS_DIR);   //SMS_DIR = 1   
  4. sUriMatcher.addURI(AUTHORITY, "sms/#", SMS_ITEM); //SMS_ITEM = 2  
String AUTHORITY = "com.shguo.statistics";
UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
sUriMatcher.addURI(AUTHORITY, "sms",  SMS_DIR);   //SMS_DIR = 1
sUriMatcher.addURI(AUTHORITY, "sms/#", SMS_ITEM); //SMS_ITEM = 2


       contentProvider要根据传入uri判断是dir还是item来操作的。
      

Java代码
  1. switch (sUriMatcher.match(uri))   
switch (sUriMatcher.match(uri))


       来分步操作.
      
     3. 定义MIME类型,
      覆盖getType方法:主要是根据uri来返回Provider的MIME类型
    

Java代码
  1. public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.shguo.sms";   
  2. ublic static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.shguo.sms";  
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.shguo.sms";
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.shguo.sms";


      getType()为:
     

Java代码
  1. switch (sUriMatcher.match(uri)) {   
  2.         case SMS_DIR:   
  3.             return   CONTENT_TYPE;   
  4.         case SMS_ITEM:   
  5.             return CONTENT_ITEM_TYPE;   
  6.         default:   
  7.             throw new IllegalArgumentException("Unknown URI " + uri);   
  8.      }  
switch (sUriMatcher.match(uri)) {
   case SMS_DIR:
    return  CONTENT_TYPE;
   case SMS_ITEM:
    return CONTENT_ITEM_TYPE;
   default:
    throw new IllegalArgumentException("Unknown URI " + uri);
  }


    
     4. 实现query, insert, delete, update四个操作。
       具体的实现可以用sqlite, file等。并根据uri分情况操作。
       a. query时如果是item加查询条件id.
          where = "_ID=" + uri.getPathSegments().get(1)   + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : "";
          最后要加上
         cursor.setNotificationUri(getContext().getContentResolver(), uri);
       
       b. insert时要求uri只能是dir. 成功之后返回一个加id的uri.
         

Java代码
  1. Uri insertUri = ContentUris.withAppendedId(CONTENT_URI, rowId);  
Uri insertUri = ContentUris.withAppendedId(CONTENT_URI, rowId);


       c. update、delete与query差不多。
         

Java代码
  1. //注意通知注册uri的观察者。   
  2. getContext().getContentResolver().notifyChange(uri, null);  
//注意通知注册uri的观察者。
getContext().getContentResolver().notifyChange(uri, null);


                 
     5. 在AndroidManifest.xml中定义
        provider元素,主要属性有:
      

Java代码
  1. name => ContentProvider类名   
  2. authorities => content type的授权部分   
  3. multiprocess => true允许在每个客户进程中创建provider实例,消除执行IPC的需求。

 

----------------------------------------------------------------------------------------------------------------------------------------------------

 

  1. android有一个独特之处就是,数据库只能被它的创建者所使用,其他的应用是不能访问到的,所以如果你想实现不同应用之间的数据共享,就不得不用content provider了。   
  2. 在Android中,content provider是一个特殊的存储数据的类型,它提供了一套标准的接口用来获取以及操作数据。并且,android自身也提供了几个现成的content provider:Contacts, Browser, CallLog, Settings, MediaStore.   
  3.     
  4. 应用可以通过一个唯一的ContentResolver interface来使用具体的某个content provider。   
  5.     
  6. ContentResolver cr = getContentResolver();   
  7. 然后你就可以用ContentResolver提供的方法来使用你需要的content provider了。其中contentResolver提供的方法包括query(),insert(),update()等。要使用这些方法,还会涉及到一个东西,那就是Uri。你可以将它理解成一个string形式的contentProvider的完全路径,它的形式为<standard_prefix>://<authority>/<data_path>/<id>,   
  8. 例如:   
  9. content://browser/bookmarks   
  10. content://contacts/people   
  11. content://contacts/people/3   
  12. 下面结合一个实例来看我们如何使用一个已有的content provider,给例子展示了如何从已有的电话本中读出联系人信息:   
  13.   
  14. package com.android.cp;   
  15.   
  16. import android.app.Activity;   
  17. import android.content.ContentResolver;   
  18. import android.database.Cursor;   
  19. import android.os.Bundle;   
  20. import android.provider.Contacts.People;   
  21. import android.util.Log;   
  22. import android.widget.Toast;   
  23.   
  24. public class ContentProviderTest extends Activity {   
  25.     private final String TAG = "ContentProviderTest";    
  26.     /** Called when the activity is first created. */  
  27.     @Override  
  28.     public void onCreate(Bundle savedInstanceState) {   
  29.         super.onCreate(savedInstanceState);   
  30.         Log.i(TAG,"enter onCreate");   
  31.         setContentView(R.layout.main);   
  32.         createCP();   
  33.     }   
  34.        
  35.     public void createCP()   
  36.     {   
  37.         ContentResolver cr = getContentResolver();   
  38.            
  39.         //Cursor cur = managedQuery(People.CONTENT_URI, null, null, null, null);   
  40.   
  41.         Cursor cur = cr.query(People.CONTENT_URI, nullnullnullnull);   
  42.            
  43.         getColumnData(cur);   
  44.   
  45.     }   
  46.        
  47.     private void getColumnData(Cursor cur){    
  48.         if (cur.moveToFirst()) {   
  49.   
  50.             String name;    
  51.             String phoneNumber;    
  52.             int nameColumn = cur.getColumnIndex(People.NAME);    
  53.             int phoneColumn = cur.getColumnIndex(People.NUMBER);   
  54.            
  55.             do {   
  56.                 // Get the field values   
  57.   
  58.                 name = cur.getString(nameColumn);   
  59.                 phoneNumber = cur.getString(phoneColumn);   
  60.                   
  61.                 Log.i(TAG, "name="+name);   
  62.                 DisplayToast(name+" "+phoneNumber);   
  63.   
  64.             } while (cur.moveToNext());   
  65.   
  66.         }   
  67.     }   
  68.        
  69.     public void DisplayToast(String s)   
  70.     {   
  71.     Toast.makeText(this,   
  72.     s,   
  73.     Toast.LENGTH_LONG).show();   
  74.     }   
  75.   
  76. }   
  77. 需要注意的是,你需要在你的Manifest文件中加上   
  78.   
  79. <uses-permission    
  80. android:name="android.permission.READ_CONTACTS">   
  81. </uses-permission>   
  82. 否则,程序无法成功运行。  

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值