【Android基础知识】ContentProvider(二)自定义ContentProvider和URI

在Android平台上创建ContentProvider,相对而言是很容易的。你所需做的就是继承ContentProvider这个抽象类,然后重新它里面的各种方法。

下面将介绍如何创建一个ContentProvider,用来存储一些图书的信息。

1. 使用Eclipse创建一个工程,ContentProviders。

2. 新建一个名为BooksProvider类。

3. BooksProvider.Java中的代码。

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public class BooksProvider extends ContentProvider  
  2. {  
  3.     static final String PROVIDER_NAME =  
  4.         "net.manoel.provider.Books";  
  5.   
  6.     static final Uri CONTENT_URI =  
  7.         Uri.parse("content://"+ PROVIDER_NAME + "/books");  
  8.   
  9.     static final String _ID = "_id";  
  10.     static final String TITLE = "title";  
  11.     static final String ISBN = "isbn";  
  12.   
  13.     static final int BOOKS = 1;  
  14.     static final int BOOK_ID = 2;  
  15.   
  16.     private static final UriMatcher uriMatcher;  
  17.     static{  
  18.         uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);  
  19.         uriMatcher.addURI(PROVIDER_NAME, "books", BOOKS);  
  20.         uriMatcher.addURI(PROVIDER_NAME, "books/#", BOOK_ID);  
  21.     }  
  22.   
  23.     //---for database use---  
  24.     SQLiteDatabase booksDB;  
  25.     static final String DATABASE_NAME = "Books";  
  26.     static final String DATABASE_TABLE = "titles";  
  27.     static final int DATABASE_VERSION = 1;  
  28.     static final String DATABASE_CREATE =  
  29.         "create table " + DATABASE_TABLE +  
  30.         " (_id integer primary key autoincrement, "  
  31.         + "title text not null, isbn text not null);";  
  32.   
  33.     private static class DatabaseHelper extends SQLiteOpenHelper  
  34.     {  
  35.         DatabaseHelper(Context context) {  
  36.             super(context, DATABASE_NAME, null, DATABASE_VERSION);  
  37.         }  
  38.   
  39.         @Override  
  40.         public void onCreate(SQLiteDatabase db)  
  41.         {  
  42.             db.execSQL(DATABASE_CREATE);  
  43.         }  
  44.   
  45.         @Override  
  46.         public void onUpgrade(SQLiteDatabase db, int oldVersion,  
  47.                 int newVersion) {  
  48.             Log.w("Content provider database",  
  49.                     "Upgrading database from version " +  
  50.                             oldVersion + " to " + newVersion +  
  51.                     ", which will destroy all old data");  
  52.             db.execSQL("DROP TABLE IF EXISTS titles");  
  53.             onCreate(db);  
  54.         }  
  55.     }  
  56.       
  57.     @Override  
  58.     public int delete(Uri arg0, String arg1, String[] arg2) {  
  59.         // arg0 = uri   
  60.         // arg1 = selection  
  61.         // arg2 = selectionArgs  
  62.         int count=0;  
  63.         switch (uriMatcher.match(arg0)){  
  64.         case BOOKS:  
  65.             count = booksDB.delete(  
  66.                     DATABASE_TABLE,  
  67.                     arg1,  
  68.                     arg2);  
  69.             break;  
  70.         case BOOK_ID:  
  71.             String id = arg0.getPathSegments().get(1);  
  72.             count = booksDB.delete(  
  73.                     DATABASE_TABLE,  
  74.                     _ID + " = " + id +  
  75.                     (!TextUtils.isEmpty(arg1) ? " AND (" +  
  76.                             arg1 + ')' : ""),  
  77.                             arg2);  
  78.             break;  
  79.         defaultthrow new IllegalArgumentException("Unknown URI " + arg0);  
  80.         }  
  81.         getContext().getContentResolver().notifyChange(arg0, null);  
  82.         return count;  
  83.     }  
  84.   
  85.     @Override  
  86.     public String getType(Uri uri) {  
  87.         switch (uriMatcher.match(uri)){  
  88.         //---get all books---  
  89.         case BOOKS:  
  90.             return "vnd.android.cursor.dir/vnd.manoel.books ";  
  91.               
  92.         //---get a particular book---  
  93.         case BOOK_ID:  
  94.             return "vnd.android.cursor.item/vnd.manoel.books ";  
  95.               
  96.         default:  
  97.             throw new IllegalArgumentException("Unsupported URI: " + uri);  
  98.         }  
  99.     }  
  100.   
  101.     @Override  
  102.     public Uri insert(Uri uri, ContentValues values) {  
  103.         //---add a new book---  
  104.         long rowID = booksDB.insert(  
  105.                 DATABASE_TABLE,  
  106.                 "",  
  107.                 values);  
  108.   
  109.         //---if added successfully---  
  110.         if (rowID>0)  
  111.         {  
  112.             Uri _uri = ContentUris.withAppendedId(CONTENT_URI, rowID);  
  113.             getContext().getContentResolver().notifyChange(_uri, null);  
  114.             return _uri;  
  115.         }  
  116.         throw new SQLException("Failed to insert row into " + uri);  
  117.     }  
  118.   
  119.     @Override  
  120.     public boolean onCreate() {  
  121.         Context context = getContext();  
  122.         DatabaseHelper dbHelper = new DatabaseHelper(context);  
  123.         booksDB = dbHelper.getWritableDatabase();  
  124.         return (booksDB == null)? false:true;  
  125.     }  
  126.   
  127.     @Override  
  128.     public Cursor query(Uri uri, String[] projection, String selection,  
  129.             String[] selectionArgs, String sortOrder) {  
  130.         SQLiteQueryBuilder sqlBuilder = new SQLiteQueryBuilder();  
  131.         sqlBuilder.setTables(DATABASE_TABLE);  
  132.   
  133.         if (uriMatcher.match(uri) == BOOK_ID)  
  134.             //---if getting a particular book---  
  135.             sqlBuilder.appendWhere(  
  136.                     _ID + " = " + uri.getPathSegments().get(1));  
  137.   
  138.         if (sortOrder==null || sortOrder=="")  
  139.             sortOrder = TITLE;  
  140.   
  141.         Cursor c = sqlBuilder.query(  
  142.             booksDB,  
  143.             projection,  
  144.             selection,  
  145.             selectionArgs,  
  146.             null,  
  147.             null,  
  148.             sortOrder);  
  149.   
  150.         //---register to watch a content URI for changes---  
  151.         c.setNotificationUri(getContext().getContentResolver(), uri);  
  152.         return c;  
  153.     }  
  154.   
  155.     @Override  
  156.     public int update(Uri uri, ContentValues values, String selection,  
  157.             String[] selectionArgs) {  
  158.         int count = 0;  
  159.         switch (uriMatcher.match(uri)){  
  160.         case BOOKS:  
  161.             count = booksDB.update(  
  162.                     DATABASE_TABLE,  
  163.                     values,  
  164.                     selection,  
  165.                     selectionArgs);  
  166.             break;  
  167.         case BOOK_ID:  
  168.             count = booksDB.update(  
  169.                     DATABASE_TABLE,  
  170.                     values,  
  171.                     _ID + " = " + uri.getPathSegments().get(1) +  
  172.                     (!TextUtils.isEmpty(selection) ? " AND (" +  
  173.                             selection + ')' : ""),  
  174.                             selectionArgs);  
  175.             break;  
  176.         defaultthrow new IllegalArgumentException("Unknown URI " + uri);  
  177.         }  
  178.         getContext().getContentResolver().notifyChange(uri, null);  
  179.         return count;  
  180.     }  
  181. }  
