Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android基礎之創建ContentProvider

Android基礎之創建ContentProvider

編輯:關於Android編程

Create content provider


Content providers管理對中央數據存儲庫的訪問。您將 提供程序作為 Android 應用中的一個或多個類(連同清單文件 中的元素)實現。其中一個類會實現子類 ContentProvider,即您的提供程序與 其他應用之間的界面。盡管內容提供程序旨在向其他應用提供 數據,但您的應用中必定有這樣一些 Activity,它們允許用戶 查詢和修改由提供程序管理的數據。

Preparations started to develop before


請在著手開發提供程序之前執行以下操作:
1.決定您是否需要內容提供程序。如果您想提供下列一項或多項功能,則需要開發內容 提供程序:
- 您想為其他應用提供復雜的數據或文件
- 您想允許用戶將復雜的數據從您的應用復制到其他應用中
- 您想使用搜索框架提供自定義搜索建議

如果完全是在 您自己的應用中使用,則“根本不”需要提供程序即可使用 SQLite 數據庫。

接下來,請按照以下步驟開發您的提供程序:
1.為您的數據設計原始存儲。內容提供程序以兩種方式提供數據:

文件數據
通常存儲在文件中的數據,如 照片、音頻或視頻。將文件存儲在您的應用的私有 空間內。您的提供程序可以應其他應用發出的文件請求 提供文件句柄。

“結構化”數據
通常存儲在數據庫、數組或類似結構中的數據。 以兼容行列表的形式存儲數據。行 表示實體,如人員或庫存項目。列表示 實體的某項數據,如人員的姓名或商品的價格。此類數據通常 存儲在 SQLite 數據庫中,但您可以使用任何類型的 持久存儲。

2.定義 ContentProvider 類及其 所需方法的具體實現。此類是您的數據與 Android 系統其余部分之間的界面。如需了解有關此類的詳細信息,請參閱 實現 ContentProvider 類部分。

3.定義提供程序的權限字符串、其內容 URI 以及列名稱。如果您想讓 提供程序的應用處理 Intent,則還要定義 Intent 操作、Extra 數據 以及標志。此外,還要定義想要訪問您的數據的應用必須具備的權限。 您應該考慮在一個單獨的協定類中將所有這些值定義為常量;以後您可以將此類公開給其他開發者。 如需了解有關內容 URI 的詳細信息,請參閱設計內容 URI 部分。

4.添加其他可選部分,如示例數據或可以在提供程序與雲數據之間同步數據的 AbstractThreadedSyncAdapter 實現。

設計數據存儲


ContentProvider是用於訪問以結構化格式保存的數據的界面。在您創建該界面之前,必須決定如何存儲數據。 您可以按自己的喜好以任何形式存儲數據,然後根據需要設計讀寫數據的界面。

以下是 Android 中提供的一些數據存儲技術:

Android 系統包括一個 SQLite 數據庫 API,Android 自己的提供程序使用它來存儲面向表的數據。
SQLiteOpenHelper 類可幫助您創建數據庫,SQLiteDatabase 類是用於訪問數據庫的基類。

請記住,您不必使用數據庫來實現存儲庫。提供程序在外部表現為一組表,與關系數據庫類似,但這並不是對提供程序內部實現的要求;

對於存儲文件數據,Android 提供了各種面向文件的 API。如果您要設計提供媒體相關數據(如音樂或視頻)的提供程序,則可開發一個合並了表數據和文件的提供程序;

要想使用基於網絡的數據,請使用 java.net 和 android.net 中的類。您也可以將基於網絡的數據與本地數據存儲(如數據庫)同步,然後以表或文件的形式提供數據。

數據設計考慮事項

以下是一些設計提供程序數據結構的技巧:
- 表數據應始終具有一個“主鍵”列,提供程序將其作為與每行對應的唯一數字值加以維護。您可以使用此值將該行鏈接到其他表中的相關行(將其用作“外鍵”)。 盡管您可以為此列使用任何名稱,但使用 BaseColumns._ID是最佳選擇,因為將提供程序查詢的結果鏈接到 ListView 的條件是,檢索到的其中一個列的名稱必須是 _ID;

