Interpreting Android ContentProvider (2) Create your own provider

Source: Internet
Author: User

This document is translated from Android official documentation, combined with your own tests, organized as follows.

Content provider Management data access, we can implement one or more custom provider in our own application (by inheriting the abstract class ContentProvider), of course these provider need to be registered in the manifest file. Although content provider is used to access data for other programs, activities in its own program can obviously handle that data.

Considerations before creating Provider

Determine if you need to provide content provider. You need to create a content provider if you have one or more of the following requirements:

    • A complex data or file that you want to provide to other programs;
    • Want to allow users to copy complex data from our program to another program;
    • You want to use the query framework to provide custom query suggestions.

If you are using a SQLite database inside your program, you do not need provider.

Next, create the provider by following these steps (a brief summary, followed by a detailed introduction):

    1. For data design storage, content provider is available in two ways:

      • File data
        Data is saved in files, examples, videos, audio and so on. These files are stored in private spaces and provider can provide external program access.
      • Structured data
        Such data is usually stored in databases, arrays, or similar structures, which can, of course, be saved in a table in a compatible manner. A row in the table represents an entity (record), and a column represents the value of the entity-related property. Usually this data is stored in the SQLite database, and of course it can be saved permanently.
    2. You need to inherit the abstract class ContentProvider and overwrite the necessary methods. This class is the interface between our data and other program interactions.

    3. Defines provider permissions (authority), content URIs, and column names. If the program wants to process intents, you must also define intent's action,extra data and flags. It is also necessary to define the license (permission) that other programs want to access the provider must request. It is common to consider defining these values as constants and defining them in another class.
    4. Add additional information.
Design data storage

Before providing provider, we have to determine how our data should be stored, and of course we can specify it, and then design the provider for that storage mode.

The following storage methods are available:

    • stored in the SQLite database. In this way we do not have to use a database, provider is represented as a set of tables, so there is no need to implement the related database internally.
    • stored in the file.
    • stored in the network.
Precautions
    • Table data typically requires a primary key, and provider assigns a unique value to each row. Although the primary key column can be any name, it is recommended BaseColumns._ID to use, so that the ListView can be easily retrieved.
    • If a bitmap or larger file data is provided, the data will be stored in a file and provided in an indirect manner. If we use this data, we should inform the client that they should use the file method in the Contentresovler class to get the data.
    • The size or structure of the stored BLOB data type can vary.
Design Content URIs

A content URI is a URI that identifies the data in the provider, including permissions (authority) and Paths (path). Permissions to find the provider, the path to find the table or file. You can also have an ID that can represent a row.

Design Permissions Authority

Permissions are used to distinguish between different programs, and are generally named in the form of package names in order to avoid conflicts. For example, if the package name is: com.example.sywyg , the permission can be: com.example.sywyg.provider .

Design path

The URI is a way to find the specified table by the permission plus path. Paths are distinguished from tables or other forms (such as files) in the same program, and can be added directly after permissions. For example, Table1 and table2, the resulting URIs are: com.example.sywyg.provider/table1 and com.example.sywyg.provider/table2 .

The final content URI needs to precede the permissions and paths with a content:// content URI. For example, a standard content URI is written as follows: content://com.example.sywyg.provider/table1 .

Handle the ID of the URI

Appending the ID to the URI allows you to retrieve the specified row in the table, with the ID corresponding to the column named _id.

URI Pattern Matching

The Urimatcher class maps the content URI pattern to an integer type number, which we can use to make pattern matching.

The URI pattern is matched by a wildcard character:

    • *: Matches any length and valid string;
    • #: Matches any length of numeric characters;

Assume that the permission is: com.example.app.provider , identify the table that corresponds to the following URI:

content: //com  Span class= "Hljs-preprocessor" >.example .app  .provider /table1: Table is table1. content: //com  .example  .app  .provider /table2/dataset1: Table is DataSet1. content: //com  .example  .app  .provider /table2/dataset2: Table is Dataset2. content: //com  .example  .app  .provider /table3: Table is table3.  

If you have an ID, you can also identify:
content://com.example.app.provider/table3/1Line 1th in table Table3

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

content://com.example.app.provider/table2/*Will match the table DataSet1 and Dataset2, but will not match table1 or table3.

content://com.example.app.provider/table3/#Will match any row in the Table3.
content://com.example.app.provider/table3/6Will match the 6th row in the Table3.

In summary, the URI standard is: content:///or content:////, the former for the table, the latter for the specified row.

We can use the Urimatcher class to quickly implement a content URI match. Common code is as follows:

Inheriting the ContentProvider class

The ContentProvider class can manage the data in our provider, and the external contentresovler can invoke the corresponding ContentProvider method to implement the Operation data. Therefore, we have to provide the appropriate method to manipulate the data.