4. 在AndroidManifest.xml中添加声明。

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="net.manoel.ContentProviders"  
  4.     android:versionCode="1"  
  5.     android:versionName="1.0" >  
  6.   
  7.     <uses-sdk android:minSdkVersion="14" />  
  8.   
  9.     <application  
  10.         android:icon="@drawable/ic_launcher"  
  11.         android:label="@string/app_name" >  
  12.         <activity  
  13.             android:label="@string/app_name"  
  14.             android:name=".ContentProvidersActivity" >  
  15.             <intent-filter >  
  16.                 <action android:name="android.intent.action.MAIN" />  
  17.   
  18.                 <category android:name="android.intent.category.LAUNCHER" />  
  19.             </intent-filter>  
  20.         </activity>  
  21. <!-- 注意使用exported = "true"可以在其他应用程序的Activity或者Service中使用 -->
  22.         <provider 
  23.             android:exported="true" 
  24.     android:name="BooksProvider"  
  25.             android:authorities="net.manoel.provider.Books">              
  26.         </provider>              
  27.     </application>  
  28.   
  29. </manifest>  

在这个例子中,首先创建一个ContentProvider的子类,名字叫BooksProvider。需要重写一些方法:

  • getTpye() - 返回给定的URI数据的MIME类型
  • onCreate() - 当provider启动的时候被调用
  • query() - 接收客户的请求。返回一个Cursor对象。
  • insert() - 向provider中插入一条新记录
  • delete() - 在provider中删除一条已存在的记录
  • update() - 在provider中更新一条已存在的记录

在content provider中,可以任意选择要存储的数据 - 传统的文件,XML,数据库,甚至web service。