如果您想提供位圖圖像或其他非常龐大的文件導向型數據,請將數據存儲在一個文件中,然後間接提供這些數據,而不是直接將其存儲在表中。 如果您執行了此操作,則需要告知提供程序的用戶,他們需要使用 ContentResolver 文件方法來訪問數據;

使用二進制大型對象 (BLOB) 數據類型存儲大小或結構會發生變化的數據。 例如,您可以使用 BLOB 列來存儲協議緩沖區或 JSON結構。

您也可以使用 BLOB 來實現獨立於架構的表。在這類表中,您需要以 BLOB 形式定義一個主鍵列、一個 MIME 類型列以及一個或多個通用列。 這些 BLOB 列中數據的含義通過 MIME 類型列中的值指示。 這樣一來,您就可以在同一表中存儲不同類型的行。 舉例來說,聯系人提供程序的“數據”表 ContactsContract.Data 便是一個獨立於架構的表。

設計內容 URI


內容 URI 是用於在提供程序中標識數據的 URI。內容 URI 包括整個提供程序的符號名稱(其權限)和一個指向表或文件的名稱(路徑)。 可選 ID 部分指向 表中的單個行。 ContentProvider 的每一個數據訪問方法都將內容 URI 作為參數;您可以利用這一點確定要訪問的表、行或文件。

設計權限

提供程序通常具有單一權限,該權限充當其 Android 內部名稱。為避免與其他提供程序發生沖突,您應該使用 Internet 域所有權(反向)作為提供程序權限的基礎。 由於此建議也適用於 Android 軟件包名稱,因此您可以將提供程序權限定義為包含該提供程序的軟件包名稱的擴展名。 例如,如果您的 Android 軟件包名稱為 com.example.,則應為提供程序授予權限 com.example..provider。

設計路徑結構

開發者通常通過追加指向單個表的路徑來根據權限創建內容 URI。 例如,如果您有兩個表:table1 和 table2,則可以通過合並上一示例中的權限來生成 內容 URI com.example..provider/table1 和 com.example..provider/table2。路徑並不限定於單個段,也無需為每一級路徑都創建一個表。

處理內容 URI ID

按照慣例,提供程序通過接受末尾具有行所對應 ID 值的內容 URI 來提供對表中單個行的訪問。同樣按照慣例,提供程序會將該 ID 值與表的 _ID 列進行匹配,並對匹配的行執行請求的訪問。

這一慣例為訪問提供程序的應用的常見設計模式提供了便利。應用會對提供程序執行查詢,並使用 CursorAdapter 以 ListView 顯示生成的 Cursor。 定義 CursorAdapter 的條件是, Cursor 中的其中一個列必須是 _ID

用戶隨後從 UI 上顯示的行中選取其中一行,以查看或修改數據。 應用會從支持 ListView 的 Cursor 中獲取對應行,獲取該行的 _ID 值,將其追加到內容 URI,然後向提供程序發送訪問請求。 然後,提供程序便可對用戶選取的特定行執行查詢或修改。

內容 URI 模式

為幫助您選擇對傳入的內容 URI 執行的操作,提供程序 API 加入了實用類 UriMatcher,它會將內容 URI“模式”映射到整型值。 您可以在一個 switch 語句中使用這些整型值,為匹配特定模式的一個或多個內容 URI 選擇所需操作。

內容 URI 模式使用通配符匹配內容 URI:

*:匹配由任意長度的任何有效字符組成的字符串 #:匹配由任意長度的數字字符組成的字符串

以設計和編碼內容 URI 處理為例,假設一個具有權限 com.example.app.provider 的提供程序能識別以下指向表的內容 URI:
content://com.example.app.provider/table1:一個名為 table1 的表
content://com.example.app.provider/table2/dataset1:一個名為 dataset1 的表
content://com.example.app.provider/table2/dataset2:一個名為 dataset2 的表
content://com.example.app.provider/table3:一個名為 table3 的表

提供程序也能識別追加了行 ID 的內容 URI,例如,content://com.example.app.provider/table3/1 對應由 table3 中 1 標識的行的內容 URI。

可以使用以下內容 URI 模式:
content://com.example.app.provider/*
匹配提供程序中的任何內容 URI。

content://com.example.app.provider/table2/*:
匹配表 dataset1 和表 dataset2 的內容 URI,但不匹配 table1 或 table3 的內容 URI。