Override method

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

    1. query()
      Retrieves the data and returns the cursor object.
    2. insert()
      Inserts a row of data, returning the URI of the newly inserted row.
    3. update()
      Updates a row that is present and returns the updated line number.
    4. delete()
      Deletes a row that exists, returning the deleted line number.
    5. getType()
      Returns the MIME type of the corresponding URI.
    6. onCreate()
      Initializes the provider. When the provider object is created, it is called immediately. Note the provider object is created only if the Contentresovler object attempts to access the data.

You can see methods that have the same name in Contentresovler for the above-mentioned methods of manipulating data.

There are a few things to consider when overriding a method:

    • In addition onCreate() to the method, you should pay attention to multi-threading security issues.
    • Avoid onCreate() long-time operations. The corresponding content is initialized until it is needed.
    • Although we need to implement these methods, we don't have to do anything except the return value. For example, we do not want the outside world to delete data, so we just need to return the corresponding line number instead of writing any code in the method.
Realize query()Method

The method returns a cursor object, or throws an exception if it fails. If the corresponding row is not found, a getCount() cursor object with a method of 0 should be returned. Null is returned only if an internal error occurs. If you use the SQLite database to save the data, you can call the Sqlitedatabase class query() method to return the cursor object directly. If you do not use it, you will use the specific subclass of the cursor class.

The following exceptions may be thrown at query time:

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

If you are accessing the SQLite database, the query() simple implementation code is as follows:

 Public  class exampleprovider extends contentprovider {    Private Static FinalUrimatcher Surimatcher; Surimatcher.adduri ("Com.example.app.provider","Table3",1); Surimatcher.adduri ("Com.example.app.provider","table3/#",2);the//parameter for Contentresovler calls the query () method passed over the     PublicCursorQuery(Uri Uri, string[] projection, string selection, string[] Selectionargs, String sortor Der) {Switch(Surimatcher.match (URI)) {//Correspondence Table3             Case 1:if(Textutils.isempty (sortOrder)) SortOrder ="_id ASC"; Break;//corresponds to Table3 with ID             Case 2: Selection = Selection +"_id ="Uri.getlastpathsegment (); Break;default:Throw NewIllegalArgumentException ("Unknown URI"+ URI); }//Actual query of SQLite database statements}
Realize insert()Method

The Insert method adds a new row to the specified table, and the data is from the data passed by the parameter contentvalues, and if a column is not specified, the default value (which depends on the provider or the database itself) is provided.

The method returns the URI of the new row. We can withAppendId() build the URI by Contenturis the URI by adding the primary key ID (usually _id) after the URIs. Directly through the parse() method is also OK.

Realize update()Method

Similar to insert, no longer described.

Realize delete()Method

Deletes the specified row. This method does not need to really delete a row, if we use the synchronization adapter, we can consider the first to delete the data to mark the deletion. The sync adapter can check out the deleted rows before actually deleting the data from provider, and remove them for false deletion.

Realize getType()Method

will be explained in detail in the following sections.

Realize onCreate()Method

The system calls the method when the provider is created onCreate() . We should ensure that the content initialized here is necessary and can be executed quickly, and that it is not necessary and time-consuming to initialize it when needed. For example, database creation and data loading can be performed when the operation data is actually requested. If it is too time-consuming, provider start-up can be time consuming, which obviously affects the program that responds to requests for that provider.

MIME type of ContentProvider

ContentProvider has two methods to return a type:

    • getType()
      This needs to be implemented in subclasses.
    • getStreamTypes()
      This is required if provider provides file access.
MIME type of table

getType()method returns a MIME-formatted string that describes the data type for the parameter URI. The parameter URI can match a pattern instead of the specified URI, so we should return and match the pattern of the URIs related data type.

For the common type: Text,html,jpeg, the getType() method should return the standard MIME type.

For URIs that specify one or more rows, the getType() method should return the MIME format specified by Android:

    • Type section: VND
    • Subtype section:
      • URI pattern is only one line: android.cursor.item/
      • URI pattern has multiple lines: android.cursor.dir/
    • Provider designation section: VND.
      The name should be globally unique, and the type should be unique to the corresponding URI pattern. Typically, name should be the package name, and type should be the name of the table associated with the URI.
      For example, with the provider permission of com.example.app.provider the table named: Table1, the MIME type of the Table1 multiline is:
      vnd.android.cursor.dir/vnd.com.example.provider.table1
      The MIME type of a single line is:
      vnd.android.cursor.item/vnd.com.example.provider.table1
MIME type of File

You need to implement the method if provider provides the file getStreamTypes() . The 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 client wants to process.

For example, provider provides picture files:. jpg,.png and. gif formats. If a program calls the getStreamTypes() image/* using the filter parameter, the method returns:
{ "image/jpeg", "image/png", "image/gif"}
If the program requires only. jpg, you can use the filter parameter *\/jpeg, then the method returns:
{"image/jpeg"}
If provider does not provide a type, the method returns NULL.

Implementing related Classes

You typically need a public final type of related class to define constants: URIs, column names, MIME, or other provider-related information. This class enables provider and other programs to establish a relationship that ensures that the provider is properly fetched.

For other programs, the associated class can be manipulated using the. jar file we provide, which enables operation provider.

Implement content provider Licensing

There are several points to note:

    • By default, data files stored in device memory (not running memory) are private to our programs and provider.
    • SQLite database is our program and provider private.
    • By default, the data that is saved on the memory card is public and can be accessed. We cannot use provider to restrict access to this data.
    • A method call to open or create a file on storage memory or a SQLite database potentially grants other programs permission to read and write to that data. If we use the data stored in memory as provider data sets, other programs have read and write permissions, and our manifest settings will not work. The default fetch data is private and should not be changed.

If we want to use the content provider permission to control the reading of the data, we need to store the data in internal files, SQLite databases or servers, and make sure that the files and databases are private.

Implementing a License

By default, provider does not have a license set and all programs have access to provider data. We can <provider> configure the properties or sub-tags of the tags in the mainfest file. Licenses can be configured for the entire provider or for specific tables or for specific records.

Declare the license <permission> to use the label, for example:
<permission android:name="com.example.app.provider.permission.READ_PROVIDER">

The detailed licensing settings for provider are described below:

  • Single provider read/write license (read-write provider-level permission)
    This license controls the read-write permission of the entire provider. <provider>set in the properties in the tag android:permission .
  • Provider level separate read or write permissions (separate read and write Provider-level permission

    <provider>set the Read permission in the properties in the tag, android:readPermission <provider> and set the Write permission in the properties in the tag android:writePermission . These two licenses are better than the licenses set by Android:permission.
  • Path-level Licensing (Path-level permission)
    Read or write or read or write permission to the specified URI. <provider>set in a sub-tab in the label <path-permission> . This level of authority is superior to the two licenses above.
  • Temporary license (Temporary permission)
    Grant the program permission to obtain data temporarily.
    Set in the <provider> properties in the tag android:grantUriPermissions , or <provider> <grant-uri-permission> add one or more to the child labels in the label.
    If a temporary license is used, it must be called whenever support for a URI is removed from provider, Context.revokeUriPermission() and the URI is related to the temporary license. If this property is set to True, the system supports licensing of temporary licenses and overrides any other license (provider level or path level).
    If False is set, you will need to <provider> <grant-uri-permission> add one or more of the child tags in the label. Each sub-label specifies that one or more URIs have temporary access to the license.

    In order to delegate temporary access permission in a program, intent must FLAG_GRANT_READ_URI_PERMISSION contain FLAG_GRANT_WRITE_URI_PERMISSION one or two flags (by setFlags() setting) in and.

    If the property is not set, it is android:grantUriPermissions considered false.

<provider>Label

We know that the four components need to be configured in the Mainfest file, and the ContentProvider implementation class is configured via a <provider> label. Some important attributes and sub-tags are also included in the tag:

    • android:authorities
      Used to identify provider in this system (identify the application first).
    • android:name
      The class name of the implementation class for ContentProvider.
    • Permission
      The above is described in detail, mainly including:

      - `android:grantUriPermssions`;- `android:permission`;- `android:readPermission`;- `android:writePermission`。
    • Start and Control properties

      • android:enabledWhether to allow instantiation
      • android:exportedWhether the external can be used
      • android:initOrderAn integer value that represents the order that is initialized in the same process, and the higher the value, the sooner it is initialized
      • android:multiProcessWhether to allow instantiation in multiple processes
      • android:processThe process in which it resides
      • android:syncable
    • Information properties

      • android:iconIcon
      • android:labelName
Summarize

The collaborative relationship between Contentresovler and ContentProvider is described by querying the SQLite database as an example:

The query() parameter URI in the method of the Contentresovler object, through the permission authority in the URI, can find the corresponding ContentProvider implementation class, instantiate the class and invoke the query() method, in the query() method through UriMatcher.match() The method matches the URI, matches the query method to the SQLite database after the successful match, returns the cursor, and returns the cursor to the caller via the ContentProvider instance. You can see that through permissions you can determine a provider, so you can include more than one providers in a program.
Legacy issues:

    • Multithreading security issues.

Interpreting Android ContentProvider (2) Create your own provider

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.