Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 四大組件之ContentProvider(二)-輕輕松松自定義ContentProvider

四大組件之ContentProvider(二)-輕輕松松自定義ContentProvider

編輯:關於Android編程

第3節 自定義ContentProvider

自定義一個ContentProvider,需要繼承ContentProvider類重新創建一個類,並實現其中的一些方法; 在應用的AndroidManifest.xml文件中,聲明這個新添加的組件;

但在這之前,我們要來設計一下外部訪問它采用的地址。

3.1 地址設計

Urischeme字段是固定的,使用content:

authority定義成程序的包名com.anddle.mycontentprovider

path就像是網站內部的分類,依據網站的邏輯進行劃分。
假設我們的ContentProvider提供書籍book和文件file兩種內容的查詢操作。而每種類型都可以進行單一數據的操作和多條數據的操作。

例如,

操作所有書的信息:content://com.anddle.mycontentprovider/books; 操作某本特定書的信息:content://com.anddle.mycontentprovider/books/8 操作所有文件的信息:content://com.anddle.mycontentprovider/files 操作某個特定文件的信息:content://com.anddle.mycontentprovider/files/3

所以,在對這些地址代表的對象進行增刪改查的時候,就需要分析出它們針對的對象。

3.2 創建ContentProvider子類

繼承ContentProvider類,會要求我們實現getType() insert() delete() update() query() onCreate()等接口,

public class MyContentProvider extends ContentProvider {

    @Override
    public boolean onCreate() {

        return true;
    }

