preface

  • ContentProviderBelong toAndroidOne of the four components of
  • This paper has been thoroughly analyzedContentProvider, includingContentProviderPrinciple, usage & examples, I hope you will like it.

directory





Schematic diagram


Definition 1.

The content provider is one of the four components of Android


2. The role

Data exchange and sharing between processes, that is, cross-process communication





Schematic diagram


Principle 3.

  • ContentProviderThe underlying is adoptionAndroidIn theBindermechanism
  • Android Binder cross-process communication

4. Specific use

The use of ContentProvider is mainly introduced as follows:





image.png

4.1 Uniform Resource Identifier (URI)

  • Definition:Uniform Resource Identifier, uniform Resource Identifier (URI)
  • Function: Unique identifierContentProvider& the data

    External processes use the URI to find the corresponding ContentProvider & data, and then perform data manipulation

  • The specific use

    URIIt is divided into system preset and custom, corresponding to the built-in data (such as address book, schedule, etc.) and custom database respectively
    1. About System PresetsURIThis is not too much explanation, students need to check
    2. This section focuses on customizationURI





Schematic diagram

/ / set the URI URI URI = URI. Parse (" content: / / com. Carson. The provider/User / 1 "), / / the URI pointing to the resource is: Id = 1 in 'User' on 'ContentProvider' named 'com.carson. Provider' // Note that URI pattern matches wildcard * & # // * : Match any length of a string of any valid characters / / the following the URI of the means to match any content provider the content: / / com. The example. The app. The provider / * / / # : Match the number of arbitrary length character string / / the following uris match the provider of the every row of the table table content: / / com. Example. App. The provider/table / #Copy the code

4.2 MIME Data types

  • HTML files are opened by text applications, and PDF files are opened by flash applications

  • Specific use:

2ContentProviderAccording to theURIreturnMIMEtype

ContentProvider. GeType (uri);Copy the code

4.2.2 MIME Type Composition Each MIME type consists of two parts = type + subtype

A MIME type is a two-part string

Text/HTML // Type = text, subtype = HTML text/ CSS text/ XML application/ PDFCopy the code

4.2.3 MIME Type Forms MIME types have two forms:

// Form 1: single record vnd.android.cursor.item/ custom // Form 2: multiple records (set) vnd.android.cursor.dir/ custom // Note: // 1. VND: Indicates that parent and child types have non-standard, specific forms. // 2. The parent type is fixed (i.e. cannot be changed). Subtypes are customizableCopy the code

Example is given to illustrate

< - a single record - > / / a single record the MIME type of VND. Android. The cursor. The item/VND yourcompanyname. Contenttype / / if a Uri as follows The content: / / com. Example. Transportationprovider/trains / 122 / / ContentProvider will through the ContentProvider. GeType (url) returns the MIME type below VND. Android. Cursor. The item/VND. Example. The rail < - multiple records - > / / multiple records the MIME type VND. Android. Cursor. Dir/VND. Yourcompanyname. Contenttype / / if a Uri for the content as follows: / / com. Example. Transportationprovider/trains / / ContentProvider will through the ContentProvider. GeType (url) returns the MIME type VND. Android. The cursor. Dir/VND. Example. RailCopy the code

4.3 ContentProvider class

4.3.1 Way to organize data

  • ContentProvidermainlyTable formOrganize data

    File data is also supported, but in tabular form

  • Each table contains multiple tables, each containing rows and columns for records and fields

    With the database

4.3.2 Main methods

  • The essence of sharing data between processes is to add, delete, retrieve, and modify (update) data
  • soContentProviderThe core method is also mainly the above four functions