content://com.example.app.provider/table3/#:匹配 table3 中單個行的內容 URI,如 content://com.example.app.provider/table3/6 對應由 6 標識的行的內容 URI。

以下代碼段說明了 UriMatcher 中方法的工作方式。 此代碼采用不同方式處理整個表的 URI 與單個行的 URI,它為表使用的內容 URI 模式是 content:///,為單個行使用的內容 URI 模式則是 content:////

方法 addURI() 會將權限和路徑映射到一個整型值。 方法 match() 會返回 URI 的整型值。switch 語句會在查詢整個表與查詢單個記錄之間進行選擇:

public class ExampleProvider extends ContentProvider {
...
    // Creates a UriMatcher object.
    private static final UriMatcher sUriMatcher;
...
    /*
     * The calls to addURI() go here, for all of the content URI patterns that the provider
     * should recognize. For this snippet, only the calls for table 3 are shown.
     */
...
    /*
     * Sets the integer value for multiple rows in table 3 to 1. Notice that no wildcard is used
     * in the path
     */
    sUriMatcher.addURI("com.example.app.provider", "table3", 1);

    /*
     * Sets the code for a single row to 2. In this case, the "#" wildcard is
     * used. "content://com.example.app.provider/table3/3" matches, but
     * "content://com.example.app.provider/table3 doesn't.
     */
    sUriMatcher.addURI("com.example.app.provider", "table3/#", 2);
...
    // Implements ContentProvider.query()
    public Cursor query(
        Uri uri,
        String[] projection,
        String selection,
        String[] selectionArgs,
        String sortOrder) {
...
        /*
         * Choose the table to query and a sort order based on the code returned for the incoming
         * URI. Here, too, only the statements for table 3 are shown.
         */
        switch (sUriMatcher.match(uri)) {


            // If the incoming URI was for all of table3
            case 1:

                if (TextUtils.isEmpty(sortOrder)) sortOrder = "_ID ASC";
                break;

            // If the incoming URI was for a single row
            case 2:

                /*
                 * Because this URI was for a single row, the _ID value part is
                 * present. Get the last path segment from the URI; this is the _ID value.
                 * Then, append the value to the WHERE clause for the query
                 */
                selection = selection + "_ID = " uri.getLastPathSegment();
                break;

            default:
            ...
                // If the URI is not recognized, you should do some error handling here.
        }
        // call the code to actually do the query
    }

另一個類 ContentUris 會提供一些工具方法,用於處理內容 URI 的 id 部分。 Uri 類和 Uri.Builder 類包括一些工具方法,用於解析現有 Uri 對象和構建新對象。

實現 ContentProvider 類


ContentProvider 實例通過處理來自其他應用的請求來管理對結構化數據集的訪問。 所有形式的訪問最終都會調用 ContentResolver,後者接著調用 ContentProvider 的具體方法來獲取訪問權限。

必需方法

抽象類 ContentProvider 定義了六個抽象方法,您必須將這些方法作為自己具體子類的一部分加以實現。 所有這些方法( onCreate() 除外)都由一個嘗試訪問您的內容提供程序的客戶端應用調用:

query()

從您的提供程序檢索數據。使用參數選擇要查詢的表、要返回的行和列以及結果的排序順序。 將數據作為 Cursor 對象返回。

insert()

在您的提供程序中插入一個新行。使用參數選擇目標表並獲取要使用的列值。 返回新插入行的內容 URI。

update()

更新您提供程序中的現有行。使用參數選擇要更新的表和行,並獲取更新後的列值。 返回已更新的行數。

delete()

從您的提供程序中刪除行。使用參數選擇要刪除的表和行。 返回已刪除的行數。

getType()

返回內容 URI 對應的 MIME 類型。實現內容提供程序 MIME 類型部分對此方法做了更詳盡的描述。

onCreate()

初始化您的提供程序。Android 系統會在創建您的提供程序後立即調用此方法。 請注意, ContentResolver 對象嘗試訪問您的提供程序時,系統才會創建它。

請注意,這些方法的簽名與同名的 ContentResolver 方法相同。

您在實現這些方法時應考慮以下事項:

所有這些方法(onCreate()除外)都可由多個線程同時調用,因此它們必須是線程安全方法。如需了解有關多個線程的更多信息,請參閱進程和線程主題; 避免在 onCreate() 中執行長時間操作。將初始化任務推遲到實際需要時進行。 實現 onCreate()方法部分對此做了更詳盡的描述; 盡管您必須實現這些方法,但您的代碼只需返回要求的數據類型,無需執行任何其他操作。 例如,您可能想防止其他應用向某些表插入數據。
要實現此目的,您可以忽略 insert() 調用並返回 0。

實現 query() 方法

ContentProvider.query() 方法必須返回 Cursor 對象。如果失敗,則會引發 Exception。 如果您使用 SQLite 數據庫作為數據存儲,則只需返回由 SQLiteDatabase 類的其中一個 query() 方法返回的 Cursor。 如果查詢不匹配任何行,您應該返回一個 Cursor 實例(其 getCount() 方法返回 0)。 只有當查詢過程中出現內部錯誤時,您才應該返回 null。

如果您不使用 SQLite 數據庫作為數據存儲,請使用 Cursor 的其中一個具體子類。 例如,在 MatrixCursor 類實現的游標中,每一行都是一個 Object 數組。 對於此類,請使用 addRow() 來添加新行。

請記住,Android 系統必須能夠跨進程邊界傳播 Exception。 Android 可以為以下異常執行此操作,這些異常可能有助於處理查詢錯誤:
- IllegalArgumentException(您可以選擇在提供程序收到無效的內容 URI 時引發此異常)
- NullPointerException

實現 insert() 方法

insert() 方法會使用 ContentValues 參數中的值向相應表中添加新行。 如果 ContentValues 參數中未包含列名稱,您可能想在您的提供程序代碼或數據庫架構中提供其默認值。

此方法應該返回新行的內容 URI。要想構建此方法,請使用 withAppendedId() 向表的內容 URI 追加新行的 _ID(或其他主鍵)值。

實現 delete() 方法

delete() 方法不需要從您的數據存儲中實際刪除行。 如果您將同步適配器與提供程序一起使用,應該考慮為已刪除的行添加“刪除”標志,而不是將行整個移除。 同步適配器可以檢查是否存在已刪除的行,並將它們從服務器中移除,然後再將它們從提供程序中刪除。

實現 update() 方法

update() 方法采用 insert() 所使用的相同 ContentValues 參數,以及 delete() 和ContentProvider.query() 所使用的相同 selection 和 selectionArgs 參數。 這樣一來,您就可以在這些方法之間重復使用代碼。

實現 onCreate() 方法

Android 系統會在啟動提供程序時調用 onCreate()。您只應在此方法中執行運行快速的初始化任務,並將數據庫創建和數據加載推遲到提供程序實際收到數據請求時進行。 如果您在 onCreate() 中執行長時間的任務,則會減慢提供程序的啟動速度, 進而減慢提供程序對其他應用的響應速度。

例如,如果您使用 SQLite 數據庫,可以在 ContentProvider.onCreate() 中創建一個新的 SQLiteOpenHelper 對象,然後在首次打開數據庫時創建 SQL 表。為簡化這一過程,在您首次調用 getWritableDatabase() 時,它會自動調用 SQLiteOpenHelper.onCreate() 方法。

以下兩個代碼段展示了 ContentProvider.onCreate() 與 SQLiteOpenHelper.onCreate() 之間的交互。第一個代碼段是 ContentProvider.onCreate() 的實現:

public class ExampleProvider extends ContentProvider

    /*
     * Defines a handle to the database helper object. The MainDatabaseHelper class is defined
     * in a following snippet.
     */
    private MainDatabaseHelper mOpenHelper;

    // Defines the database name
    private static final String DBNAME = "mydb";

    // Holds the database object
    private SQLiteDatabase db;

    public boolean onCreate() {

        /*
         * Creates a new helper object. This method always returns quickly.
         * Notice that the database itself isn't created or opened
         * until SQLiteOpenHelper.getWritableDatabase is called
         */
        mOpenHelper = new MainDatabaseHelper(
            getContext(),        // the application context
            DBNAME,              // the name of the database)
            null,                // uses the default SQLite cursor
            1                    // the version number
        );

        return true;
    }

    ...

    // Implements the provider's insert method
    public Cursor insert(Uri uri, ContentValues values) {
        // Insert code here to determine which table to open, handle error-checking, and so forth

        ...

        /*
         * Gets a writeable database. This will trigger its creation if it doesn't already exist.
         *
         */
        db = mOpenHelper.getWritableDatabase();
    }
}

下一個代碼段是 SQLiteOpenHelper.onCreate() 的實現,其中包括一個幫助程序類:

...
// A string that defines the SQL statement for creating a table
private static final String SQL_CREATE_MAIN = "CREATE TABLE " +
    "main " +                       // Table's name
    "(" +                           // The columns in the table
    " _ID INTEGER PRIMARY KEY, " +
    " WORD TEXT"
    " FREQUENCY INTEGER " +
    " LOCALE TEXT )";
...
/**
 * Helper class that actually creates and manages the provider's underlying data repository.
 */
protected static final class MainDatabaseHelper extends SQLiteOpenHelper {

    /*
     * Instantiates an open helper for the provider's SQLite data repository
     * Do not do database creation and upgrade here.
     */
    MainDatabaseHelper(Context context) {
        super(context, DBNAME, null, 1);
    }

    /*
     * Creates the data repository. This is called when the provider attempts to open the
     * repository and SQLite reports that it doesn't exist.
     */
    public void onCreate(SQLiteDatabase db) {

        // Creates the main table
        db.execSQL(SQL_CREATE_MAIN);
    }
}

實現 ContentProvider MIME 類型


ContentProvider 類具有兩個返回 MIME 類型的方法:

getType()

您必須為任何提供程序實現的必需方法之一。

getStreamTypes()

系統在您的提供程序提供文件時要求實現的方法。

表的 MIME 類型

getType() 方法會返回一個 MIME 格式的 String,後者描述內容 URI 參數返回的數據類型。Uri 參數可以是模式,而不是特定 URI;在這種情況下,您應該返回與匹配該模式的內容 URI 關聯的數據類型。

對於文本、HTML 或 JPEG 等常見數據類型, getType() 應該為該數據返回標准 MIME 類型。 IANA MIME Media Types 網站上提供了這些標准類型的完整列表。

對於指向一個或多個表數據行的內容 URI, getType() 應該以 Android 供應商特有 MIME 格式返回 MIME 類型:

類型部分:vnd

子類型部分:
- 如果 URI 模式用於單個行:android.cursor.item/
- 如果 URI 模式用於多個行:android.cursor.dir/

提供程序特有部分:vnd..

您提供 值應具有全局唯一性, 值應在對應的 URI 模式中具有唯一性。適合選擇貴公司的名稱或您的應用 Android 軟件包名稱的某個部分作為 。 適合選擇 URI 關聯表的標識字符串作為

例如,如果提供程序的權限是 com.example.app.provider,並且它公開了一個名為 table1 的表,則 table1 中多個行的 MIME 類型是:

vnd.android.cursor.dir/vnd.com.example.provider.table1

對於 table1 的單個行,MIME 類型是:

vnd.android.cursor.item/vnd.com.example.provider.table1

文件的 MIME 類型

