Content Providers是Android四大組件之一,扮演者非常重要的角色,看下官方文檔對它的解釋:
Content providers manage access to a structured set of data. They encapsulate the data, and provide mechanisms for defining data security. Content providers are the standard interface that
connects data in one process with code running in another process.
可以看到Content providers負責管理結構化資料的訪問,Content providers封裝資料並且提供一套定義資料安全的機制。Content providers是一套在不同進程間進行資料訪問的介面。
Content providers為資料跨進程訪問提供了一套安全的訪問機制,對資料群組織和安全訪問提供了可靠的保證。
另外來看看官方文檔是如何解釋Content Providers的使用的:
When you want to access data in a content provider, you use theContentResolver object
in your application's Context to communicate with the provider as a client. The ContentResolverobject
communicates with the provider object, an instance of a class that implements ContentProvider. The provider object receives data
requests from clients, performs the requested action, and returns the results.
意思是當你想要通過Content Providers訪問資料時,在應用程式的上下文(Context)中使用ContentResolver對象最為用戶端(client)與provider進行互動。ContentResolver對象通過實現抽象類別ContentProvider的一個執行個體來訪問provider。Provider對象從用戶端(client)接收資料請求,執行請求操作並且返回請求結果。
Android通過Content Provider來管理資料諸如音頻、視頻、圖片和通訊錄等。還可以通過ContentProvider來訪問SQLite資料庫等,下面來看看Content Provider的基本使用。
在此之前,官方文檔中給出了一些是否需要需用Content Providers的建議:
Decide if you need a content provider. You need to build a content provider if you want to provide one or more of the following features:
- You want to offer complex data or files to other applications.
- You want to allow users to copy complex data from your app into other apps.
- You want to provide custom search suggestions using the search framework.
在以下情況下你需要使用Content Providers:
1.你想為其他應用程式提供複雜資料或檔案;
2.你想允許使用者從你的應用程式中拷貝複雜資料到其他的應用中
3.你想使用搜尋方塊架提供自訂的查詢建議功能
Content Provider通過URI(統一資源定位器)來訪問資料,URI可以理解為訪問資料的唯一地址,URI由authority和資料地址構成,關於authority可以理解成網站地址中的主機地址,而資料地址可以理解成某一個頁面的子地址,二者共同構成了一個完整的訪問地址,關於authority的命名,官方文檔中有這麼一句話 If your Android package
name iscom.example.<appname>, you should give your provider the authority com.example.<appname>.provider.可見對於authority的命名還是有一定的規範性的。
關於URI的格式:content://<authority>/<path>/<id>,path就是資料路徑,比如說一張表,而id就是這張表中主鍵為id的一行,也可以理解成一個實體物件。
看下構建Content Provider和使用URI的代碼:
publicclassExampleProviderextendsContentProvider{... // Creates a UriMatcher object. privatestaticfinalUriMatcher 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. * 這裡說明了兩種萬用字元的作用 * *: Matches a string of any valid characters of any length. * #: Matches a string of numeric characters of any length. */ sUriMatcher.addURI("com.example.app.provider","table3/#",2);... // Implements ContentProvider.query() publicCursor 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 case1: if(TextUtils.isEmpty(sortOrder)) sortOrder ="_ID ASC"; break; // If the incoming URI was for a single row case2: /* * 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 }
實現抽象類別ContentProvider後,有幾個需要實現的方法:
query()
Retrieve data from your provider. Use the arguments to select the table to query, the rows and columns to return, and the sort order of the result. Return the data as a Cursor object.
insert()
Insert a new row into your provider. Use the arguments to select the destination table and to get the column values to use. Return a content URI for the newly-inserted row.
update()
Update existing rows in your provider. Use the arguments to select the table and rows to update and to get the updated column values. Return the number of rows updated.
delete()
Delete rows from your provider. Use the arguments to select the table and the rows to delete. Return the number of rows deleted.
getType()
Return the MIME type corresponding to a content URI. This method is described in more detail in the sectionImplementing Content
Provider MIME Types.
onCreate()
Initialize your provider. The Android system calls this method immediately after it creates your provider. Notice that your provider is not created until a ContentResolver object
tries to access it.
舉一個例子,如果使用SQLite作為Content Provider的資料來源,下面這段程式碼片段建立了SQLiteOpenHelper的子類MainDatabaseHelper,並且產生了表main
// A string that defines the SQL statement for creating a tableprivatestaticfinalString 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. */protectedstaticfinalclassMainDatabaseHelperextendsSQLiteOpenHelper{ /* * 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. */ publicvoid onCreate(SQLiteDatabase db){ // Creates the main table db.execSQL(SQL_CREATE_MAIN); } }
然後定義ContentProvider來操作資料庫,這樣,就建立了一套在資料來源(SQLite)和用戶端(client)之間的介面
publicclassExampleProviderextendsContentProvider /* * Defines a handle to the database helper object. The MainDatabaseHelper class is defined * in a following snippet. */ privateMainDatabaseHelper mOpenHelper; // Defines the database name privatestaticfinalString DBNAME ="mydb"; // Holds the database object privateSQLiteDatabase db; publicboolean 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 =newSQLiteOpenHelper( getContext(), // the application context DBNAME, // the name of the database) null, // uses the default SQLite cursor 1 // the version number ); returntrue; } ... // Implements the provider's insert method publicCursor 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(); } }
簡單的總結一些Content Providers:
1.Content Providers是Android系統中四大組件之一,提供一套在用戶端(client)和資料來源(data source)之間的提供者
2.Content Providers可以提供跨進程訪問資料的功能,能暴露本機資料給其他應用訪問
3.實現Content Providers只需要繼承抽象類別ContentProvider並實現必要的抽象方法即可,訪問ContentProvider則根據URI來訪問
以上簡單介紹了下ContentProvider,資料來源是Android官方文檔,有不足之處還望指教
參考:http://developer.android.com/guide/topics/providers/content-providers.html
加入我們的QQ群或公眾帳號請查看:Ryan's
zone公眾帳號及QQ群
歡迎關注我的新浪微博:@唐韌_Ryan