All of my articles are collected in this article, and will be updated in time: Knowledge is long, the road of the walker will end in no words (My Programming Road)

Zero, preface,

This paper focus on
[1] Understand the query function of ContentProvider through SMS [2] Understand the operations of ContentProvider insertion, modification, update, search and so on through picture query [3] Query the contact to see how to do between two tables [4] How does the Android system implement SMS ContentProvider? [5] How to customize a ContentProvider for other applicationsCopy the code

1. Query function of ContentProvider (SMS as an example)


1: the entity class
*/ class SMSBean {var address: String? = null// Name of the SMS sender var name: String? = null// Name of the phone in the address book: none Null var date: String? = NULL // SMS time var body: String? = null// Short message content vartypeVar thread_id: Int = 0 var thread_id: Int = 0}Copy the code

2. Query processing

/** * Get SMS: SMSBean: address sender date body information ** @param CTX context * @return*/ public static List<SMSBean> getSMS(Context CTX) {List<SMSBean> smsBeans = new ArrayList<>(); //[1.] Get the ContentResolver object ContentResolver resolver = ctx.getContentResolver(); //[2.1] Obtain Uri: access raw_contacts URL Uri Uri = uri.parse ("content://sms"); //[3] projection = {String[] projection = {"address"."date"."body"."type"."person"."thread_id"}; Cursor = resolver.query(URI, projection, null, null, null);while(cursor.moveTonext ()) {// iterate over the cursor and store the data in the bean SMSBean = new SMSBean(); smsBean.setAddress(cursor.getString(cursor.getColumnIndex("address")));
        smsBean.setDate(cursor.getString(cursor.getColumnIndex("date")));
        smsBean.setBody(cursor.getString(cursor.getColumnIndex("body")));
        smsBean.setType(cursor.getInt(cursor.getColumnIndex("type")));
        smsBean.setName(cursor.getString(cursor.getColumnIndex("person")));
        smsBean.setThread_id(cursor.getInt(cursor.getColumnIndex("thread_id"))); smsBeans.add(smsBean); } //[4] close cursor. Close ();return smsBeans;
}
Copy the code


3. Five query parameters

SQL basics

* @param uri Resource address The URI, using The content:// scheme,forThe content to retrieve. * @param Projection would like to query, null queries all columns, the least efficient A list ofwhich columns to return. Passing null will return all columns, whichIs inefficient. * @param selection Specifies the filter statement to be displayedwhere)
A filter declaring which rows to return, formatted as an SQL WHERE clause (excluding the WHERE itself).
Passing null will return all rows forThe given URI. * @param selectionArgs Query parameters in the filter statement You may include? sin selection, which will be replaced by the values from selectionArgs, 
in the order that they appear inThe values will be bound as Strings. * @param sortOrder How to order the rows, formatted as an SQL ORDER BY clause (excluding the ORDER BY itself). Passing null will use the default sort order,which may be unordered.
Copy the code

The following pro test available, the subsidy diagram

| - queries from the 10086 information Cursor Cursor = resolver. Query (uri, the projection,"address=10086", null, null); | - query from the specified number information public static List < SMSBean > getSMSByPhone (Context CTX, String phone) {... Cursor cursor = resolver.query( uri, projection,"address=?", new String[]{phone}, null); . } | - reverse chronological order by the Cursor Cursor. = resolver query (uri, the projection,"address=?", new String[]{phone}, "date desc"); | - in reverse chronological order sort + take before eight data Cursor Cursor = resolver. Query (uri, the projection,"address=?", new String[]{phone}, "The date desc limit 0, 8");
Copy the code

2, about multimedia ContentProvider operation (picture as an example)

As one of the three tripods of mobile phone, media is naturally inevitable for content providers to leak information to the outside world. The information is mainly stored in two databases, external.db and internal.db. The main fields of pictures in the database are:

_ID: INDICATES the ID id. _data: indicates the absolute path of the image. _size: indicates the size of the image. Type data_ADDED: added time data_MODIFIDE: last modified time _display_name: display name Description: description width: width Height: heightCopy the code


1. Get the content provider and add an image with a custom message
private void insertImg() {//1. Create object ContentValues and insert photo information. ContentValues values = new ContentValues(); values.put(MediaStore.Images.Media.DISPLAY_NAME,"Zhang Feng Jie Te Li");
    values.put(MediaStore.Images.Media.DESCRIPTION, "Like no other in the world.");
    values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg"); //2. Get the content provider, insert (external image store Uri,values), Return to insert pictures Uri Uri imgFileUri = getContentResolver (), insert (MediaStore. Images. Media. EXTERNAL_CONTENT_URI, values). L.d(imgFileUri + L.l()); //content://media/external/images/media/1064830 //3. Intent = New Intent(mediastore.action_image_capture); Intent = New Intent(mediastore.action_image_capture); intent.putExtra(MediaStore.EXTRA_OUTPUT, imgFileUri); startActivity(intent); }Copy the code

2. Read the image just inserted through the content provider
 private void readImg() {try {//1. Get the content provider and open the input stream with the last Uri Uri imgUri = uri.parse ();"content://media/external/images/media/1064830"); InputStream is = getContentResolver().openInputStream(imgUri); / / 2. The image decoding display Bitmap Bitmap. = BitmapFactory decodeStream (is); mImageView.setImageBitmap(bitmap); } catch (FileNotFoundException e) { e.printStackTrace(); }}Copy the code

3. Update the description
private void updateImg() {
    ContentValues values = new ContentValues(2);
    values.put(MediaStore.Images.Media.DISPLAY_NAME, "Toly");
    values.put(MediaStore.Images.Media.DESCRIPTION, "Only Me"); //1. Get the content provider and open the input stream with the previous Uri Uri imgUri = uri.parse ()"content://media/external/images/media/1064830");
    getContentResolver().update(imgUri, values, null, null);
}
Copy the code

4. The look-up table

Since you are the content provider, it is inevitable to play a table again to verify that the above modification method is successful

private void queryImg() {/ / 1. Query for Cursor Cursor Cursor = getContentResolver () query (MediaStore. Images. Media. EXTERNAL_CONTENT_URI, null,"_id=1064830", null, null, null); //2. Move the cursor to the endwhile (cursor.moveToNext()) {
        String filePath = cursor.getString(cursor.getColumnIndex("_data"));
        String name = cursor.getString(cursor.getColumnIndex("_display_name"));
        String description = cursor.getString(cursor.getColumnIndex("description")); L.d(filePath + L.l()); //storage/emulated/0/DCIM/Camera/1539834068417.jpg L.d(name + L.l()); //Toly L.d(description + L.l()); //Only Me }Copy the code

5. Remove
private void deleteImg() {
    Uri imgUri = Uri.parse("content://media/external/images/media/1064830");
    int delete = getContentResolver().delete(imgUri, "_id=1064830", null); L.d(delete + L.l()); //1 indicates that one line is deleted.Copy the code

6. Obtain the path of all images

A total of 12540 images, method time :1.289 seconds, belong to the time-consuming operation should be placed in the child thread can get the database field, encapsulate an image entity class, so that use

private ArrayList<String> queryAllImg() { ArrayList<String> imgPaths = new ArrayList<>(); / / 1. Query for Cursor Cursor Cursor = getContentResolver () query (MediaStore. Images. Media. EXTERNAL_CONTENT_URI, null,"", null, null, null); //2. Move the cursor to the endwhile (cursor.moveToNext()) {
        String filePath = cursor.getString(cursor.getColumnIndex("_data"));
        imgPaths.add(filePath);
    }
    return imgPaths;
}
Copy the code

7. Show the last 100 pictures

For simplicity, use Picasso to load images — see the open source framework’s [-Picasso-] app for details


7.1. Obtain the last 100 Database Records

Order condition: “date_added DESC “indicates that the data is stored in the List in reverse order based on the date_added field, and the number of elements in the List is determined to break out of the while loop

private ArrayList<String> queryPic100() { ArrayList<String> imgPaths = new ArrayList<>(); / / 1. Query for cursor String queryCol = MediaStore. Images. Media. DATE_ADDED; Cursor cursor = getContentResolver().query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null,"",
            null, "date_added desc", null); //2. Move the cursor to the endwhile (cursor.moveToNext()) {
        if (imgPaths.size() >= 100) {
            break;
        }
        String filePath = cursor.getString(cursor.getColumnIndex("_data"));
        imgPaths.add(filePath);
    }
    return imgPaths;
}
Copy the code

7.2.RecyclerView simple use (layout is very simple to avoid)

1). Create adapter class and ViewHolder 2). Set RecyclerView style