接下来,在BooksProvider.java类中定义一些常量:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static final String PROVIDER_NAME =  
  2.     "net.manoel.provider.Books";  
  3.   
  4. static final Uri CONTENT_URI =  
  5.     Uri.parse("content://"+ PROVIDER_NAME + "/books");  
  6.   
  7. static final String _ID = "_id";  
  8. static final String TITLE = "title";  
  9. static final String ISBN = "isbn";  
  10.   
  11. static final int BOOKS = 1;  
  12. static final int BOOK_ID = 2;  
  13.   
  14. private static final UriMatcher uriMatcher;  
  15. static{  
  16.     uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);  
  17.     uriMatcher.addURI(PROVIDER_NAME, "books", BOOKS);  
  18.     uriMatcher.addURI(PROVIDER_NAME, "books/#", BOOK_ID);  
  19. }  

观察上面的代码,使用的一个UriMatcher对象去转换URI,这个URI将会作为一个参数传递给ContentResolver。举个例子,下面的URI代表了请求所有的图书:

content://net.manoel.provider.Books/books

下面的URI代表了请求指定_id 5为的图书:

content://net.manoel.provider.Books/books/5


content provider 使用一个SQlite数据库去存储图书。注意一点,这里使用SQLiteOpenHelper辅助类去操纵数据库:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. private static class DatabaseHelper extends SQLiteOpenHelper  
  2.     {  
  3.         DatabaseHelper(Context context) {  
  4.             super(context, DATABASE_NAME, null, DATABASE_VERSION);  
  5.         }  
  6.   
  7.         @Override  
  8.         public void onCreate(SQLiteDatabase db)  
  9.         {  
  10.             db.execSQL(DATABASE_CREATE);  
  11.         }  
  12.   
  13.         @Override  
  14.         public void onUpgrade(SQLiteDatabase db, int oldVersion,  
  15.                 int newVersion) {  
  16.             Log.w("Content provider database",  
  17.                     "Upgrading database from version " +  
  18.                             oldVersion + " to " + newVersion +  
  19.                     ", which will destroy all old data");  
  20.             db.execSQL("DROP TABLE IF EXISTS titles");  
  21.             onCreate(db);  
  22.         }  
  23.     }  

接下来,重写getType()方法,唯一可以描述content provider的数据类型。使用UriMatcher对象,返回vnd.android.cursor.item/vnd.manoel.books代表单独的一本书,vnd.android.cursor.dir/vnd.android.cursor.item/vnd.manoel.bools 代表多本书:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public String getType(Uri uri) {  
  3.     switch (uriMatcher.match(uri)){  
  4.     //---get all books---  
  5.     case BOOKS:  
  6.         return "vnd.android.cursor.dir/vnd.manoel.books ";  
  7.           
  8.     //---get a particular book---  
  9.     case BOOK_ID:  
  10.         return "vnd.android.cursor.item/vnd.manoel.books ";  
  11.           
  12.     default:  
  13.         throw new IllegalArgumentException("Unsupported URI: " + uri);  
  14.     }  
  15. }  

然后,重写onCreate()方法,当provider被开启的时候,和数据库建立建立链接:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public boolean onCreate() {  
  3.     Context context = getContext();  
  4.     DatabaseHelper dbHelper = new DatabaseHelper(context);  
  5.     booksDB = dbHelper.getWritableDatabase();  
  6.     return (booksDB == null)? false:true;  
  7. }  

然后,重新query()方法:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public Cursor query(Uri uri, String[] projection, String selection,  
  3.         String[] selectionArgs, String sortOrder) {  
  4.     SQLiteQueryBuilder sqlBuilder = new SQLiteQueryBuilder();  
  5.     sqlBuilder.setTables(DATABASE_TABLE);  
  6.   
  7.     if (uriMatcher.match(uri) == BOOK_ID)  
  8.         //---if getting a particular book---  
  9.         sqlBuilder.appendWhere(  
  10.                 _ID + " = " + uri.getPathSegments().get(1));  
  11.   
  12.     if (sortOrder==null || sortOrder=="")  
  13.         sortOrder = TITLE;  
  14.   
  15.     Cursor c = sqlBuilder.query(  
  16.         booksDB,  
  17.         projection,  
  18.         selection,  
  19.         selectionArgs,  
  20.         null,  
  21.         null,  
  22.         sortOrder);  
  23.   
  24.     //---register to watch a content URI for changes---  
  25.     c.setNotificationUri(getContext().getContentResolver(), uri);  
  26.     return c;  
  27. }  
查询的结果是一个Cursor对象。


然后,重写insert()方法:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public Uri insert(Uri uri, ContentValues values) {  
  3.     //---add a new book---  
  4.     long rowID = booksDB.insert(  
  5.             DATABASE_TABLE,  
  6.             "",  
  7.             values);  
  8.   
  9.     //---if added successfully---  
  10.     if (rowID>0)  
  11.     {  
  12.         Uri _uri = ContentUris.withAppendedId(CONTENT_URI, rowID);  
  13.         getContext().getContentResolver().notifyChange(_uri, null);  
  14.         return _uri;  
  15.     }  
  16.     throw new SQLException("Failed to insert row into " + uri);  
  17. }  

