ContentProvider of Android's Four Components

Keywords: Android Database SQL simulator

The problems to be solved are:

There are two projects A and B. Project A creates a self-produced and self-sold database through the subclass of SQLiteOpenHelper. Project B does not have a database, but Project B wants to share the same database with Project A.

To achieve the above objectives, two system classes are needed:

  1. One of the four components of ContentProvider content provider Andord
  2. ContentResolver Content Observer
    The combination of the two can share data between processes (between multiple projects)

How to use it:

Engineering A (to open data to other projects):

  1. Prepare a subclass of SQLiteOpenHelper to manage the self-produced and self-sold database of the current project.
  2. In order to open up the self-produced and self-sold database, the following operations need to be done through ContentProvider:
    Create a subclass of ContentProvider
    b. Register a subclass of ContentProvider in the manifest file
 <! - Register the ContentProvider subclass information in the application tag 
        android:name is used to specify the specific path of the subclass
        android:authorities sets the name of the author corresponding to the current subclass and writes any string of attribute values.
        The authorities in the Uri path that are set when connecting to this class via ContentResolver in other projects later
        Android: export= "true" allows open data operations
        -->
        <provider 
            android:name="com.example.day14_5_contentprovider.MyProvider"
            android:authorities="com.ay.sql"
            android:exported="true"
            ></provider>

c. Fill in the corresponding code in the method of adding, deleting and modifying subclasses

MyProvider subclass:

public class MyProvider ext ends ContentProvider {
    //Initialize UriMatcher objects for comparing Uri path types
    private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
    private static final int VIP = 1;
    private static final int VIP_ID = 3;
    private static final int VIP_LIKE = 4;
    private static final int BLACK = 2;
    static {
        //Adding a reference for comparison
        /**
         * Representatives store references to matcher objects: content://com.ay.oye/vip,
         * Later, when matcher calls match method for comparison, once the same as the current reference, the return value of match method is the data 1 corresponding to VIP.
         */
        matcher.addURI("com.ay.oye", "vip", VIP);
        matcher.addURI("com.ay.oye", "black", BLACK);
        matcher.addURI("com.ay.oye", "vip/#", VIP_ID);  //# Represents any number
        matcher.addURI("com.ay.oye", "vip/*", VIP_LIKE);  //* Represents any character

    }

    private SQLiteDatabase db;

    @Override
    public boolean onCreate() {
        // TODO Auto-generated method stub
        db = new MyHelper(getContext()).getReadableDatabase();
        return false;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {
        // TODO Auto-generated method stub
        Cursor cursor = null;
        switch (matcher.match(uri)) {
        case VIP:
            //The query is the vip table
            //Encapsulate query method for query in database through db object calling system
            cursor = db.query("vip", projection, selection, selectionArgs, null, null, sortOrder);
            break;

        case BLACK:
            //The query is the black table
            cursor = db.query("black", projection, selection, selectionArgs, null, null, sortOrder);
            break;
        case VIP_ID:
            if (selection == null) {
                cursor = db.query("vip", projection, "_id = "+uri.getLastPathSegment(), null, null, null, sortOrder);
            } else {
                cursor = db.query("vip", projection, selection+"and _id = "+uri.getLastPathSegment(), selectionArgs, null, null, sortOrder);
            }

            break;
        case VIP_LIKE:
            if (selection == null) {
                cursor = db.query("vip", projection, "name like ?", new String[] {"%"+uri.getLastPathSegment()+"%"}, null, null, sortOrder);
            } else {
                cursor = db.query("vip", projection, selection + " and name like "+"'"+"%"+uri.getLastPathSegment()+"%"+"'", selectionArgs, null, null, sortOrder);
            }

            break;
        }
        return cursor;
    }

    @Override
    public String getType(Uri uri) {
        // TODO Auto-generated method stub
        return matcher.match(uri)+"";
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        // TODO Auto-generated method stub
        long num = 0;
        switch (matcher.match(uri)) {
        case VIP:
            num = db.insert("vip", "_id", values);
            break;

        case BLACK:
            num = db.insert("black", "_id", values);
            break;
        }
        return Uri.withAppendedPath(uri, num+"");
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        // TODO Auto-generated method stub
        switch (matcher.match(uri)) {
        case VIP:
            db.delete("vip", selection, selectionArgs);
            break;

        case BLACK:
            db.delete("black", selection, selectionArgs);
            break;
        case VIP_ID:
            if (selection == null) {
                db.delete("vip", "_id = "+uri.getLastPathSegment(), null);
            } else {
                db.delete("vip", selection+" and _id = "+uri.getLastPathSegment(), selectionArgs);
            }
            break;

        case VIP_LIKE:

            break;
        }
        return 0;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
            String[] selectionArgs) {
        // TODO Auto-generated method stub
        return 0;
    }

}

In Engineering B (data obtained from Engineering A):

1. Initialize the ContentResolver object