    @Override
    public String getType(Uri uri) {

        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {

        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {

        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
                      String[] selectionArgs) {

        throw new UnsupportedOperationException("Not yet implemented");
    }

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

        throw new UnsupportedOperationException("Not yet implemented");
    }

}

定義提供給其他組件使用的“網絡地址”URI,這裡我們把它們定義成content://com.anddle.mycontentprovider/books content://com.anddle.mycontentprovider/files

private static final String SCHEME = "content://";

private static final String PATH_BOOKS = "/books";
private static final String PATH_FILES = "/files";

public static final String AUTHORITY = "com.anddle.mycontentprovider";

//"content://com.anddle.mycontentprovider/books"
public static final Uri CONTENT_BOOKS_URI = Uri.parse(SCHEME + AUTHORITY + PATH_BOOKS);

//"content://com.anddle.mycontentprovider/files"
public static final Uri CONTENT_FILES_URI = Uri.parse(SCHEME + AUTHORITY + PATH_FILES);

定義解析地址的匹配器,

private static final int BOOKS = 0;
private static final int BOOK = 1;
private static final int FILES = 2;
private static final int FILE = 3;

private static final UriMatcher sUriMatcher;

static {

    sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

    sUriMatcher.addURI(AUTHORITY, PATH_BOOKS, BOOKS);
    sUriMatcher.addURI(AUTHORITY, PATH_BOOKS+"/#", BOOK);

    sUriMatcher.addURI(AUTHORITY, PATH_FILES, FILES);
    sUriMatcher.addURI(AUTHORITY, PATH_FILES+"/#", FILE);

}

UriMatcher可以對傳入的字符串進行匹配檢測,如果匹配成功,會返回一個對應的值,例如,

int type = sUriMatcher.match("content://com.anddle.mycontentprovider/files");
//type就等於FILES的值2

type就等於FILES的值2。利用這個方法,我們就可以區分出Uri訪問ContentProvider時,到底希望操作什麼樣的數據。

創建匹配器的時候,加入sUriMatcher.addURI("content://com.anddle.mycontentprovider","files/#", FILE);這種帶有”#”的關鍵字段,表示如下這種匹配方式,即匹配任何數字

content://com.anddle.mycontentprovider/files/0
content://com.anddle.mycontentprovider/files/1
content://com.anddle.mycontentprovider/files/3

創建匹配器的時候,加入sUriMatcher.addURI("content://com.anddle.mycontentprovider","files/*", FILE);這種帶有”#”的關鍵字段,表示如下這種匹配方式,即匹配任何字符

content://com.anddle.mycontentprovider/files/how-to-program
content://com.anddle.mycontentprovider/files/bible
content://com.anddle.mycontentprovider/files/101story

在回調函數中,根據Uri,做對應的操作,

@Override
public Uri insert(Uri uri, ContentValues values) {

   Uri result = null;?

   switch (sUriMatcher.match(uri)) {

       case BOOKS: {
            //從ContentValues中取出數據,保存起來;返回保存數據的Uri地址,例如
            //content://com.anddle.mycontentprovider/books
       }
       break;

       case BOOK: {
            //從ContentValues中取出數據,保存起來;返回保存數據的Uri地址,例如
            //content://com.anddle.mycontentprovider/books/8
       }
       break;

       case FILES: {
            //從ContentValues中取出數據,保存起來;返回保存數據的Uri地址,例如
            //content://com.anddle.mycontentprovider/files
       }
       break;

       case FILE: {
            //從ContentValues中取出數據,保存起來;返回保存數據的Uri地址,例如
            //content://com.anddle.mycontentprovider/files/8
       }
       break;

       default:
           throw new IllegalArgumentException("Unknown URI " + uri);
   }

   return result;
}

這裡就要實現對數據增刪改查的真正操作。

ContentProvider中,可以使用很多方式對數據進行保存、修改,例如SQL數據庫。不過我們暫時不去實現,把它放到下一個章節專門介紹。

其他delete() update() query()實現的函數做類似處理。

對於getType(), 需要為每一種類型的Uri返回一種數據類型-MIME type,告訴調用者,當前這種Uri可以處理什麼類型的數據。

它的格式型如type\subtype,有很多知名的MIME type類型,例如application/pdf image/jpeg等等,可以在網上查找到公開的MIME type類型有哪些。也可以自定義自己應用支持的特殊MIME type類型。

這裡我們就返回一個空值,

@Override
public String getType(Uri uri) {

   return null;
}

至此,一個ContentProvider的就完成了。不過它現在還沒有添加上真正可以存儲數據的功能。

/*******************************************************************/
版權聲明
本教程只在CSDN和安豆網發布,其他網站出現本教程均為盜鏈。
/*******************************************************************/

 

3.3 聲明ContentProvider
千萬不要忘記,在應用的AndroidManifest.xml文件中,聲明新添加的ContentProvider

這裡的android:authorities屬性值,就要填寫定義MyContentProvider時,代碼中的那個,

public static final String AUTHORITY = "com.anddle.mycontentprovider";

android:exported屬性如何設置成true,說明這個ContentProvider可以被其他應用使用(就像一個公共網站,可以被任何人訪問),如果設置成false,說明它只能被自己所在的應用使用(就像一個內部網站,只能在公司內部訪問)。

3.4 使用自定義ContentProvider

無論是使用應用自己的ContentProvider還是使用其他應用提供的,它們的使用方式都和使用系統提供的ContentProvider一樣,

添加一條數據數據:通過ContentResolver獲取訪問ContentProvider的入口,使用ContentValues添加要插入的數據;

ContentResolver cr = getContentResolver();
ContentValues cv = new ContentValues();
cv.put("數據字段名稱", "數據內容");
Uri uri = cr.insert("content://com.anddle.mycontentprovider/books", cv)

通常會返回指向剛成功插入的這條數據的Uri(內容就如content://com.anddle.mycontentprovider/books/8)。

刪除一條數據:通過ContentResolver獲取訪問ContentProvider的入口,使用Uri刪除指定的數據;

String where = null;
String [] keywords = null;
ContentResolver cr = getContentResolver();
cr.delete("content://com.anddle.mycontentprovider/books/8", where, keywords);

修改一條數據:通過ContentResolver獲取訪問ContentProvider的入口,使用Uri更新指定的數據,要修改的數據放在ContentValues當中;

String where = null;
String [] keywords = null;
ContentResolver cr = getContentResolver();
ContentValues cv = new ContentValues();
cv.put("數據字段名稱", "新數據內容",where,keywords);
cr.update("content://com.anddle.mycontentprovider/books", cv, where, keywords)

查詢某一類的數據(或者特定某條數據),

Uri uri = MyContentProvider.CONTENT_BOOKS_URI;

String[] searchKey = null;
String where = null;
String [] keywords = null;
String sortOrder = null;

ContentResolver resolver = getContentResolver();
Cursor cursor = resolver.query(
                    uri,
                    searchKey, 
                    where, 
                    keywords, 
                    sortOrder);

if(cursor != null)
{
    while(cursor.moveToNext())
    {   
        ......  
    }

    cursor.close();
}

注意,在刪改查的操作中,還會使用諸如where sortOrder keywords searcgKey這樣的參數,它們是輔助ContentProvider查詢特定數據時用的。

雖然Uri已經能定位到某條具體的數據了,但是大部分的ContentProvider都是通過SQL數據庫來實現的真正存儲,因此,在設計這些接口的時候就保留了SQL語言的一些用法,讓使用者也能像直接操作SQL數據庫那樣靈活方便的使用ContentProvider

假如ContentProvider不用SQL實現數據存儲功能,而采用別的存儲機制,那麼這些額外的參數就可以派上別的用場或者完全用不著。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved