165 lines
5.2 KiB
Markdown
165 lines
5.2 KiB
Markdown
# Content Providers - Storage
|
||
|
||
Access to data is restricted to the app that owns it
|
||
|
||
- Database is usually located in internal app-specific storage
|
||
- If we want other apps to access our data, or we want to access other apps’ data, or we want to be notified when data has changed, we must use a content provider
|
||
|
||
Content providers expose data / content to other applications in a structured manner
|
||
|
||
- Fundamentally IPC via Binder and ashmem (Android shared memory) with a well-defined (database-like) interface
|
||
|
||
#### System Content Providers
|
||
|
||
Content providers manage data for:
|
||
|
||
**Browser**: bookmarks, history
|
||
|
||
**Call Log**: Telephone usage
|
||
|
||
**Contacts**: Contact data, contacts for other apps, e.g. WhatsApp
|
||
|
||
**Media**: Media metadata database
|
||
|
||
**User Dictionary**: database for predictive spelling
|
||
|
||
###### Storage Access Framework
|
||
|
||
Is an abstraction of *documents*
|
||
|
||
- Restricted access to external storage
|
||
- Enumerated by the system content object picker
|
||
|
||

|
||
|
||
A content provider is mostly used for making content available outside your application, as using it to get data is now done by the repository.
|
||
|
||
###### How to use it?
|
||
|
||
- Create our own by sub-classing `ContentProvider`
|
||
- Must add it in the manifest
|
||
- Or add/query data via an existing content provider
|
||
|
||
### Data Model
|
||
|
||
Very similar to a relational database table
|
||
|
||
- A collection of records
|
||
- Support for read/write
|
||
- Support for typical database operations
|
||
- CRUD - **C**reate **R**ead **U**pdate **D**elete
|
||
|
||
Records are stored in rows, with each column providing different data fields
|
||
|
||
- Each record has a numeric id (in the field ID) that uniquely identifies it
|
||
- Tables exposed via URI
|
||
- This is a further abstraction
|
||
|
||

|
||
|
||
Applications query the content provider, which maps the requests to the underlying database. This can be SQLite or Room (doesn’t really matter to the application)
|
||
|
||
### Querying a Content Provider
|
||
|
||
Content Providers **identify data** sets through **URIs**
|
||
|
||
- `content://authority/path/id`
|
||
- **content**: Data managed by a content provider
|
||
- **authority**: ID for the Content provider
|
||
- A fully qualified class name, e.g. `com.example.project`
|
||
- **path**: 0 or more segments indicating the subset of data to be requested
|
||
- e.g. table name
|
||
- A RESTful resource philosophy
|
||
- **id**: specific record (row) being accessed
|
||
|
||
`/email/2021/Nov/17` -> would retrieve all emails received on Nov 17th 📅
|
||
|
||
###### Content Resolver
|
||
|
||
- Manages and supports content provider access
|
||
- How to service a request for content
|
||
- Similar to `ServiceManager`
|
||
- Enables Content Providers to be used across multiple applications
|
||
- Can observe a content provider to be informed of real-time modifications
|
||
- e.g. `contentResolver` monitors the path and can notify if a new email pops up ✉
|
||
|
||
Full URI: `ContactsContract.Contact.CONTENT_URI = "content://com.android.contacts/contacts/"`
|
||
|
||
`ContentResolver.query(...)`
|
||
|
||
- Returns a cursor instance for accessing results
|
||
- Cursor is a pointer to a `cursorWindow`
|
||
- A read-only reference to shared memory
|
||
- Allocated by ashmem
|
||
- Retrieved via Binder
|
||
- Max `CursorWindow` size is 2 Mb
|
||
|
||
###### Example of Querying Contacts
|
||
|
||
- To access / modify requires a permission
|
||
- `android.permission.READ_CONTACTS`
|
||
- `android.permission.WRITE_CONTACTS`
|
||
- Contacts has 3 components
|
||
- Data
|
||
- Rows (mime-typed) that can hold personal info
|
||
- Raw Contacts
|
||
- A contact for a given person from a given system
|
||
- Gmail contact, Facebook contact, etc.
|
||
- Associated with data entries
|
||
- Contacts
|
||
- Aggregated raw contacts
|
||
- Single view of a *person*
|
||
|
||
##### Modifying a Content Provider
|
||
|
||
`Uri insert (Uri uri, ContentValues values)`
|
||
|
||
Returns the URI of the newly inserted item
|
||
|
||
`int update(Uri uri, ContentValues values, String where, String[] selectionArgs)`
|
||
|
||
###### Parameters
|
||
|
||
**uri**: the *table* we want to modify
|
||
|
||
**content values**: values for the new row or key/value pairs where the key is the column name
|
||
|
||
#### Creating a content Provider
|
||
|
||
- Implement a storage system for the data
|
||
- Structured data, can be SQLite or Room
|
||
- Media & blobs
|
||
- Implement a content provider
|
||
- query, add, update, insert, etc.
|
||
- onCreate
|
||
- When content provider is instantiated, needs to instantiate the internal storage (create the table)
|
||
- getType
|
||
- single items, multiple items, mime type
|
||
- Tell Android we are a provider
|
||
- Declare in the manifest
|
||
|
||
#### Contract
|
||
|
||
- Defines metadata pertaining to the provider
|
||
- Constant definitions that are exposed to developers via a compiled .jar file
|
||
- Authority
|
||
- URI
|
||
- Meta-data
|
||
- Column names
|
||
|
||
#### URI Matching
|
||
|
||
All of these methods take a URI as the first parameter
|
||
|
||
- The object will need to parse it to know what to return
|
||
|
||
`android.content.UriMatcher`
|
||
|
||
- Provides mapping between abstraction of contract class to concrete db implementation
|
||
- Does the calling app want all the data from the table or just a row?
|
||
- `content://authority/tablename/`
|
||
- whole table
|
||
- `content://authority/tablename/1`
|
||
- row
|
||
- Or a virtual table (joins across various underlying resources)
|