  //Initialize the ContentResolver object
        cr = getContentResolver();

2. Implementing database operation by calling add-delete-modify method of ContentResolver object
Such as:

 public void click (View v) {
        switch (v.getId()) {
        case R.id.but_add:
            /**
             * Let's start with an example of adding
             * Parameters: 
             * 1. Uri  Used to describe paths
             * Splicing features:
             * scheme: // authorities / data
             * scheme  Theme, which represents the specific type of current path, is a file path or a phone, etc.
             * 
             * 2.ContentValues ,Used to store data to be added
             */
            ContentValues values = new ContentValues();
            values.put("name", "tearful");
            values.put("age", 28);

            /**
             *  Execution process: Find out which Subclass of ContentProvider registers the same author name in all applications of the entire device based on the author name in the Uri path
             *  Run the insert method in this subclass after finding it
             */
            Uri uri = cr.insert(Uri.parse("content://com.ay.sql/pr"), values);

           //If you want to get the id value of the newly added data from the uri object returned by the insert method
           String id =  uri.getLastPathSegment();
           Log.i("oye", "Project 6: Corresponding to the newly added data id As follows:  "+id);
            break;

        case R.id.but_query:
            /**
             * Parameters:
             * 1. Uri Route,
             * 2. To query which columns in the table, fill in null to get all columns
             * 3, Conditions for queries
             * 3, For substitution conditions? Value
             * 5. sort
             */
            Cursor cursor = cr.query(Uri.parse("content://com.ay.sql/pr"), null, null, null, null);

             while (cursor.moveToNext()) {
                 String name = cursor.getString(cursor.getColumnIndex("name"));

                 Log.i("oye", "Data bits obtained in Engineering 6:  "+name);
             }
            break;

        case R.id.but_delete:

            int num = cr.delete(Uri.parse("content://com.ay.sql/pr"), "_id=?", new String[]{"3"});
            Log.i("oye", "The number of items deleted in Engineering 6 is:"+num);
            break;

        case R.id.but_update:

            ContentValues cv = new ContentValues();
            cv.put("name", "Wang Laoshi");
            int num1 = cr.update(Uri.parse("content://com.ay.sql/pr"), cv, "_id = ?", new String[]{"5"});
            Log.i("oye", "The number of items deleted in Engineering 6 is:"+num1);
            break;
        }
    }

Relatively common uses such as:

The system's call record project opens the call record through ContentProvider. We want to get the information through the record, we just need to call the corresponding add-delete check method through ContentResolver.

Read common system data through ContentResolver:

1. Call Logging Information
 2. Short Message Recording Information
 3. Contact address book information

1. Read the call record through ContentResolver:

Prepare before reading: Make sure that the device used for testing has a call record, otherwise the content will not be read.

If it is the way the simulator processes the call record:

1. Dial-out telephone: directly use the dialing software on the simulator.
2. Answer the phone (only the native simulator can simulate the answer): Select to open the Emulator Control tag in Window-ShowVIew-Other-Android, in which the function of dialing out the phone to the simulator and sending short messages can be realized.

The storage location of the system call record table:

 /*
         * Location of the database for call records: data/data/com.android.providers.contacts/databases/contacts 2.db
         * Table name: calls
         * Corresponding author name: call_log
         * Read the content through the query method
         */

Main columns in the call log:

number Storage Phone number
 Type stores the type of call, 1 for incoming calls (answered calls) and 2 for outgoing calls (dialed calls)
date calls
 The duration of a duration call

The Uri used by the connection through the record:

Uri.parse("content://call_log/calls")

Specific reading methods:

Cursor cursor = cr.query(Uri.parse("content://call_log/calls"), null, null, null, null);

        while(cursor.moveToNext()) {
            //Telephone number?
            String number = cursor.getString(cursor.getColumnIndex("number"));
            //Is it a call or a call?
            String s = cursor.getString(cursor.getColumnIndex("type"));

            String type = s.equals("1") ? "Calls (answered calls)":"To call (a dialed phone)";
            //time
            String date = cursor.getString(cursor.getColumnIndex("date"));

            //Get the length of the call
            String duration = cursor.getString(cursor.getColumnIndex("duration"));

            Log.i("oye", "Data bits in the voice record:  "+number +"  "+date+"  "+type+"   "+duration);

        }

Permissions that need to be added:

 <! - Add permission to read the call record - >
    <uses-permission android:name="android.permission.READ_CALL_LOG"/>

     <! - Add permission to modify the write-to-call record - >
    <uses-permission android:name="android.permission.WRITE_CALL_LOG"/>

2. Read short message records through ContentResolver:

Storage location of system short message record table:

data/data/com.android.provider.telephony/databases/mmssms.dbMedium sms surface

Uri for connection use:

content://sms

The more important columns in the table are:

address phone number
 date receives short messages
 date_sent date for sending short messages
 Read is used to identify whether text messages have been read, 0 for unread and 1 for read.
Type is used to identify SMS received by SMS type 1, SMS sent by type 2, SMS sent by type 3, SMS sent in draft box
 body Short Message Content

Reading mode:

protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);

        ContentResolver cr = getContentResolver();

        Cursor cursor = cr.query(Uri.parse("content://sms"), null, null, null, null);

        while (cursor.moveToNext()) {
            String number = cursor.getString(cursor.getColumnIndex("address"));
            String mess = cursor.getString(cursor.getColumnIndex("body"));
            String read = cursor.getString(cursor.getColumnIndex("read")).equals("0") ? "Unread":"Already read";
            String type = cursor.getString(cursor.getColumnIndex("type")).equals("1")?"Received SMS":"Short Messages Sended";

            Log.i("oye", "The content of the short message obtained is as follows: "+number+"  "+mess+"  "+read+"  "+type);
        }
    }

Required permissions:

<! - Access to SMS Records - >
    <uses-permission android:name="android.permission.READ_SMS"/>

    <! - Permission to modify SMS records - >
     <uses-permission android:name="android.permission.WRITE_SMS"/>

3. Reading System Address Book Contacts through ContentResolver

Storage location of contact person in system address book:

data/data/com.android.providers.contacts/databases/Contacts2.db database file

Main tables for reading contact information:

1.raw_contacts
 Used to store the name of a contact and the unique id value corresponding to that contact
2.data
 Used to store all data for all contacts, but note:
(1) Not all the information of a contact is stored in one line
 Instead, it splits all the information of a contact into multiple rows of storage.
The way to determine which rows of data belong to the same contact is:
Judging by the value of raw_contact_id for each row, all data for the same contact is the same value
 (2) Basically, most of the data is stored in the data1 column. In order to determine the type of data (phone number or name) in the data1 column of this row, it is necessary to judge the value in the mimetype_id column.
3.Mimetypes
 Used to store all data class names, such as phone number, name, mailbox address, etc.

Reading mode:

Reading mode 1:

private ArrayList<MyC> queryAll() {
        ArrayList<MyC> list = new ArrayList<MyC>();

        // 1. Read the raw_contacts table. The purpose is to get the unique id of each person's contact. This time, all the contact id values are stored in the idCursor.
        Cursor idCursor = cr.query(
                Uri.parse("content://com.android.contacts/raw_contacts"), null,
                "deleted = 0", null, null);

        while (idCursor.moveToNext()) {
            // Get the id of the contact
            int id = idCursor.getInt(idCursor.getColumnIndex("_id"));

            MyC myc = new MyC();
            myc.setId(id);
            // 2. Read the data from the data table according to the id value or obtained. The cursor object obtained this time stores a contact's multi-faceted data.
            Cursor cursor = cr.query(
                    Uri.parse("content://com.android.contacts/data"), null,
                    "raw_contact_id = " + id, null, null);

            // 3. Loop cursor object to read contact data
            while (cursor.moveToNext()) {
                // Get the value of the column data1
                String data1 = cursor.getString(cursor.getColumnIndex("data1"));

                Log.i("oye", "Current row data1 The data are as follows:  " + data1);

                String mime = cursor.getString(cursor
                        .getColumnIndex("mimetype"));

                if (mime.equals("vnd.android.cursor.item/name")) {
                    // Names are stored in the data1 column representing the current row
                    myc.setName(data1);
                } else if (mime.equals("vnd.android.cursor.item/email_v2")) {
                    // In data1, which represents the bank, the mailbox address is stored.
                    myc.setEmail(data1);
                } else if (mime
                        .equals("vnd.android.cursor.item/postal-address_v2")) {
                    // Home address
                    myc.setAddress(data1);
                } else if (mime.equals("vnd.android.cursor.item/phone_v2")) {
                    // Stored is the phone number.
                    String data2 = cursor.getString(cursor
                            .getColumnIndex("data2"));
                    if (data2.equals("1")) {
                        // Family seat number
                        myc.setPhone_home(data1);
                    } else if (data2.equals("2")) {
                        // Cell-phone number
                        myc.setPhone_mobile(data1);
                    }

                }

            }
            list.add(myc);
            Log.i("oye", "*************************************");
        }

        return list;
    }

Reading mode 2:

public void queryAllMethod2() {
        // Manage Uri of all contacts
        Cursor c1 = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null,
                null, null);
        //Read the names of all contacts
        while (c1.moveToNext()) {

            String name = c1.getString(c1
                    .getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
            Log.i("oye", "c1   ddd  " + c1.toString() + "  " + name);
        }

        Cursor c2 = cr.query(
                ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null,
                null, null);
        //Read the phone numbers of all contacts
        while (c2.moveToNext()) {

            String number = c2.getString(c2
                    .getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
            Log.i("oye", "c1   ddd  " + c2.toString() + "  " + number);
        }

    }

Permissions that need to be added:

  <! - Access to Address Book Contacts - >
    <uses-permission android:name="android.permission.READ_CONTACTS"/>

    <! - Modify and add the permissions of contacts in the address book - >.
     <uses-permission android:name="android.permission.WRITE_CONTACTS"/>

How to delete data:

case R.id.but_delete:
            //Delete Contacts in Address Book
            //1. Delete data from raw_contacts table
            cr.delete(Uri.parse("content://com.android.contacts/raw_contacts"), "_id=2", null);
            //2. (Not to write) Remove contacts from the data table
            cr.delete(Uri.parse("content://com.android.contacts/data"), "raw_contact_id = 2", null);
            break;

How to add new data:

case R.id.but_insert:
            //Additional Contact Data
            //1.First direction raw_contacts Save the data in the table and get the corresponding newly added data id value
            ContentValues values = new ContentValues();
            values.put("display_name", "Xiao Zhao");
            Uri uri = cr.insert(Uri.parse("content://com.android.contacts/raw_contacts"), values);
            //Get the id value corresponding to the newly added data
            String id = uri.getLastPathSegment();

            //2. according to id towards data Information stored in the table, name, mailbox and telephone number
            //Deposit name information
            values.clear();
            values.put("data1", "Xiao Zhao");
            values.put("raw_contact_id", id);
            values.put("mimetype", "vnd.android.cursor.item/name");
            cr.insert(Uri.parse("content://com.android.contacts/data"), values);
            //Mailbox information
            values.clear();
            values.put("data1", "250@250.com");
            values.put("raw_contact_id", id);
            values.put("mimetype", "vnd.android.cursor.item/email_v2");
            values.put("data2", "1");
            cr.insert(Uri.parse("content://com.android.contacts/data"), values);
            //Store telephone number information
            values.clear();
            values.put("data1", "250250250");
            values.put("raw_contact_id", id);
            values.put("mimetype", "vnd.android.cursor.item/phone_v2");
            values.put("data2", "2");
            cr.insert(Uri.parse("content://com.android.contacts/data"), values);

            break;

How to modify data:

case R.id.but_update:
            //Modify contacts

            //Modify the original content in the database
            ContentValues values2 = new ContentValues();
            values2.put("data1", "252252252");
            cr.update(Uri.parse("content://com.android.contacts/data"), values2, "raw_contact_id = ? and mimetype = ?", new String[]{"3","vnd.android.cursor.item/phone_v2"});


            //Add new content to the database
            ContentValues values1 = new ContentValues();
            values1.put("data1", "Family address:");
            values1.put("raw_contact_id", 3);
            values1.put("mimetype", "vnd.android.cursor.item/postal-address_v2");
            cr.insert(Uri.parse("content://com.android.contacts/data"), values1);

            break;

Posted by smc on Thu, 21 Mar 2019 09:42:54 -0700