<-- 4 core methods --> public Uri insert Public int delete(Uri Uri, String Selection, Public int update(Uri Uri, ContentValues values, String Selection, String[] selectionArgs // External process updates ContentProvider data public Cursor query(Uri Uri, String[] projection, String Selection, String[] selectionArgs, String sortOrder); / / 1. The above four methods are called back by external processes and run in the Binder thread pool of the ContentProvider process (not the main thread) // 2. A. If the ContentProvider is used to store data using SQLite and one SQLite, then this is not necessary, because SQLite has implemented thread synchronization internally. If there are multiple SQLite, this is required. Thread synchronization cannot be performed between SQL objects. If the ContentProvider stores data in memory, Public Boolean onCreate() // The system calls the ContentProvider when it is accessed for the first time by another process Public String getType(Uri Uri) // Returns the MIME type of the data represented by the current UrlCopy the code
  • AndroidProvides built-in defaults for common data such as address book, calendar, etcContentProvider
  • But it can also be customized as requiredContentProviderBut the above six methods must be rewritten

    This article focuses on custom ContentProviders

  • ContentProviderClasses do not interact directly with external processes, but throughContentResolver

4.4 ContentResolver class

4.1 role

Manage operations between different ContentProviders in a unified manner

  1. throughURICan operate differentContentProviderThe data in the
  2. External process passesContentResolverclass Thus withContentProviderClass to interact

4.2 Why to use passContentResolverClass withContentProviderClasses interact instead of accessing them directlyContentProviderThe class?

A:

  • Typically, you use more than one appContentProviderIf you need to know eachContentProviderIn order to complete data interaction,Expensive & difficult to operate
  • So againContentProviderThere’s an extra one on the classContentResolverClass for allContentProviderUnified management.

4.3 Specific Use

The ContentResolver class provides four methods with the same name and function as the ContentProvider class

// The external process adds data to the ContentProvider. ContentValues values public int Delete (Uri Uri, String Selection, Public int update(Uri Uri, ContentValues values, String selection, String[] selectionArgs public Cursor query(Uri Uri) String[] projection, String selection, String[] selectionArgs, String sortOrder)Copy the code
  • Example is given to illustrate
// Before using ContentResolver, ContentResolver // you can getContentResolver by calling getContentResolver() in all classes that inherit the Context getContentResolver(); / / set the ContentProvider URI URI URI = URI. Parse (" content: / / cn. Scu. Myprovider/user "); Cursor = resolver.query(URI, null, null, null, "userid desc");Copy the code

Android provides three utility classes to aid ContentProvide:

  • ContentUris
  • UriMatcher
  • ContentObserver

4.5 ContentUris class

  • Function: operationURI
  • The specific use

    There are two core methods:WithAppendedId () &ParseId ()
// withAppendedId () Add an id to the URI URI URI = URI. Parse (" content: / / cn. Scu. Myprovider/user ") URI resultUri = ContentUris. WithAppendedId (URI, 7); / / the resulting Uri is: after the content: / / cn. Scu. Myprovider/user / 7 / / parseId () function: Obtain ID Uri Uri from the URL = Uri. Parse (" content: / / cn. Scu. Myprovider/user / 7 ") long personid = ContentUris. ParseId (Uri). // Get the result :7Copy the code

4.6 UriMatcher class

  • role

    1. inContentProviderRegistered inURI
    2. According to theURImatchingContentProviderThe corresponding data table in
  • The specific use

// Step 1: Initialize UriMatcher object UriMatcher matcher = new UriMatcher(urimatcher.no_match); // Constant urimatcher.no_match = does not match any path return code // that is, does not match anything when initialized // Step 2: Register URI (addURI ()) int URI_CODE_a = 1 in ContentProvider; Int URI_CODE_b = 2; matcher.addURI("cn.scu.myprovider", "user1", URI_CODE_a); matcher.addURI("cn.scu.myprovider", "user2", URI_CODE_b); If resource URI path = the content: / / / / cn. The scu. Myprovider/user1, return the registration code if URI_CODE_a / / path = content: URI resources / / cn. Scu. Myprovider/user2, URI_CODE_b // Step 3: Matches URI_CODE according to URI, (match ()) @override public String getType(Uri Uri) {Uri Uri = uri.parse (" content://cn.scu.myprovider/user1"); Switch (matcher.match(uri)){// The return code for matching according to the URI is URI_CODE_a // that is, matcher.match(URI) == URI_CODE_a case URI_CODE_a: return tableNameUser1; Case URI_CODE_b: return tableNameUser2; case URI_CODE_b: return tableNameUser2; case URI_CODE_b: return tableNameUser2; // If the return code matched by URI is URI_CODE_b, return the table named tableNameUser2 in ContentProvider}}Copy the code

4.7 ContentObserver class

  • Definition: Content observer
  • Role: ObservationUricauseContentProviderData changes in & notification to the outside world (i.e. visitors to that data)

    The ContentObserver class is triggered when the data in the ContentProvider changes (adding, deleting, and changing)

  • The specific use
// step 1: registerContentObserver ContentObserver getContentResolver().registercontentobserver (uri); // Register with the ContentResolver class and specify the URI to observe // Step 2: When the ContentProvider data for the URI changes, Public class UserContentProvider extends ContentProvider {public Uri insert(Uri Uri, ContentValues values) { db.insert("user", "userid", values); getContext().getContentResolver().notifyChange(uri, null); / / inform visitors}} / / step 3: remove the observer getContentResolver () unregisterContentObserver (uri). // This is also done using the ContentResolver classCopy the code

This concludes the use of ContentProvider


5. Examples

  • Due to theContentProviderIt is not only used for inter-process communication, but also for intra-process communication
  • So this example will takeContentProviderExplanation:
    1. In-process communication
    2. Interprocess communication
  • Example: The data source used isAndroidIn theSQLiteThe database

5.1 Intra-process Communication

  • Step description:

    1. Creating a database class
    2. The customContentProvider
    3. Registered createdContentProviderclass
    4. In-process accessContentProviderThe data of
  • The specific use

Step 1: Create a database class for the database operation see article: Android: SQLlite database operation most detailed analysis

DBHelper.java

Public class DBHelper extends SQLiteOpenHelper {private static final String DATABASE_NAME = "finch.db"; Public static final String USER_TABLE_NAME = "user"; public static final String JOB_TABLE_NAME = "job"; private static final int DATABASE_VERSION = 1; Public DBHelper(Context Context) {super(Context, DATABASE_NAME, null, DATABASE_VERSION); } @override public void onCreate(SQLiteDatabase db) {// CREATE two tables: user TABLE and profession TABLE db.execSQL("CREATE TABLE IF NOT EXISTS "+ USER_TABLE_NAME + "(_id INTEGER PRIMARY KEY AUTOINCREMENT," + " name TEXT)"); db.execSQL("CREATE TABLE IF NOT EXISTS " + JOB_TABLE_NAME + "(_id INTEGER PRIMARY KEY AUTOINCREMENT," + " job TEXT)"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }Copy the code

Step 2: Customize the ContentProvider class

public class MyProvider extends ContentProvider { private Context mContext; DBHelper mDbHelper = null; SQLiteDatabase db = null; public static final String AUTOHORITY = "cn.scu.myprovider"; Public static final int User_Code = 1; public static final int Job_Code = 2; Private static final UriMatcher mMatcher; private static final UriMatcher mMatcher; static{ mMatcher = new UriMatcher(UriMatcher.NO_MATCH); // initialize mmatcher. addURI(AUTOHORITY,"user", User_Code); mMatcher.addURI(AUTOHORITY, "job", Job_Code); If resource URI path = the content: / / / / cn. The scu. Myprovider/user, return the registration code if User_Code / / path = content: URI resources / / cn. Scu. Myprovider/job, /** * Init ContentProvider */ @override public Boolean onCreate() {mContext =  getContext(); MDbHelper = new DBHelper(getContext()); db = mDbHelper.getWritableDatabase(); Db. execSQL("delete from user"); db.execSQL("insert into user values(1,'Carson');" ); db.execSQL("insert into user values(2,'Kobe');" ); db.execSQL("delete from job"); db.execSQL("insert into job values(1,'Android');" ); db.execSQL("insert into job values(2,'iOS');" ); return true; } @override public Uri insert(Uri Uri, ContentValues values) {// Match URI_CODE with Uri, String table = getTableName(uri); String table = getTableName(uri); Db. insert(table, null, values); / / when the URI ContentProvider data changes, inform the outside world (i.e., access to the visitors to the ContentProvider data) mContext. GetContentResolver () notifyChange (URI, null); // // get ID from URL via ContentUris class // long PersonId = contenturis.parseId (uri); // System.out.println(personid); return uri; Public Cursor query(Uri Uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {// Match URI_CODE according to URI to match the corresponding table name in ContentProvider // This method is at the bottom String table = getTableName(URI); // // get ID from URL via ContentUris class // long PersonId = contenturis.parseId (uri); // System.out.println(personid); / / return db query data query (table, the projection, selection, selectionArgs, null, null, sortOrder, null); } /** * Override public int update(Uri Uri, ContentValues values, String selection, String[] selectionArgs) {return 0; } @override public int delete(Uri Uri, String selection, String[] selectionArgs) {return 0; } @override public String getType(Uri Uri) {return null; } private String getTableName(URI URI){String tableName = null; switch (mMatcher.match(uri)) { case User_Code: tableName = DBHelper.USER_TABLE_NAME; break; case Job_Code: tableName = DBHelper.JOB_TABLE_NAME; break; } return tableName; }}Copy the code

Step 3: Register the created ContentProvider class AndroidManifest.xml

<provider android:name="MyProvider"
                android:authorities="cn.scu.myprovider"
                    />Copy the code

Step 4: Access the data in the ContentProvider within the process

MainActivity.java

public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); / * * * to manipulate * / / / set the user table URI URI uri_user = URI. Parse (" content: / / cn. Scu. Myprovider/user "); ContentValues values = new ContentValues(); values.put("_id", 3); values.put("name", "Iverson"); // getContentResolver ContentResolver = getContentResolver(); Insert (uri_user,values); Cursor = resolver.query(uri_user, new String[]{"_id","name"}, null, null, null); while (cursor.moveToNext()){ System.out.println("query book:" + cursor.getInt(0) +" "+ cursor.getString(1)); } cursor.close(); // Close the cursor /** * operate on the job table */ / similar to the above except that the URI needs to be changed to match different URI codes to find different data resource URI uri_job = Uri.parse("content://cn.scu.myprovider/job"); Values2 = new ContentValues(); values2.put("_id", 3); values2.put("job", "NBA Player"); Resolver2 = getContentResolver(); Insert (uri_job,values2); insert(uri_job,values2); Cursor2 = resolver2.query(uri_job, new String[]{"_id","job"}, null, null, null); while (cursor2.moveToNext()){ System.out.println("query job:" + cursor2.getInt(0) +" "+ cursor2.getString(1)); } cursor2.close(); // Close cursor}}Copy the code

The results of





Schematic diagram

The source address

Carson-Ho Github address: ContentProvider

At this point, the sharing of data within the ContentProvider process is explained.


5.2 Data Sharing between Processes

  • Example: In this document, you need to create two processes, that is, two projects





Schematic diagram

  • The specific use

Process 1

The steps are as follows:

  1. Creating a database class
  2. The customContentProvider
  3. Registered createdContentProvider

The first two steps are the same as those in the preceding example, and are not described here. Step 3 is mainly described here.

Step 3: Register the created ContentProvider class AndroidManifest.xml

<provider Android :name="MyProvider" Android :authorities=" scut.carson_ho.myProvider" Android :permission="scut.carson_ho.PROVIDER" // It can be subdivided into read and write permissions. // The outside world needs to declare the same read and write permissions. // Android :readPermisson = "scut.carson_ho.Read" // Android :writePermisson = "scut.carson_ho.Write" // Android: Exported ="true" /> // Set the provider to be used by other processes android: Exported ="true" /> // Android :protectionLevel="normal"/> // This Demo uses full permission. // <permission Android :name="scut.carson_ho.Write" Android :protectionLevel="normal"/> // <permission android:name="scut.carson_ho.PROVIDER" android:protectionLevel="normal"/>Copy the code

At this point, process 1 has been created and is ready to create the ContentProvider & data.

The source address

Carson-Ho Github address: ContentProvider1


Process 2

Step 1: Declare accessible permissions

AndroidManifest.xml

<uses-permission android:name="scut.carson_ho.PROVIDER"/> This Demo uses full permission // <uses-permission Android :name=" scut.carson_ho.read "/> // <uses-permission Android :name="scut.carson_ho.Write"/> // Note: The declared permission must correspond to the permission set in process 1Copy the code

Step 2: Access the ContentProvider class

public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Parse ("content://scut.carson_ho.myprovider/user"); ContentValues values = new ContentValues(); values.put("_id", 4); values.put("name", "Jordan"); // getContentResolver ContentResolver = getContentResolver(); Insert (uri_user,values); Cursor = resolver.query(uri_user, new String[]{"_id","name"}, null, null, null); while (cursor.moveToNext()){ System.out.println("query book:" + cursor.getInt(0) +" "+ cursor.getString(1)); } cursor.close(); // Close the cursor /** * operate on the job table */ / similar to the above except that the URI needs to be changed to match different URI codes to find different data resource URI uri_job = Uri.parse("content://scut.carson_ho.myprovider/job"); Values2 = new ContentValues(); values2.put("_id", 4); values2.put("job", "NBA Player"); Resolver2 = getContentResolver(); Insert (uri_job,values2); insert(uri_job,values2); Cursor2 = resolver2.query(uri_job, new String[]{"_id","job"}, null, null, null); while (cursor2.moveToNext()){ System.out.println("query job:" + cursor2.getInt(0) +" "+ cursor2.getString(1)); } cursor2.close(); // Close cursor}}Copy the code

At this point, process 2 to access the ContentProvider data has been created

The source address

Carson-Ho Github address: ContentProvider2


The results show

During the process display, you need to run process 1, which prepares data, and then process 2, which accesses data

  1. Run process 1 that prepares the data. In process 1, we prepare a set of data



    Schematic diagram

  2. Run the process 2 that needs to access the data. In process 2, we insert the data into the ContentProvider and then query the data





Schematic diagram

This concludes the tutorial on the use of ContentProvider in and between processes.


Advantages of 6.

6.1 security

ContentProvider provides a secure environment for data interaction between applications. It allows you to add, delete, modify, and query your application data according to your needs without worrying about security problems caused by directly opening database permissions

6.2 Simple & efficient access

Compared with other data sharing modes, the data access modes vary depending on the data storage modes:

  • To share data in file mode, you need to perform file operations to read and write data.
  • usingSharedpreferencesTo share data, you need to use the SharedPreferences API to read and write data

This makes accessing the data complex & difficult.

  • And useContentProviderMode, which decouples the storage mode of the underlying data, so that no matter what mode of the underlying data storage is adopted, the external access to the data is unified, which makesEasy & efficient access

    If SQLite database is used for data storage at the beginning and MongoDB is changed later, the code used by the upper-layer data ContentProvider will not be affected





Schematic diagram


7. To summarize

  • I conclude this article with a diagram





Schematic diagram

  • The Underlying ContentProvider mechanism is the Android Binder, which provides cross-process communication with the Android Binder

  • In my next post, I’ll cover Android. If you’re interested, keep an eye out for Carson_Ho’s Android development notes


Thumb up, please! Because your encouragement is the biggest power that I write!

The Android event distribution mechanism is the most comprehensive and easy to understand solution for Android screen adaptation. It is the most comprehensive and easy to understand solution for Android screen adaptation. Android development: JSON introduction and the most comprehensive analysis method! BroadcastReceiver Is the most comprehensive version of Android’s BroadcastReceiver


Welcome to attentionCarson_HoJane books!

Share the dry things about Android development from time to time, the pursuit of short, flat, fast, but there is no lack of depth.