一旦新的记录插入成功,调用ContentResolver的nofityChande()方法。这就通知观察者一个新的记录被更新了。


然后,重新delete()方法:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public int delete(Uri arg0, String arg1, String[] arg2) {  
  3.     // arg0 = uri   
  4.     // arg1 = selection  
  5.     // arg2 = selectionArgs  
  6.     int count=0;  
  7.     switch (uriMatcher.match(arg0)){  
  8.     case BOOKS:  
  9.         count = booksDB.delete(  
  10.                 DATABASE_TABLE,  
  11.                 arg1,  
  12.                 arg2);  
  13.         break;  
  14.     case BOOK_ID:  
  15.         String id = arg0.getPathSegments().get(1);  
  16.         count = booksDB.delete(  
  17.                 DATABASE_TABLE,  
  18.                 _ID + " = " + id +  
  19.                 (!TextUtils.isEmpty(arg1) ? " AND (" +  
  20.                         arg1 + ')' : ""),  
  21.                         arg2);  
  22.         break;  
  23.     defaultthrow new IllegalArgumentException("Unknown URI " + arg0);  
  24.     }  
  25.     getContext().getContentResolver().notifyChange(arg0, null);  
  26.     return count;  
  27. }  

最后,重写update()方法:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public int update(Uri uri, ContentValues values, String selection,  
  3.         String[] selectionArgs) {  
  4.     int count = 0;  
  5.     switch (uriMatcher.match(uri)){  
  6.     case BOOKS:  
  7.         count = booksDB.update(  
  8.                 DATABASE_TABLE,  
  9.                 values,  
  10.                 selection,  
  11.                 selectionArgs);  
  12.         break;  
  13.     case BOOK_ID:  
  14.         count = booksDB.update(  
  15.                 DATABASE_TABLE,  
  16.                 values,  
  17.                 _ID + " = " + uri.getPathSegments().get(1) +  
  18.                 (!TextUtils.isEmpty(selection) ? " AND (" +  
  19.                         selection + ')' : ""),  
  20.                         selectionArgs);  
  21.         break;  
  22.     defaultthrow new IllegalArgumentException("Unknown URI " + uri);  
  23.     }  
  24.     getContext().getContentResolver().notifyChange(uri, null);  
  25.     return count;  
  26. }

使用ContentResolve使用自定义ContentProvider

public class MainActivity extends Activity {
	private static final String TAG = "BooksProviderTest";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        try {
			testSave();
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }
    
    public void testSave() throws Throwable{
        ContentResolver contentResolver =this.getBaseContext().getContentResolver();
        Uri insertUri = Uri.parse("content://net.manoel.provider.Books/books");
        ContentValues values = new ContentValues();
        values.put("title", "lm");
        values.put("isbn", "1350000009");
        Uri uri = contentResolver.insert(insertUri, values);
        Log.i(TAG, uri.toString());
    }
    
    public void testUpdate() throws Throwable{
        ContentResolver contentResolver = this.getBaseContext().getContentResolver();
        Uri updateUri = Uri.parse("content://net.manoel.provider.Books/books1");
        ContentValues values = new ContentValues();
        values.put("title", "linjiqin");
        contentResolver.update(updateUri, values, null, null);
    }
 
    public void testFind() throws Throwable{
        ContentResolver contentResolver = this.getBaseContext().getContentResolver();
        //Uri uri = Uri.parse("content://com.ljq.provider.personprovider/person");
        Uri uri = Uri.parse("content://net.manoel.provider.Books/books");
        Cursor cursor = contentResolver.query(uri, null, null, null, "id asc");
        while(cursor.moveToNext()){
            int personid = cursor.getInt(cursor.getColumnIndex("_id"));
            String name = cursor.getString(cursor.getColumnIndex("title"));
            String phone = cursor.getString(cursor.getColumnIndex("isbn"));
            Log.i(TAG, "_id="+ personid + ",title="+ name+ ",isbn="+ phone);
        }
        cursor.close();
    }
    
    public void testDelete() throws Throwable{
        ContentResolver contentResolver = this.getBaseContext().getContentResolver();
        Uri uri = Uri.parse("content://net.manoel.provider.Books/books/1");
        contentResolver.delete(uri, null, null);
    }
}
运行结果,插入了数据


注意,如果想在其他应用程序的Activity或Service中使用自定义的ContentProvider,要在配置文件中加入  android:exported="true" 


文章转自: http://blog.csdn.net/manoel/article/details/10578587

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值