Interpreting Android ContentProvider (2) creating your own Provider and android creating provider

Source: Internet
Author: User

Interpreting Android ContentProvider (2) creating your own Provider and android creating provider

This article is translated from the official android documentation and tested by yourself.

Content provider manages data access. We can implement one or more custom providers in our own applications (by inheriting the abstract class ContentProvider ), of course, these providers must be registered in the manifest file. Although content providers are used to access data for other programs, activities in their own programs can obviously process the data.

Notes before creating a provider

Determine whether the content provider is required. To meet one or more of the following requirements, you must create a content provider:

  • To provide complex data or files to other programs;
  • To allow users to copy complex data from our program to another program;
  • You want to use the query framework to provide custom query recommendations.

If the SQLite database is used in the program, no provider is required.

Next, follow these steps to create a provider ):

The above steps are described in detail below.

Design Data Storage

Before providing the provider, we must determine how to store our data. Of course, we can specify the storage method and then design the provider for the storage method.

There are several storage methods:

  • Stored in the SQLite database.
  • Stored in files.
  • Stored in the network.

For this part, refer to my translated article: Android Data Storage Solution

Notes
  • A primary key is usually required for table data. The provider assigns a unique value to each row. Although the primary key column can be any name, we recommend that you useBaseColumns._IDIn this way, you can easily search in ListView.
  • If a bitmap or larger file data is provided, the data is stored in the file and provided indirectly. If the data is used, we should notify external applications that they should use the file method in the ContentResovler class to obtain the data, suchopenInputStream(Uri uri)AndopenOutputStream(Uri uri).
  • If the BLOB data type is stored, the size or structure will change. We can use BLOB to implement a schema-independent table. For this type of table, we need to define a primary key, a MIME-type column, and one or more BLOB-type columns. The meaning of data in the BLOB column is expressed by the value in the MIME type column. This method allows different row types to be stored in the same table.
Design Content: URIs

Content URI is the URI that can recognize data in the provider, including authority and path ). Find the permission provider and find the table or file in the path. You can also have an id that represents a row.

Design permission authority

Permissions are used to differentiate the providers of different programs. Generally, to avoid conflicts, they are named in the form of package names. For example, the package name is:com.example.sywyg, The permission can be:com.example.sywyg.provider. In the AndroidManifest configuration file<provider>Label settings<android:authority>Label.

Design path

URI is used to search for the specified table by adding the permission and path. The path is to distinguish between tables or other forms (such as files) in the same program, and can be directly added after the permission. For example, table1 and table2 form the following Uris:com.example.sywyg.provider/table1Andcom.example.sywyg.provider/table2.

The URI must be added before the permission and path.content://Indicates the content URI. For example, a standard content URI is written as follows:content://com.example.sywyg.provider/table1.

ID of the URI

Append the ID to the URI to retrieve the specified row in the table. The column name corresponding to the ID is _ ID.

URI pattern matching

UriMatcher class ing content URI mode to an integer type number, we can use this value for pattern matching.

URI mode matches by wildcards:

  • *: Match any length and Valid String;
  • #: Match numbers of any length;

Assume the permission is:com.example.app.providerTo identify the table corresponding to the URI below:

'
Content: // com. example. app. provider/table1: The table is table1.
Content: // com. example. app. provider/table2/dataset1: The table is dataset1.
Content: // com. example. app. provider/table2/dataset2: The table is dataset2.
Content: // com. example. app. provider/table3: The table is table3.

`

If it carries an ID, it can also be identified:
content://com.example.app.provider/table3/11st rows in Table 3

The following URI mode:
content://com.example.app.provider/*
Match any URI in the provider

content://com.example.app.provider/table2/*Dataset1 and dataset2 will be matched, but table1 or table3 will not be matched.

content://com.example.app.provider/table3/#Any row in Table 3 will be matched.
content://com.example.app.provider/table3/6The 6th rows in Table 3 are matched.

To sum up, the URI standard is: content: // or content: //. The former is for the table and the latter is for the specified row.

We can use the UriMatcher class to quickly match the content URI. Common Code:

public static UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);mUriMatcher.addURI(authority,path,customMatch);

addURI()Parses the string authority and string path as follows:content://<authority>/<path>(The path here can contain an id .)match(URI)Method to match the string customMatch,match(URI)The returned value is the customMatch (addURI()The third parameter), which can be used to respond to the data that the caller expects to access.

Other classes, such as ContentUris, Uri, and Uri. Builder. ContentUris allows you to easily add an id after a uri. Uri and Uri. builder can easily parse the Uri object and generate a new Uri object.

Inherit ContentProvider class

The ContentProvider class can manage the data in our provider. External programs can use the ContentResovler object to call the corresponding ContentProvider method to implement data operations. Therefore, we must provide corresponding methods to operate data.

Overwrite Method

We need to implement the following methods to facilitate ContentResovler to access data.

We can see that the ContentResovler has the same name for the methods of the preceding operations, and the parameters are the same.

Pay attention to the following points when overwriting methods:

  • BesidesonCreate()You must pay attention to the multi-thread security issues in other methods.
  • AvoidonCreate()For a long time. Wait until the corresponding content is initialized as needed.
  • Although we need to implement these methods, we do not need to do anything except the return value. For example, we do not want to delete data, so we only need to return the corresponding row number, instead of writing any code in the method.
Implementation query()Method

This method returns a Cursor object or throws an exception if it fails. If no corresponding row is found,getCount()The Cursor object whose method is 0. Null is returned only when an internal error occurs. If you use the SQLite database to save data, you can directly callquery()Method to return the Cursor object. If you do not use it, you must use a specific subclass of the Cursor class.

The following exceptions may be thrown during query:

  • IllegalArgumentException (when an invalid URI is received)
  • NullPointerException

If the SQLite database is accessedquery()The simple implementation code is as follows:

Public class ExampleProvider extends ContentProvider {private static final UriMatcher sUriMatcher; sUriMatcher. addURI ("com. example. app. provider "," table3 ", 1); sUriMatcher. addURI ("com. example. app. provider "," table3/# ", 2); // The parameter is the public Cursor query (Uri uri, String [] projection, String selection, string [] selectionArgs, String sortOrder) {switch (sUriMatcher. match (uri) {// corresponding to table3 case 1: if (TextUtils. isEmpty (sortOrder) sortOrder = "_ id asc"; break; // corresponding to table3 case 2 with id: selection = selection + "_ ID =" uri. getLastPathSegment (); break; default: throw new IllegalArgumentException ("Unknown URI" + uri);} // The actual SQLite database query statement}
Implementation insert()Method

The insert method adds a new row to the specified table. The data comes from the data transmitted by the ContentValues parameter. If a column is not specified, the default value is provided (the default value depends on the provider or the database itself ).

This method returns the URI of the new row. We can use ContentUris'swithAppendId()Add the primary key ID (usually _ ID) after the URI to construct the URI. Directly passparse()Method.

Implementation update()Method

It is similar to insert.

Implementation delete()Method

Deletes a specified row. This method does not need to delete a row. If we use a synchronization adapter, we can mark and delete the data to be deleted first. The synchronization adapter can check the deleted rows before deleting the data from the provider, and exclude these rows for false deletion.

Implementation getType()Method

The following sections describe in detail.

Implementation onCreate()Method

When a provider is created, the system callsonCreate()Method. We should ensure that the content initialized here is required and can be executed quickly. For non-essential and time-consuming content, it can be initialized as needed. For example, database creation and data loading can be performed again when the data is actually requested. If it is too time-consuming, it will take time for the provider to start. Obviously, this will affect the program that responds to the provider request.

MIME Type of ContentProvider

ContentProvider has two return types:

  • getType()
    This needs to be implemented in the subclass
  • getStreamTypes()
    If the provider provides file access, you need to implement this.
MIME Type of the table

getType()Method returns a MIME-formatted string to describe the data type corresponding to the parameter URI. The parameter Uri can be a matching pattern rather than a detailed URI, so that we should return the MIME type related to the URL of the matching pattern.

For common types: text, HTML, JPEG,getType()The method should return the standard MIME type.

For the URIs of a specified row or multiple rows,getType()The method should return the MIME format specified by android:

  • Type part: vnd
  • Subtype:
    • URI mode has only one row: android. cursor. item/
    • URI mode has multiple lines: android. cursor. dir/
  • Specified by Provider: vnd ..
    Name should be globally unique, and type should be unique in the URI mode. Generally, the name should be the package name, And the type should be the URI-related table name.
    For example, the provider permission iscom.example.app.provider, Table name: table1, the MIME type of multiple rows of table1 is:
    vnd.android.cursor.dir/vnd.com.example.provider.table1
    The MIME type of a single row is:
    vnd.android.cursor.item/vnd.com.example.provider.table1
Object MIME type

If the provider provides file access, you must implementgetStreamTypes()Method. This method returns a MIME-type String Array Based on the given URI. We should filter the MIME type based on the MIME type filter parameter to return the MIME type that the external program wants to process.

For example, the provider provides image files in the format of .jpg, .png, and .gif. If a program callsgetStreamTypes()If the filter parameter image/* is used, this method returns:
{ "image/jpeg", "image/png", "image/gif"}
If the program only uses the. JPG file, you can use the filter parameter * \/jpeg, then the method returns:
{"image/jpeg"}

If the provider does not provide a type, the method returns null.

Implementation class

A public final class is generally required to define constants: URIs, column name, MIME, or other provider-related information. This class enables the provider to establish a relationship with other programs to ensure that the provider is correctly obtained. For other programs, you can use the. jar file we provide to operate on this class, and then implement the operation provider.

Implement Content Provider permission

Pay attention to the following points:

  • By default, data files stored in the device memory (not running memory) are private to our programs and providers.
  • SQLite databases are private to our programs and providers.
  • By default, data stored on the memory card is public. External programs can access the data. We cannot use providers to restrict access to the data.
  • Opening or creating a file in the storage memory or calling the SQLite database method potentially grants other programs the permission to read and write the data. If you use the data stored in the memory as the provider's dataset, other programs have read and write permissions, but what we set in manifest does not work. The data obtained by default is private and should not be changed.

If we want to use the content provider permission to Control Data Reading, We need to store the data in internal files, SQLite databases or servers, and ensure that these files and databases are private.

Implement license

By default, no permission is set for the provider, and all programs can obtain the provider data. In the mainfest file<provider>Tag attributes or sub-tag configurations. The license can be configured for the entire provider, a specific table, or a specific record.

Declare license<permission>Tag, for example:
<permission android:name="com.example.app.provider.permission.READ_PROVIDER">

The detailed license settings of providers are described below:

  • Single read-write provider-level permission)
    This license controls the read and write permissions of the entire provider. In<provider>Labelandroid:permissionAttribute.
  • Separate read or write permissions at the provider level (Separate read and write provider-level permission
    )
    In<provider>Labelandroid:readPermissionSet the read permission in<provider>Labelandroid:writePermissionSet write permission in properties. These two licenses are better than those set for android: permission.
  • Path-level permission)
    Permission to read, write, or read a specified URI. In<provider>Label<path-permission>Sub-label settings. This level of permission is superior to the above two permissions.
  • Temporary License (Temporary permission)
    Grant the program temporary permission to obtain data.
    In<provider>Labelandroid:grantUriPermissionsAttribute, or<provider>Label<grant-uri-permission>Add one or more sub-tags.
    If a temporary license is used, you must callContext.revokeUriPermission()The URI is related to the temporary license. If this attribute is set to true, The system supports authorizing temporary licenses and overwriting any other licenses (provider-level or path-level ).
    If false is set<provider>Label<grant-uri-permission>Add one or more sub-tags. Each sub-tag specifies that one or more URIs have temporary access permission.

    Intent must containFLAG_GRANT_READ_URI_PERMISSIONAndFLAG_GRANT_WRITE_URI_PERMISSIONOne or two flags insetFlags()).

    If notandroid:grantUriPermissionsAttribute is considered as false.

<provider>Tag

We know that all the four components need to be configured in the mainfest file. The ContentProvider implementation class uses<provider>Label configuration. This tag also includes some important attributes and sub-tags:

  • android:authorities
    Identifies the provider in this system (first identifies the application ).
  • android:name
    The name of the ContentProvider implementation class.
  • Permission
    It has been described in detail above, mainly including:

    - `android:grantUriPermssions`;- `android:permission`;- `android:readPermission`;- `android:writePermission`。
  • Launch and Control Properties

    • android:enabledWhether instantiation is allowed
    • android:exportedWhether external services can be used
    • android:initOrderInteger value indicates the initialization order in the same process. The larger the value, the earlier it is initialized.
    • android:multiProcessWhether instantiation is allowed in multiple processes
    • android:processProcess
    • android:syncable
  • Information attributes

    • android:iconIcon
    • android:labelName
Summary

The collaboration between ContentResovler and ContentProvider is described by querying the SQLite database as an example:

ContentResovler objectquery()The parameter URI in the method. The permission authority in the URI can be used to find the corresponding ContentProvider implementation class, instantiate the class and callquery()Method, inquery()TheUriMatcher.match()The method matches the Uri, returns the method to the SQLite database, returns the Cursor, and then returns the Cursor to the caller through the ContentProvider instance. The permission can be used to determine a provider. Therefore, a program can contain multiple providers.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.