This is the first day of my participation in the Gwen Challenge in November. Check out the details: the last Gwen Challenge in 2021

This study note is mainly to learn the basic knowledge of ContentProvider, through the operation of adding, deleting, changing and checking contact information, to understand how to provide program data through ContentProvider operation. This study note is based on the basics of content providers and can be accessed directly by clicking on the link to the official documentation.

An overview of the

Content providers help manage access to data stored by themselves and other applications, and provide ways to share data with other applications. They encapsulate data and provide a mechanism for defining data security.

A content provider is a standard interface that connects data in one process to code in another. By configuring content providers, other applications can securely access and modify the data of the current application.

basis

Access the content provider

If you need to access data in the content provider, you can use the Context’s ContentResolver object on the client side to communicate with the provider. The provider object receives the data request from the client, performs the requested action, and returns the result. Some methods of the ContentResolver object call methods of the same name in the provider object. The ContentResolver method provides basic CRUD (create, retrieve, update, and delete) functionality for a persistent storage space.

Android’s address book is one of the built-in providers where users can store address book information. If we need to query the current phone’s contact list, we can call the contentresolver.query () method, which calls the query() method in the ContentProvider. The following code shows how to retrieve the current phone’s contact list:

    // Read contact data
    private fun queryContactList(a) {
        // Request contact information
        val cursor = this.contentResolver.query(
            ContactsContract.Contacts.CONTENT_URI,
            null.null.null.null) cursor? .let {while (it.moveToNext()){
                val rawId = it.getString(it.getColumnIndex(ContactsContract.Contacts.NAME_RAW_CONTACT_ID))
                // Request contact information according to rawId
                val dataCursor = this.contentResolver.query(
                    ContactsContract.Data.CONTENT_URI,
                    null."${ContactsContract.Data.RAW_CONTACT_ID}=? ",
                    arrayOf(rawId.toString()),
                    null,
                )?.apply {
                    while (this.moveToNext()) {
                        // Get the type information
                        val mimeType = this.getString(this.getColumnIndex(ContactsContract.Data.MIMETYPE))
                        var name = ""
                        var phone = ""
                        when(mimeType){
                            ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE -> {
                                name = this.getString(this.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME))
                            }
                            ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE -> {
                                phone = this.getString(this.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))
                            }
                        }
                        Log.i(TAG, "queryContactList: contact name is:$name,phone is:$phone") } } dataCursor? .close() } } cursor? .close() }Copy the code

The function of the above code is to retrieve the name and phone number of each contact from the contact database. We first query the rawId of all original contacts through the ContentResolver query() method, and then use these RAwiDs to find specific information.

Query (); query();

The query () parameters Parameter of the SELECT keyword note
Uri FROM table_name The Uri maps to the table named table_name in the provider
projection col,col,col… We need to query an array of column names
selection where col = ? Specifies the condition for the selected row
selectionAtgs In place of selection? The value of the We need to specify the conditional value
sortOrder ORDER BY col,col Specified returnCursorThe display order of each line in

contentUri

The content Uri is used to identify data in the provider. The content Uri contains the symbolic name of the entire provider (that is, the authority part of the Uri) and the name pointing to the table (that is, the PATH part of the Uri).

In the code above, we use ContactsContract. Contacts. The constant CONTENT_URI to say we need to query the path of the table. The ContentResolver object resolves the Uri’s authorization and compares it to a system table of known providers to resolve the provider. The ContentResolver can then assign the query parameters to the correct provider.

The ContentProvider uses the path portion of the content Uri to represent the name of the table to be accessed. Typically, a provider displays a path for each table it exposes.

In the code above, ContactsContract. Contacts. CONTENT_URI full path is:

content://com.android.contacts/contacts

Also, many applications support adding an ID to the end of a Uri without specifying a specific line to query. For example, in the above code, we only want to query for the contact whose rawId is 2, so we could set the Uri to:

val cursor = this.contentResolver.query(
    ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI,2),
    null.null.null.null
)
Copy the code

We use the ID value when we retrieve many rows and want to update or delete a row.

Insert, update, and delete data

Similar to retrieving data from the provider, we can modify the data through the interaction between the provider client and the provider’s ContentProvider. We can invoke the methods of ContentResolver using arguments passed to the corresponding methods of ContentProvider, and the provider and provider client handle security and interprocess communication automatically.

Insert data

If we need to insert data into the provider, we can do so by calling the contentresolver.insert () method. This method inserts a new line in the provider and returns a content Uri for that line. The following code demonstrates how to insert a new contact into the address book:

*/ Private fun addRawContact(accountName: accountName, accountName, accountName, accountName, accountName, accountName, accountName, accountName, accountName) String, accountType: Var id = -1l var id = -1l val value = ContentValues() var id = -1l val value = ContentValues() value.put(ContactsContract.RawContacts.ACCOUNT_NAME, accountName) value.put(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType) val uri = this.contentResolver.insert( ContactsContract.RawContacts.CONTENT_URI, value ) if (uri ! If (id == -1l) {showInfo(r.string.can_not_create_account)} else {addContact(id)}} private fun addContact(rawId: Long) { val name = mBinding.etContactName.text.toString() val phone = mBinding.etContactPhoneNumber.text.toString() // After we have the account ID, we need to store the contact information in the account. We will not judge whether the contact information is duplicate. Directly inserted into the Data / / insert first name information val nameContentValues = ContentValues () nameContentValues. Put (ContactsContract. Data. RAW_CONTACT_ID, rawId) nameContentValues.put( ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE ) nameContentValues.put(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, Name) / / and then inserted into the mobile phone number information val phoneContentValues = ContentValues () phoneContentValues. Put (ContactsContract. Data. RAW_CONTACT_ID, rawId) phoneContentValues.put( ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE ) phoneContentValues.put(ContactsContract.CommonDataKinds.Phone.NUMBER, Phone) / / insert this. ContentResolver. Insert (ContactsContract. Data. CONTENT_URI, nameContentValues) this.contentResolver.insert(ContactsContract.Data.CONTENT_URI, phoneContentValues) }Copy the code

The above code demonstrates inserting a new contact into the address book. At first we ContactsContract. RawContacts. CONTENT_URI, pointing to the original contact has added a new original contact records in the table, insert the data, we get the record Uri, after we separated the id information, access to this id, We can set the name and phone number of the contact for this ID.

After doing the above, we can find the information of the contact we just inserted in the address book application.

ContentProviderOperation

The code above, we in the add contact, is to ContactsContract. Data. The CONTENT_URI points to add the two rows of Data in the table, a line is the name of the contact Data, Data line is contact number of hands. We did two inserts.

Operations of this type of bulk access provider, such as inserting a large number of rows or rows in multiple tables through the same method call, or typically performing a set of operations across process boundaries as transactions (atomic operations), can be performed using ContentProviderOperation, modifying the methods in Add Contacts as follows:

        // Use ContentProviderOperation for batch operations
        val operationList = arrayListOf<ContentProviderOperation>()

        // Insert the contact name
        operationList.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
            .withValue(ContactsContract.Data.RAW_CONTACT_ID,rawId)
            .withValue(ContactsContract.Data.MIMETYPE,
                ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
            .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name)
            .build()
        )
        // Insert the contact phone number
        operationList.add(
            ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValue(ContactsContract.Data.RAW_CONTACT_ID, rawId)
                .withValue(ContactsContract.Data.MIMETYPE,
                    ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone)
                .build()
        )
        // Perform the insert operation
        val resultArray = this.contentResolver.applyBatch(ContactsContract.AUTHORITY,operationList)
Copy the code

You can also insert a contact in the address book by performing the preceding operations.

Update the data

As with inserting data, we can update the corresponding data using the contentresolver.update () method. The only thing to note is that we need to specify conditions when updating the data. The following code demonstrates updating information about a contact using ContentProviderOpration.

    // Update contact information
    private fun updateContact(a){
        val operation = arrayListOf<ContentProviderOperation>()
        val name = mBinding.etContactName.text.toString()
        val phone = mBinding.etContactPhoneNumber.text.toString()
        // Set the name informationoperation.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI) .withValue(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) .withValue(ContactsContract.Data.RAW_CONTACT_ID,mContactEntity!! .rawId) .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,name) .withSelection("${ContactsContract.Data._ID}=? ", arrayOf(mContactEntity!! .nameId.toString())) .build() )// Set the phone numberoperation.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI) .withValue(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) .withValue(ContactsContract.Data.RAW_CONTACT_ID,mContactEntity!! .rawId) .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER,phone) .withSelection("${ContactsContract.Data._ID}=? ", arrayOf(mContactEntity!! .phoneId.toString())) .build() )// Perform the insert operation
        val resultArray = this.contentResolver.applyBatch(ContactsContract.AUTHORITY,operation)
        for(result in resultArray){
            Log.i(TAG, "addContact: result is:${result.uri}")}// Exit the page after performing the operation
        onBackPressed()
    }

Copy the code

The code above sets up to update the contact information based on the current ID. Eventually, a contact’s information is successfully updated to the new data.

Delete the data

Deleting rows is similar to retrieving row data. Specify the selection criteria for the rows to be deleted. The client method returns the number of deleted rows.

    // Delete a contact
    private fun deleteContact(a){ mContactEntity? .let {val count = this.contentResolver.delete(
                ContactsContract.RawContacts.CONTENT_URI,
                "${ContactsContract.RawContacts._ID}=?",
                arrayOf("${it.rawId}")
            )
            Log.i(TAG, "deleteContact: count is:$count")

            // Exit the page after deletion
            onBackPressed()
        }
    }
Copy the code

In the code above, we specify the rawId want to delete the contact, through this id deleted ContactsContract. RawContacts the data in the table, after return to see the designated contact person no longer exists.

At this point, we have learned how to access and modify the provider’s data in the ContentProvider.

The code in this study note is located at ContentProvider