如果您的提供程序提供文件,請實現 getStreamTypes()。 該方法會為您的提供程序可以為給定內容 URI 返回的文件返回一個 MIME 類型 String 數組。您應該通過 MIME 類型過濾器參數過濾您提供的 MIME 類型,以便只返回客戶端想處理的那些 MIME 類型。
例如,假設提供程序以 .jpg、 .png 和 .gif 格式文件形式提供照片圖像。 如果應用調用 ContentResolver.getStreamTypes() 時使用了過濾器字符串 image/*(任何是“圖像”的內容),則 ContentProvider.getStreamTypes() 方法應返回數組:

{ "image/jpeg", "image/png", "image/gif"}

如果應用只對 .jpg 文件感興趣,則可以在調用 ContentResolver.getStreamTypes() 時使用過濾器字符串 *\/jpeg,ContentProvider.getStreamTypes() 應返回:

{"image/jpeg"}

如果您的提供程序未提供過濾器字符串中請求的任何 MIME 類型,則 getStreamTypes() 應返回 null。

實現協定類(Achieve agreement class)

協定類是一種 public final 類,其中包含對 URI、列名稱、MIME 類型以及其他與提供程序有關的元數據的常量定義。 該類可確保即使 URI、列名稱等數據的實際值發生變化,也可以正確訪問提供程序,從而在提供程序與其他應用之間建立合同。

協定類對開發者也有幫助,因為其常量通常采用助記名稱,因此可以降低開發者為列名稱或 URI 使用錯誤值的可能性。 由於它是一種類,因此可以包含 Javadoc 文檔。 集成開發環境(如 Eclipse)可以根據協定類自動完成常量名稱,並為常量顯示 Javadoc。

開發者無法從您的應用訪問協定類的類文件,但他們可以通過您提供的 .jar 文件將其靜態編譯到其應用內。

實現內容提供程序權限


安全與權限主題中詳細描述了 Android 系統各個方面的權限和訪問。 數據存儲主題也描述了各類存儲實行中的安全與權限。 其中的要點簡述如下:
- 默認情況下,存儲在設備內部存儲上的數據文件是您的應用和提供程序的私有數據文件;

您創建的 SQLiteDatabase 數據庫是您的應用和提供程序的私有數據庫;

默認情況下,您保存到外部存儲的數據文件是公用並可全局讀取的數據文件。 您無法使用內容提供程序來限制對外部存儲內文件的訪問,因為其他應用可以使用其他 API 調用來對它們執行讀取和寫入操作;

用於在您的設備的內部存儲上打開或創建文件或 SQLite 數據庫的方法調用可能會為所有其他應用同時授予讀取和寫入訪問權限。如果您將內部文件或數據庫用作提供程序的存儲庫,並向其授予“可全局讀取”或“可全局寫入”訪問權限,則您在清單文件中為提供程序設置的權限不會保護您的數據。 內部存儲中文件和數據庫的默認訪問權限是“私有”,對於提供程序的存儲庫,您不應更改此權限。

如果您想使用內容提供程序權限來控制對數據的訪問,則應將數據存儲在內部文件、SQLite 數據庫或“雲”中(例如,遠程服務器上),而且您應該保持文件和數據庫為您的應用所私有。

實現權限

即使底層數據為私有數據,所有應用仍可從您的提供程序讀取數據或向其寫入數據,因為在默認情況下,您的提供程序未設置權限。 要想改變這種情況,請使用屬性或 元素的子元素在您的清單文件中為您的提供程序設置權限。 您可以設置適用於整個提供程序、特定表、甚至特定記錄的權限,或者設置同時適用於這三者的權限。

您可以通過清單文件中的一個或多個 元素為您的提供程序定義權限。要使權限對您的提供程序具有唯一性,請為 android:name 屬性使用 Java 風格作用域。 例如,將讀取權限命名為 com.example.app.provider.permission.READ_PROVIDER。

以下列表描述了提供程序權限的作用域,從適用於整個提供程序的權限開始,然後逐漸細化。 更細化的權限優先於作用域較大的權限:

統一讀寫提供程序級別權限

一個同時控制對整個提供程序讀取和寫入訪問的權限,通過 元素的 android:permission 屬性指定。

單獨的讀取和寫入提供程序級別權限

針對整個提供程序的讀取權限和寫入權限。您可以通過 元素的 android:readPermission 屬性和 android:writePermission 屬性 指定它們。它們優先於 android:permission 所需的權限。

路徑級別權限

針對提供程序中內容 URI 的讀取、寫入或讀取/寫入權限。您可以通過 元素的 子元素指定您想控制的每個 URI。 對於您指定的每個內容 URI,您都可以指定讀取/寫入權限、讀取權限或寫入權限,或同時指定所有三種權限。 讀取權限和寫入權限優先於讀取/寫入權限。 此外,路徑級別權限優先於提供程序級別權限。

臨時權限

一種權限級別,即使應用不具備通常需要的權限,該級別也能授予對應用的臨時訪問權限。 臨時訪問功能可減少應用需要在其清單文件中請求的權限數量。 當您啟用臨時權限時,只有持續訪問您的所有數據的應用才需要“永久性”提供程序訪問權限。

假設您需要實現電子郵件提供程序和應用的權限,如果您想允許外部圖像查看器應用顯示您的提供程序中的照片附件, 為了在不請求權限的情況下為圖像查看器提供必要的訪問權限,可以為照片的內容 URI 設置臨時權限。 對您的電子郵件應用進行相應設計,使應用能夠在用戶想要顯示照片時向圖像查看器發送一個 Intent,其中包含照片的內容 URI 以及權限標志。 圖像查看器可隨後查詢您的電子郵件提供程序以檢索照片,即使查看器不具備對您提供程序的正常讀取權限,也不受影響。

要想啟用臨時權限,請設置 元素的 android:grantUriPermissions 屬性,或者向您的 元素添加一個或多個 子元素。如果您使用了臨時權限,則每當您從提供程序中移除對某個內容 URI 的支持,並且該內容 URI 關聯了臨時權限時,都需要調用 Context.revokeUriPermission()。

該屬性的值決定可訪問的提供程序范圍。 如果該屬性設置為 true,則系統會向整個提供程序授予臨時權限,該權限將替代您的提供程序級別或路徑級別權限所需的任何其他權限。

如果此標志設置為 false,則您必須向 元素添加 子元素。每個子元素都指定授予的臨時權限所對應的一個或多個內容 URI。

要向應用授予臨時訪問權限, Intent 必須包含 FLAG_GRANT_READ_URI_PERMISSION 和/或 FLAG_GRANT_WRITE_URI_PERMISSION 標志。它們通過 setFlags() 方法進行設置。

如果 android:grantUriPermissions 屬性不存在,則假設其為 false。

元素


與 Activity 和 Service 組件類似,必須使用 元素在清單文件中為其應用定義 ContentProvider 的子類。 Android 系統會從該元素獲取以下信息:

權限 (android:authorities)

用於在系統內標識整個提供程序的符號名稱。

提供程序類名 ( android:name )

實現 ContentProvider 的類。

權限

指定其他應用訪問提供程序的數據所必須具備權限的屬性:

android:grantUriPermssions:臨時權限標志 android:permission:統一提供程序范圍讀取/寫入權限 android:readPermission:提供程序范圍讀取權限 android:writePermission:提供程序范圍寫入權限

實現內容提供程序權限部分對權限及其對應屬性做了更詳盡的描述。

啟動和控制屬性

這些屬性決定 Android 系統如何以及何時啟動提供程序、提供程序的進程特性以及其他運行時設置:

android:enabled:允許系統啟動提供程序的標志。 android:exported:允許其他應用使用此提供程序的標志。 android:initOrder:此提供程序相對於同一進程中其他提供程序的啟動順序。 android:multiProcess:允許系統在與調用客戶端相同的進程中啟動提供程序的標志。 android:process:應在其中運行提供程序的進程的名稱。 android:syncable:指示提供程序的數據將與服務器上的數據同步的標志。

開發指南中針對 元素的主題提供了這些屬性的完整資料。

信息屬性

提供程序的可選圖標和標簽:

android:icon:包含提供程序圖標的 Drawable 資源。 該圖標出現在設置 > 應用 > 全部中應用列表內的提供程序標簽旁; android:label:描述提供程序和/或其數據的信息標簽。 該標簽出現在設置 > 應用 > 全部中的應用列表內。

Intent 和數據訪問


應用可以通過 Intent 間接訪問內容提供程序。 應用不會調用 ContentResolver 或 ContentProvider 的任何方法,而會發送一個啟動 Activity 的 Intent,該 Activity 通常是提供程序自身應用的一部分。 目標 Activity 負責檢索和顯示其 UI 中的數據。視 Intent 中的操作而定,目標 Activity 可能還會提示用戶對提供程序的數據進行修改。 Intent 可能還包含目標 Activity 在 UI 中顯示的“extra”數據;用戶隨後可以選擇更改此數據,然後使用它來修改提供程序中的數據。

您可能想使用 Intent 訪問權限來幫助確保數據完整性。您的提供程序可能依賴於根據嚴格定義的業務邏輯插入、更新和刪除數據。 如果是這種情況,則允許其他應用直接修改您的數據可能會導致無效的數據。

處理想要修改您的提供程序數據的傳入 Intent 與處理其他 Intent 沒有區別。

 

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