/** * Adapter */ class PicRVAdapter extends recyclerVievie. Adapter<PicViewHolder> {@nonnull @override public PicViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(Pic100Activity.this).inflate(R.layout.item_img, null);returnnew PicViewHolder(view); } @Override public void onBindViewHolder(@NonNull PicViewHolder holder, Picas.get ().setindicatorSenabled () {// load the file image with Picas.get ().setindicatorSenabled ()true); Picas.get ().load(new File(mlist.get (position)))// file.resize (200,200)// Resize.into(holster.miv_icon); } @Override public intgetItemCount() {
        returnmList.size(); } } /** * ViewHolder */ public class PicViewHolder extends RecyclerView.ViewHolder { public final ImageView mIv_icon; ** @param itemView entry */ public PicViewHolder(View itemView) { super(itemView); mIv_icon = itemView.findViewById(R.id.id_iv_item); }}Copy the code
Midrvpic100. setAdapter(new PicRVAdapter()); / / 2.!!!!! Create a layout manager mGLM = new GridLayoutManager (this, 4, GridLayoutManager. VERTICAL,false); / / 3.!!!!!! Set the layout manager mIdRvPic100. SetLayoutManager (mGLM);Copy the code

MediaStore is an example of a class given to facilitate the operation of the media ContentProvider. The image, audio, and video three main columns are all involved, so the image can operate, those two are also included


Three, address book query

1. Realization analysis:

The contact_ID field is found in the RAW_CONTACTS table. Under each contact_ID, query the data table field according to the contact_ID, then determine the value of miMEType, create an entity class, set the data in the entity, put the entity into the entity set, and return the collection after checking.

Contact database

The RAW_CONTACTS table focuses on the field CONTact_ID

Data table and MIMETYPE table: Focus on miMETYPE_ID, RAW_CONTact_ID, and datA1


2. Contact entity class
/ * * * the author: packer jet fierce < br > < br > * time: 2019/2/27/027: this < br > < br > * E-mail: 1981462002 @qq.com < br > < br > * note: Contact */ class ContactBean {var name: String? = null var address: String? = null var email: Var phone: String? = null var photo: Bitmap? = null}Copy the code

3. The ContactBean collection is displayed
/** * Obtain contact: ContactBean field: Name name address Address Email Email Phone Phone number ** @param CTX context * @return*/ public static List<ContactBean> getContact(Context CTX) {// Create a container to put the result List<ContactBean> contactBeans = new ArrayList<>(); //[1.] Get the ContentResolver object ContentResolver resolver = ctx.getContentResolver(); Raw_contactsUri = uri.parse (raw_contactsUri = uri.parse)"content://com.android.contacts/raw_contacts"); DataUri = uri.parse (dataUri = uri.parse (dataUri = uri.parse))"content://com.android.contacts/data"); Cursor raw_contactsCursor = resolver.query(raw_contactsUri, new String[]{"contact_id"}, null, null, null); //[4] Iterate over the cursor to get the data and store it in the beanwhile(raw_contactsCursor moveToNext ()) {/ / [4.1] queries to contact_id String contact_id = raw_contactsCursor. Get String (0);if(contact_id ! Datursor = resolver.query(dataUri, new String[]{dataUri = dataUri, dataUri = dataUri, new String[]{"data1"."mimetype"},// Note that it is not mimetype_id"raw_contact_id=?",
                    new String[]{contact_id}, null);
            ContactBean contactBean = new ContactBean();
            while(dataCursor.moveToNext()) { String result = dataCursor.getString(0); String mimeType = datacursor.getString (1); //[4.4] String mimeType = datacursor.getString (1);if(mimetype ! = null) {//[4.3] Create entity class switch (mimeType) {case "vnd.android.cursor.item/phone_v2"Contactbean.setphone (result);break;
                        case "vnd.android.cursor.item/email_v2"://email
                            contactBean.setEmail(result);
                            break;
                        case "vnd.android.cursor.item/name": / / name contactBean elegantly-named setName (result);break;
                        case "vnd.android.cursor.item/postal-address_v2": / / address contactBean setAddress (result);break; }}}if(contactBean.getPhone() ! = null) { contactBeans.add(contactBean); } //[5.1] close the data table Cursor datacursor.close (); }} //[5.2] close raw_contactsCursor raw_contactscursor.close ();return contactBeans;
}
Copy the code

4. Extra talk about getting contact pictures
** @param CTX context ** @param number * @returnPublic static Bitmap getContactPhoto(Context CTX, String number) {Bitmap bmpHead = null; ContentResolver resolver = ctx.getContentResolver(); // Obtain the Uri Uri uriNumber2Contacts = uri.parse (uri.parse)"content://com.android.contacts/"
            + "data/phones/filter/"+ number); CursorCantacts = resolver.query(uriNumber2Contacts, null, null, null, null, null); // If the contact existsif(cursorCantacts getCount () > 0) {/ / move to the first data cursorCantacts. MoveToFirst (); / / get the contacts contact_id Long contactID = cursorCantacts. GetLong (cursorCantacts. GetColumnIndex ("contact_id")); / / get contact_id Uri Uri Uri = ContentUris withAppendedId (ContactsContract. Contacts. CONTENT_URI, contactID); / / open the avatar picture InputStream InputStream input = ContactsContract. Contacts. OpenContactPhotoInputStream (resolver, uri); . / / bitmap from the InputStream bmpHead = BitmapFactory decodeStream (input); }return bmpHead;
Copy the code

Below is the previous small project, used to get contacts

At this point, you should know what contentProviders are for. Let’s take a look at how SMS ContentProvider is implemented in the Android system.


The ContentProvider for SMS is in Android

Have a look, this is still hold, the other several are deadly long. If you downloaded the Android source code, you can see: The source directory \packages\providers\TelephonyProvider\ SRC \com\android\providers\telephony\ smsprovider.java contains less than 900 lines

1. Member variables

Here you can see the URIs and the related fields of the database table

public class SmsProvider extends ContentProvider {
    private static final Uri NOTIFICATION_URI = Uri.parse("content://sms");
    private static final Uri ICC_URI = Uri.parse("content://sms/icc");
    static final String TABLE_SMS = "sms";
    static final String TABLE_RAW = "raw";
    private static final String TABLE_SR_PENDING = "sr_pending";
    private static final String TABLE_WORDS = "words";
    static final String VIEW_SMS_RESTRICTED = "sms_restricted";

    private static final Integer ONE = Integer.valueOf(1);

    private static final String[] CONTACT_QUERY_PROJECTION =
            new String[] { Contacts.Phones.PERSON_ID };
    private static final int PERSON_ID_COLUMN = 0;

    /**
     * These are the columns that are available when reading SMS
     * messages from the ICC.  Columns whose names begin with "is_"
     * have either "true" or "false"As their values. These columns are available when the SMS message is read from the ICC. Columns with names beginning with "is_" have values that are either"true", or"false". */ private final static String[] ICC_COLUMNS = new String[] {// N.B.: These columns must appear in the same order as the calls to be added appear in convertIccToSms."service_center_address",       // getServiceCenterAddress
        "address",                      // getDisplayOriginatingAddress
        "message_class",                // getMessageClass
        "body",                         // getDisplayMessageBody
        "date",                         // getTimestampMillis
        "status",                       // getStatusOnIcc
        "index_on_icc",                 // getIndexOnIcc
        "is_status_report",             // isStatusReportMessage
        "transport_type",               // Always "sms".
        "type",                         // Always MESSAGE_TYPE_ALL.
        "locked",                       // Always 0 (false).
        "error_code",                   // Always 0
        "_id"}; --->private SQLiteOpenHelper mOpenHelper; // Database operation class private final static String TAG ="SmsProvider";
    private final static String VND_ANDROID_SMS = "vnd.android.cursor.item/sms";
    private final static String VND_ANDROID_SMSCHAT =
            "vnd.android.cursor.item/sms-chat";
    private final static String VND_ANDROID_DIR_SMS =
            "vnd.android.cursor.dir/sms";

    private static final String[] sIDProjection = new String[] { "_id"}; -- -- -- - > operation identifier -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- private static final ints SMS_ALL = 0; private static final int SMS_ALL_ID = 1; private static final int SMS_INBOX = 2; private static final int SMS_INBOX_ID = 3; private static final int SMS_SENT = 4; private static final int SMS_SENT_ID = 5; private static final int SMS_DRAFT = 6; private static final int SMS_DRAFT_ID = 7; private static final int SMS_OUTBOX = 8; private static final int SMS_OUTBOX_ID = 9; private static final int SMS_CONVERSATIONS = 10; private static final int SMS_CONVERSATIONS_ID = 11; private static final int SMS_RAW_MESSAGE = 15; private static final int SMS_ATTACHMENT = 16; private static final int SMS_ATTACHMENT_ID = 17; private static final int SMS_NEW_THREAD_ID = 18; private static final int SMS_QUERY_THREAD_ID = 19; private static final int SMS_STATUS_ID = 20; private static final int SMS_STATUS_PENDING = 21; private static final int SMS_ALL_ICC = 22; private static final int SMS_ICC = 23; private static final int SMS_FAILED = 24; private static final int SMS_FAILED_ID = 25; private static final int SMS_QUEUED = 26; private static final int SMS_UNDELIVERED = 27; -------------------------------------------------------- private static final UriMatcher sURLMatcher = new UriMatcher(UriMatcher.NO_MATCH); Surlmatcher.adduri (-->static {// static code block defines the operation item --> surlMatcher.adduri (-->static {// static code block defines the operation item --> surlMatcher.adduri ("sms", null, SMS_ALL); // If null is, all surlMatcher.adduri ("sms"."#", SMS_ALL_ID);
        sURLMatcher.addURI("sms"."inbox", SMS_INBOX);
        sURLMatcher.addURI("sms"."inbox/#", SMS_INBOX_ID);
        sURLMatcher.addURI("sms"."sent", SMS_SENT);
        sURLMatcher.addURI("sms"."sent/#", SMS_SENT_ID);
        sURLMatcher.addURI("sms"."draft", SMS_DRAFT);
        sURLMatcher.addURI("sms"."draft/#", SMS_DRAFT_ID);
        sURLMatcher.addURI("sms"."outbox", SMS_OUTBOX);
        sURLMatcher.addURI("sms"."outbox/#", SMS_OUTBOX_ID);
        sURLMatcher.addURI("sms"."undelivered", SMS_UNDELIVERED);
        sURLMatcher.addURI("sms"."failed", SMS_FAILED);
        sURLMatcher.addURI("sms"."failed/#", SMS_FAILED_ID);
        sURLMatcher.addURI("sms"."queued", SMS_QUEUED);
        sURLMatcher.addURI("sms"."conversations", SMS_CONVERSATIONS);
        sURLMatcher.addURI("sms"."conversations/*", SMS_CONVERSATIONS_ID);
        sURLMatcher.addURI("sms"."raw", SMS_RAW_MESSAGE);
        sURLMatcher.addURI("sms"."attachments", SMS_ATTACHMENT);
        sURLMatcher.addURI("sms"."attachments/#", SMS_ATTACHMENT_ID);
        sURLMatcher.addURI("sms"."threadID", SMS_NEW_THREAD_ID);
        sURLMatcher.addURI("sms"."threadID/*", SMS_QUERY_THREAD_ID);
        sURLMatcher.addURI("sms"."status/#", SMS_STATUS_ID);
        sURLMatcher.addURI("sms"."sr_pending", SMS_STATUS_PENDING);
        sURLMatcher.addURI("sms"."icc", SMS_ALL_ICC);
        sURLMatcher.addURI("sms"."icc/#", SMS_ICC);
        //we keep these for not breaking old applications
        sURLMatcher.addURI("sms"."sim", SMS_ALL_ICC);
        sURLMatcher.addURI("sms"."sim/#", SMS_ICC);
    }
Copy the code

2. onCreate()methods

Here you get a database operation class for MmsSmsDatabaseHelper

@Override
    public boolean onCreate() {
        setAppOps(AppOpsManager.OP_READ_SMS, AppOpsManager.OP_WRITE_SMS);
        mOpenHelper = MmsSmsDatabaseHelper.getInstance(getContext());
        return true;
    }
Copy the code

3. Query method
@Override public Cursor query(Uri url, String[] projectionIn, String selection, String[] selectionArgs, String sort) { final boolean accessRestricted = ProviderUtil.isAccessRestricted( getContext(), getCallingPackage(), Binder.getCallingUid()); final String smsTable = getSmsTable(accessRestricted); SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); // Generate the body of the query. int match = sURLMatcher.match(url); // Obtain the operation identifier switch (match) {// Query according to the situationcase SMS_ALL:
                constructQueryForBox(qb, Sms.MESSAGE_TYPE_ALL, smsTable);
                break;
            case SMS_UNDELIVERED:
                constructQueryForUndelivered(qb, smsTable);
                break;
            case SMS_FAILED:
                constructQueryForBox(qb, Sms.MESSAGE_TYPE_FAILED, smsTable);
                break;
            case SMS_QUEUED:
                constructQueryForBox(qb, Sms.MESSAGE_TYPE_QUEUED, smsTable);
                break;
            case SMS_INBOX:
                constructQueryForBox(qb, Sms.MESSAGE_TYPE_INBOX, smsTable);
                break;
            case SMS_SENT:
                constructQueryForBox(qb, Sms.MESSAGE_TYPE_SENT, smsTable);
                break; . } String orderBy = null;if(! Textutils.isempty (sort)) {// If sort is not empty orderBy = sort; / / assign}else if(qb.getTables().equals(smsTable)) { orderBy = Sms.DEFAULT_SORT_ORDER; / / use the default sort} - > SQLiteDatabase db. = mOpenHelper getReadableDatabase (); SQLiteDatabase --> Cursor ret = qb.query(db, projectionIn, Selection, selectionArgs, null, null, orderBy); Ret. SetNotificationUri (getContext().getContentResolver(), NOTIFICATION_URI);returnret; } private void constructQueryForBox(SQLiteQueryBuilder qb, int)type, String smsTable) {
    qb.setTables(smsTable);

    if (type! = sms.message_type_all) {// If not All, query qb.appendWHERE () based on the type passed in."type=" + type); }}Copy the code

4. Delete methods
    @Override
    public int delete(Uri url, String where, String[] whereArgs) { int count; int match = sURLMatcher.match(url); ---> SQLiteDatabase db = mOpenHelper.getWritableDatabase(); // Get SQLiteDatabase switch (match) {// handle according to branchcase SMS_ALL:
                count = db.delete(TABLE_SMS, where.whereArgs); // Execute the delete statementif(count ! = 0) { // Don't update threads unless something changed. MmsSmsDatabaseHelper.updateAllThreads(db, where, whereArgs); } break; case SMS_ALL_ID: ... break; case SMS_CONVERSATIONS_ID: ... break; case SMS_RAW_MESSAGE: count = db.delete("raw", where, whereArgs); // Execute the delete statement break; case SMS_STATUS_PENDING: count = db.delete("sr_pending", where, whereArgs); // Execute the delete statement break; case SMS_ICC: String messageIndexString = url.getPathSegments().get(1); return deleteMessageFromIcc(messageIndexString); default: throw new IllegalArgumentException("Unknown URL"); } if (count > 0) { notifyChange(url); } return count; }Copy the code

If you look at these two, you can see that there are different operations based on the Uri, the core is still SQLiteDatabase’s database operations, and the ContentProvider just encapsulates and exposes it to everyone


5. The most important thing to remember is to configure


Custom ContentProvider:SwordProvider

This should be very rarely used, not system level application provided data you dare to use? Here’s a little to learn about entering the following Sqlite database related, non-combatant quick standby… Still take “million world divine soldier record” table to see

| - table analysis: the database name: weapon table name: sworld fields: Id ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL Name VARCHAR(32) NOT NULL Attack FORCE ATK SMALLINT UNSIGNED DEFAULT 1000 Holder user VARCHAR (32) NOT NULL | - built TABLE statements CREATE TABLE sword (id INTEGER PRIMARY KEY AUTOINCREMENT the NOT NULL, name VARCHAR(32) NOT NULL, atk SMALLINT UNSIGNED NOT NULL DEFAULT 1000, user VARCHAR(32) NOT NULL, );Copy the code

Create a class that inherits from ContentProvider

ContentProvider is an abstract class that implements the following methods

/** * Author: Zhang Feng Jieteilie <br/> * Time: 2019/2/28/028:11:42<br/> * Email: [email protected]<br/> * Description: */ public class SwordProvider extends ContentProvider {@override public BooleanonCreate() {
        return false;
    }
    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        return null;
    }
    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        return null;
    }
    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        return null;
    }
    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        return 0;
    }
    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
        return0; }}Copy the code

2. Database related
2.1– Generate the database

I am based on the MmsSmsDatabaseHelper source code to write, after all, is written by the big guy, refer to the writing style

public class SwordDatabaseHelper extends SQLiteOpenHelper {
    private static String DATABASE_NAME = "weapon.db"; Private static int DATABASE_VERSION = 1; Private static SwordDatabaseHelper sInstance; Public static synchronized SwordDatabaseHelper getInstance(Context Context) {synchronized SwordDatabaseHelper getInstance(Context Context) {if (sInstance == null) {
            synchronized (SwordDatabaseHelper.class) {
                if(sInstance == null) { sInstance = new SwordDatabaseHelper(context); }}}returnsInstance; } public SwordDatabaseHelper(@Nullable Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { createSwordTable(db); } /** * createSwordTable ** @param db SQLiteDatabase */ private void createSwordTable(SQLiteDatabase db) {db.execsql ("CREATE TABLE sword (" +
                "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," +
                "name VARCHAR(32) NOT NULL," +
                "atk INTEGER DEFAULT 1000," +
                "user VARCHAR(32) NOT NULL" +
                "); ");
    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }
}
Copy the code

2.CURD test — add, delete, modify and check

This is the basic syntax of SQL

SwordDatabaseHelper helper = new SwordDatabaseHelper(this); SQLiteDatabase db = helper.getWritableDatabase(); | - insert test db. ExecSQL ("INSERT INTO sword(name,atk,user) VALUES" +
                    "(' The Best Sword ',7000,' Bujing Cloud ')"); | - modify the test db. ExecSQL ("UPDATE sword SET atk=3500 WHERE id=1"); | - query test Cursor Cursor = the rawQuery ("SELECT * FROM sword", null);
while (cursor.moveToNext()) {
    String id = cursor.getString(cursor.getColumnIndex("id"));
    String name = cursor.getString(cursor.getColumnIndex("name"));
    String atk = cursor.getString(cursor.getColumnIndex("atk"));
    String user = cursor.getString(cursor.getColumnIndex("user"));
    Log.e(TAG, "rawQuery: "+id + "-" + name + "-" + atk + "-"+ user ); / / rawQuery: 1 - the best sword - 3500 - cloud} cursor. The close (); / / close the cursor | -- delete test db. ExecSQL ("DELETE FROM sword WHERE id=1");
Copy the code

3. Use of SwordDatabaseHelper in ContentProvider

Now that the test is ok, let’s implement a few methods of the ContentProvider, and set the URI to add, delete, modify and check four… Rules can be set by themselves, and methods can be differentiated by surimatcher.match (URI)

/** * Author: Zhang Feng Jieteilie <br/> * Time: 2019/2/28/028:11:42<br/> * Email: [email protected]<br/> * Description: */ public class SwordProvider extends ContentProvider {private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); private static final int SWORD_QUERY = 0; private static final int SWORD_INSERT = 1; private static final int SWORD_UPDATE = 2; private static final int SWORD_DELETE = 3; private static final String TABLE_NAME ="sword"; Static {// Add a matching rule to the current sUriMatcher surimatcher.adduri ("toly1994.com.sword"."query", SWORD_QUERY);
        sUriMatcher.addURI("toly1994.com.sword"."insert", SWORD_INSERT);
        sUriMatcher.addURI("toly1994.com.sword"."update", SWORD_UPDATE);
        sUriMatcher.addURI("toly1994.com.sword"."delete", SWORD_DELETE);
    }

    private SQLiteOpenHelper mOpenHelper;

    @Override
    public boolean onCreate() {
        mOpenHelper = SwordDatabaseHelper.getInstance(getContext());
        return true; } @Nullable @Override public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @nullable String[] selectionArgs, @nullable String sortOrder) {int result = surimatcher.match (uri);if (result == SWORD_QUERY) {
            SQLiteDatabase db = mOpenHelper.getReadableDatabase();
            return db.query(TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);

        } else {
            throw new IllegalStateException("Query Uri error");
        }
    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        returnnull; } @Nullable @Override public Uri insert(@NonNull Uri uri, @nullable ContentValues values) {int result = surimatcher.match (uri);if(result == SWORD_INSERT) { SQLiteDatabase db = mOpenHelper.getWritableDatabase(); Long insert = db.insert(TABLE_NAME, null, values); // the second parameter: GetContext ().getContentResolver().NotifyChange (URI, null); db.close();return Uri.parse(String.valueOf(insert));
        } else {
            throw new IllegalStateException("Insert Uri error"); } } @Override public int delete(@NonNull Uri uri, @Nullable String selection, @nullable String[] selectionArgs) {int result = surimatcher.match (uri);if (result == SWORD_DELETE) {
            SQLiteDatabase db = mOpenHelper.getWritableDatabase();
            int delete = db.delete(TABLE_NAME, selection, selectionArgs);
            db.close();
            return delete;
        } else {
            throw new IllegalStateException("Delete Uri error"); } } @Override public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @nullable String[] selectionArgs) {int result = surimatcher.match (uri);if (result == SWORD_UPDATE) {
            SQLiteDatabase db = mOpenHelper.getWritableDatabase();
            int update = db.update(TABLE_NAME, values, selection, selectionArgs);
            db.close();
            return update;
        } else {
            throw new IllegalStateException("Update Uri error"); }}}Copy the code

4. Configuration
<provider
        android:name=".provider.swordProvider.SwordProvider"
        android:authorities="toly1994.com.sword"
        android:exported="true"/>
Copy the code

As you should know, this is the system’s SmsProvider, which provides a database for global operation


5. Now go to == another app== to test

After testing, it is available, that is, another app can operate the database in the application just now

/** * Author: Zhang Feng Jiete Lie <br/> * Time: 2019/2/27/027:19:52<br/> * Email: [email protected]<br/> * Description: Public class SwordProviderActivity extends AppCompatActivity {private static final String TAG ="SwordProviderActivity";
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); ContentResolver resolver = getContentResolver(); // insert(resolver); // Insert test // query(resolver); Update (resolver); // Update query(resolver); delete(resolver); // Delete test query(resolver); } /** * delete test ** @param resolver */ private void delete(ContentResolver resolver) {Uri Uri = uri.parse ("content://toly1994.com.sword/delete");
        resolver.delete(uri, "name=?", new String[]{"Dragon slayer."}); } /** * @param resolver */ private void insert(ContentResolver resolver) {Uri Uri = uri.parse (uri.parse)"content://toly1994.com.sword/insert");
        ContentValues values = new ContentValues();
        values.put("name"."Dragon slayer.");
        values.put("atk"."3000");
        values.put("user"."Zhang Wuji"); resolver.insert(uri, values); } /** * @param resolver */ private void update(ContentResolver resolver) {Uri Uri = uri.parse (uri.parse)"content://toly1994.com.sword/update");
        ContentValues values = new ContentValues();
        values.put("name"."Dragon slayer.");
        values.put("atk"."3500");
        values.put("user"."Zhang Wuji");
        resolver.update(uri, values, "name=?", new String[]{"Dragon slayer."}); } /** * @param resolver */ private void query(ContentResolver resolver) {Uri Uri = uri.parse ("content://toly1994.com.sword/query");
        Cursor cursor = resolver.query(uri, null, null, null, null);
        whileInt id = cursor.getint (cursor.getColumnIndex());"id"));
            String name = cursor.getString(cursor.getColumnIndex("name"));
            int atk = cursor.getInt(cursor.getColumnIndex("atk"));
            String user = cursor.getString(cursor.getColumnIndex("user"));
            Log.e(TAG, "query: " + id + "-" + name + "-" + atk + "-"+ user); //query: 2-- longdao --3000-- Zhang Wuji}}}Copy the code

As for the internal implementation of ContentProvider, there is no interest, not on the agenda, so far, the Four components of Android are resummed up again, this is the second time that the end of the four components of several articles with a engineering test, Github address: Welcome to Star