When there is no beginning, there is a shard in the morning. Experiences
Many things, the vast majority of people will be enthusiastic at the beginning, but few can stick to the end. To treat your own goals, you must never get them. If you stop halfway, you will only get nothing done. We must persevere and stick to it to the end to win the fruits of victory. I have been busy recently and am busy charging myself. I am well aware that this task is not a day or two, so I also use this warning to warn myself and persevere.
Today, we will explain how to use the contentprovider mechanism to read and write contact information.
In Android, contentprovider is a data package that is suitable for sharing information between different processes. For example, in Android, The SQLite database is a typical data source. We can encapsulate it in contentprovider to provide information sharing services for other applications. When other applications access contentprovider, they can use a set of rest-like Uris to perform data operations, which greatly simplifies the complexity of reading and writing information. For example, if you want to obtain a group of image books from the contentprovider that encapsulates the library database, you need to use a URI similar to the following:
Content: // com. Scott. Book. bookprovider/books
To obtain a specified book (such as Book 23) from the library database, you must use a URI similar to the following:
Content: // com. Scott. Book. bookprovider/books/23
Note: contentprovider is an abstract class that defines a series of method templates for data operations. bookprovider needs to implement these methods to implement various operations on Book information.
Now that we know the specific URI, how can we operate to get data?
At this point, we need to understand the contentresolver class, which corresponds to the contentprovider. We use it to exchange data with contentprovider. Android. content. the context class defines the getcontentresolver () method for us to obtain a contentresolver object. If we can get the current context instance object through getcontext () at runtime, you can use the getcontentresolver () method provided by this instance object to obtain the contentresolver type instance object, and then you can operate on the corresponding data.
Next we will demonstrate this mechanism through the contact instance.
In Android, all contact operations are performed through a unified way to read and write data. We can open/data/COM. Android. providers. contacts to see the contact's Data source:
If you are interested, you can export this file and open it with professional tools and software to check the table structure.
After the SQLite data source is encapsulated, the contacts provide the Read and Write services for the contacts of other application processes in the form of contentprovider. Then, we can complete the operations on our contact information.
To facilitate the test, we first add two contacts to the Data source ,:
We can see that each contact has two phone numbers and two email accounts, namely the home landline number, mobile phone number, home mailbox account, and work mailbox account. Of course, there is a lot of other information when adding a contact. We didn't fill it in here. We only selected the most common phone and email addresses, mainly to facilitate the demonstration of this process.
Before DEMO code, we need to know about Android. provider. contactscontract (note: in earlier versions, it is Android. provider. contacts class, but it has been deprecated and is not recommended). It defines the URI related to various contacts and the attribute information of each type of information:
If you are interested, you can read the source code. However, there are many internal classes that are especially difficult to read, so you still need to be prepared.
Next we will use a project to demonstrate the specific contact operation process. Create a project named provider and create a test case named contactsreadtest, as shown below:
Package COM. scott. provider; import Java. util. arraylist; import android. content. contentresolver; import android. database. cursor; import android.net. uri; import android. provider. contactscontract; import android. test. androidtestcase; import android. util. log; public class contactsreadtest extends androidtestcase {Private Static final string tag = "contactsreadtest"; // [content: // COM. android. contacts/contacts] Private Static final URI contacts_uri = contactscontract. contacts. content_uri; // [content: // COM. android. contacts/data/phones] Private Static final URI phones_uri = contactscontract. commondatakinds. phone. content_uri; // [content: // COM. android. contacts/data/emails] Private Static final URI email_uri = contactscontract. commondatakinds. email. content_uri; Private Static final string _ id = contactscontract. contacts. _ id; Private Static final string display_name = contactscontract. contacts. display_name; Private Static final string has_phone_number = contactscontract. contacts. has_phone_number; Private Static final string contact_id = contactscontract. data. contact_id; Private Static final string phone_number = contactscontract. commondatakinds. phone. number; Private Static final string phone_type = contactscontract. commondatakinds. phone. type; Private Static final string email_data = contactscontract. commondatakinds. email. data; Private Static final string email_type = contactscontract. commondatakinds. email. type; Public void testreadcontacts () {contentresolver resolver = getcontext (). getcontentresolver (); cursor c = resolver. query (contacts_uri, null); While (C. movetonext () {int _ id = C. getint (C. getcolumnindex (_ id); string displayname = C. getstring (C. getcolumnindex (display_name); log. I (TAG, displayname); arraylist <string> phones = new arraylist <string> (); arraylist <string> emails = new arraylist <string> (); string selection = contact_id + "=" + _ id; // The 'where' clause // get the phone number int hasphonenumber = C. getint (C. getcolumnindex (has_phone_number); If (hasphonenumber> 0) {cursor primary key = resolver. query (phones_uri, null, selection, null, null); While (primary privilege. movetonext () {string phonenumber = primary privilege. getstring (SCC. getcolumnindex (phone_number); int phonetype = primary privilege. getint (primary privilege. getcolumnindex (phone_type); phones. add (getphonetypenamebyid (phonetype) + ":" + phonenumber. close ();} log. I (TAG, "phones:" + phones); // obtain the email address cursor EMC = resolver. query (email_uri, null, selection, null, null); While (EMC. movetonext () {string emaildata = EMC. getstring (EMC. getcolumnindex (email_data); int emailtype = EMC. getint (EMC. getcolumnindex (email_type); emails. add (getemailtypenamebyid (emailtype) + ":" + emaildata);} EMC. close (); log. I (TAG, "Emails:" + emails);} C. close ();} private string getphonetypenamebyid (INT typeid) {Switch (typeid) {Case contactscontract. commondatakinds. phone. type_home: Return "home"; Case contactscontract. commondatakinds. phone. type_mobile: Return "mobile"; Case contactscontract. commondatakinds. phone. type_work: Return "work"; default: Return "NONE" ;}} private string getemailtypenamebyid (INT typeid) {Switch (typeid) {Case contactscontract. commondatakinds. email. type_home: Return "home"; Case contactscontract. commondatakinds. email. type_work: Return "work"; Case contactscontract. commondatakinds. email. type_other: Return "other"; default: Return "NONE ";}}}
To run this test case, we need to configure the device declaration in androidmanifest. XML, which is at the same level as the <Application> element:
<! -- Configure the main class and target package of the test device --> <instrumentation Android: Name = "android. Test. instrumentationtestrunner" Android: targetpackage = "com. Scott. provider"/>
Then configure the declaration using the test library, which is at the same level as the <activity> element:
<! -- Configure the class library to be used for testing --> <uses-library Android: Name = "android. Test. Runner"/>
Finally, an important Declaration needs to be configured, that is, read the contact permission. The declaration is as follows:
<! -- Read the contact --> <uses-Permission Android: Name = "android. Permission. read_contacts"/>
After the above preparations, this test case can run. Let's run the testreadcontacts () method and print the result as follows:
It seems that the information in the contact is read accurately by us.
If we run the code to read a contact in an activity, we can not only use contentresolver to directly read (I .e., query), but also use the managedquery method provided by activity to conveniently achieve the same effect, let's take a look at the specific code of this method:
public final Cursor managedQuery(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { Cursor c = getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder); if (c != null) { startManagingCursor(c); } return c; }
We found that it still uses contentresolver for query operations, but with one more startmanagingcursor operation, it manages the cursor object according to the activity lifecycle, it avoids some problems caused by the release of cursor, so it is very convenient and greatly simplifies our workload.
Next, we will try to add a contact information to the data source of the system contact to write the contact information. Create a new test case named contactswritetest, as shown below:
Package COM. scott. provider; import Java. util. arraylist; import android. content. contentprovideroperation; import android. content. contentproviderresult; import android. content. contentresolver; import android.net. uri; import android. provider. contactscontract; import android. test. androidtestcase; import android. util. log; public class contactswritetest extends androidtestcase {Private Static final string tag = "contactswritetest"; // [content: // COM. android. contacts/raw_contacts] Private Static final URI raw_contacts_uri = contactscontract. rawcontacts. content_uri; // [content: // COM. android. contacts/data] Private Static final URI data_uri = contactscontract. data. content_uri; Private Static final string account_type = contactscontract. rawcontacts. account_type; Private Static final string account_name = contactscontract. rawcontacts. account_name; Private Static final string raw_contact_id = contactscontract. data. raw_contact_id; Private Static final string mimetype = contactscontract. data. mimetype; Private Static final string name_item_type = contactscontract. commondatakinds. structuredname. content_item_type; Private Static final string display_name = contactscontract. commondatakinds. structuredname. display_name; Private Static final string phone_item_type = contactscontract. commondatakinds. phone. content_item_type; Private Static final string phone_number = contactscontract. commondatakinds. phone. number; Private Static final string phone_type = contactscontract. commondatakinds. phone. type; Private Static final int phone_type_home = contactscontract. commondatakinds. phone. type_home; Private Static final int phone_type_mobile = contactscontract. commondatakinds. phone. type_mobile; Private Static final string email_item_type = contactscontract. commondatakinds. email. content_item_type; Private Static final string email_data = contactscontract. commondatakinds. email. data; Private Static final string email_type = contactscontract. commondatakinds. email. type; Private Static final int email_type_home = contactscontract. commondatakinds. email. type_home; Private Static final int email_type_work = contactscontract. commondatakinds. email. type_work; Private Static final string authority = contactscontract. authority; Public void testwritecontacts () throws exception {arraylist <contentprovideroperation> operations = new arraylist <contentprovideroperation> (); contentprovideroperation operation = contentprovideroperation. newinsert (raw_contacts_uri ). withvalue (account_type, null ). withvalue (account_name, null ). build (); operations. add (operation); // Add the contact name operation = contentprovideroperation. newinsert (data_uri ). withvaluebackreference (raw_contact_id, 0 ). withvalue (mimetype, name_item_type ). withvalue (display_name, "Scott Liu "). build (); operations. add (operation); // Add the home landline number operation = contentprovideroperation. newinsert (data_uri ). withvaluebackreference (raw_contact_id, 0 ). withvalue (mimetype, phone_item_type ). withvalue (phone_type, phone_type_home ). withvalue (phone_number, "01034567890 "). build (); operations. add (operation); // Add the mobile phone number operation = contentprovideroperation. newinsert (data_uri ). withvaluebackreference (raw_contact_id, 0 ). withvalue (mimetype, phone_item_type ). withvalue (phone_type, phone_type_mobile ). withvalue (phone_number, "13034567890 "). build (); operations. add (operation); // Add the home mailbox operation = contentprovideroperation. newinsert (data_uri ). withvaluebackreference (raw_contact_id, 0 ). withvalue (mimetype, email_item_type ). withvalue (email_type, email_type_home ). withvalue (email_data, "scott@android.com "). build (); operations. add (operation); // Add the work email operation = contentprovideroperation. newinsert (data_uri ). withvaluebackreference (raw_contact_id, 0 ). withvalue (mimetype, email_item_type ). withvalue (email_type, email_type_work ). withvalue (email_data, "scott@msapple.com "). build (); operations. add (operation); contentresolver resolver = getcontext (). getcontentresolver (); // batch execution, returns the execution result set contentproviderresult [] Results = resolver. applybatch (authority, operations); For (contentproviderresult result: Results) {log. I (TAG, result. uri. tostring ());}}}
In the above Code, we divide the entire operation into several contentprovideroperation operations and Perform Batch Processing on them. We may note that starting from the second operation, each item has a withvaluebackreference (raw_contact_id, 0) step. It refers to the ID of the newly added contact in the first operation. Because it is a batch processing, we do not know the id value before inserting data, however, you don't need to worry about this. during batch processing and data insertion, it will re-reference the new ID value without affecting the final result.
Of course, you cannot forget to configure the permission statement for writing contacts:
<! -- Write a contact --> <uses-Permission Android: Name = "android. Permission. write_contacts"/>
After the preceding steps, run the testwritecontacts () method to check whether the contact is added: