Your favorite buddies are welcome to pay attention. I will share Android knowledge points and analysis regularly, and keep updating BATJ interview topics. You are welcome to come to discuss and communicate. If you have good articles, you are welcome to contribute.
1. What is ContentProvider
ContentProvider is the interface that your own APP opens to third-party APPs for accessing your own database data.
Third-party APP s can use this interface to add, delete, and inspect specified data.
So how do you define your own ContentProvider interface?
Before answering the question, take a look at Uri.
2. What is Uri
The reason is that uri is a key parameter for ContentProvider to resolve external requests (or third-party access to its own database).
The string format of Uri is as follows
for example
content://com.breakloop.sqlitehelperdemo/hero/1
From the Uri example above, you can get the following information.
Third-party APP s want to
Access the database of com.breakloop.sqlitehelperdemo.As to which, it is specified by the contentProvider internal mapping.
Access the table hero.Whether the table name is really a hero has the final say from the contentProvider.
Access data with id 1.As to whether the id represents the specific meaning, the right of interpretation is also vested in the contentProvider.
So, how does ContentProvider make its map a specific database operation after third-party APP passes Uri in?
This led to the introduction of the UriMatcher tool class.
3.UriMatcher
This tool class can map Uri to behavior code of type int.Behavior code, which can be seen as an enumeration type customized by ContentProvider.Different behavior codes bind different database operations.
Let's first look at the mapping of Uri to behavior code
public final static String AUTHORITY="com.breakloop.contentproviderdemo1"; public final static int BY_NAME=1; public final static int BY_AGE=2; public final static int BY_SEX=3; public final static int BY_NONE=0; public final static String PATH_BY_NAME=DBConst.TABLE_PERSON+"/ByName/*"; public final static String PATH_BY_AGE=DBConst.TABLE_PERSON+"/ByAge/#"; public final static String PATH_BY_SEX=DBConst.TABLE_PERSON+"/BySex/*"; }
static { matcher=new UriMatcher(UriMatcher.NO_MATCH); matcher.addURI(MatcherConst.AUTHORITY,MatcherConst.PATH_BY_NAME,MatcherConst.BY_NAME); matcher.addURI(MatcherConst.AUTHORITY,MatcherConst.PATH_BY_AGE,MatcherConst.BY_AGE); matcher.addURI(MatcherConst.AUTHORITY,MatcherConst.PATH_BY_SEX,MatcherConst.BY_SEX); matcher.addURI(MatcherConst.AUTHORITY,DBConst.TABLE_PERSON,MatcherConst.BY_NONE); }
In the example above, UriMatch binds four Uri and maps each Uri to four behavior codes.
Escape characters are used.#for any number and * for any letter.
So how do you map the behavior code to a specific database operation?In other words, where do you use UriMatcher?Of course in ContentProvider!!!Complete the operation mapping in the Add/Remove check method in ContentProvider.
Let's look at the creation of the ContentProvider.
4. Creation of ContentProvider
Create a ContentProvider with Android Studio first.
AUTHORITY is required during creation.
Once the ContentProvider is generated, Android Studio automatically helps the ContentProvider register in Manifest.
Next, let's look at the structure of the ContentProvider.
5. Structure of ContentProvider
import android.content.ContentProvider;import android.content.ContentValues;import android.content.UriMatcher;import android.database.Cursor;import android.net.Uri;public class MyContentProvider extends ContentProvider { public MyContentProvider() { } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { // Implement this to handle requests to delete one or more rows. throw new UnsupportedOperationException("Not yet implemented"); } @Override public String getType(Uri uri) { // TODO: Implement this to handle requests for the MIME type of the data // at the given URI. throw new UnsupportedOperationException("Not yet implemented"); } @Override public Uri insert(Uri uri, ContentValues values) { // TODO: Implement this to handle requests to insert a new row. throw new UnsupportedOperationException("Not yet implemented"); } @Override public boolean onCreate() { // TODO: Implement this to initialize your content provider on startup. return false; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // TODO: Implement this to handle query requests from clients. throw new UnsupportedOperationException("Not yet implemented"); } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { // TODO: Implement this to handle requests to update one or more rows. throw new UnsupportedOperationException("Not yet implemented"); } }
There are seven methods.There is one construction method, four database methods (add-delete-check), one initialization method (onCreate), and one getType.
For getType, we'll explain later.
There is nothing to explain about the construction method.
Regarding the initialization method, when true is returned, the initialization is successful, otherwise it fails.Since we are going to operate on the database, we need to get the sqlite database object.
public boolean onCreate() { helper=new mySqliteHelper(getContext(),DBConst.DB_NAME,null,1); return true; }
With regard to database methods, we see Uri in the pass, so we need to use UirMatcher here.We'll add the UriMatcher snippet to MyContentProvider. That way, we can parse Uri in each database method.At the same time, due to the existence of sqlite database objects, the database can be operated on accordingly.
6. Behavior Code Mapping Database Operation
Let's first look at the simplest insertion.
public Uri insert(Uri uri, ContentValues values) { Uri returnUri=null; SQLiteDatabase db=helper.getWritableDatabase(); switch (matcher.match(uri)){ case MatcherConst.BY_NONE: long recordID=db.insert(DBConst.TABLE_PERSON,null,values); returnUri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON+"/"+recordID); break; default: break; } return returnUri; }
Let's look at a slightly more complex query.
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { Cursor cursor=null; SQLiteDatabase db=helper.getReadableDatabase(); switch (matcher.match(uri)){ case MatcherConst.BY_NONE: cursor=db.query(DBConst.TABLE_PERSON,projection,selection,selectionArgs,null,null,sortOrder); break; case MatcherConst.BY_AGE: cursor=db.query(DBConst.TABLE_PERSON,projection,DBConst.COLUMN_AGE+"=?",new String[]{uri.getPathSegments().get(2)},null,null,sortOrder); break; case MatcherConst.BY_SEX: cursor=db.query(DBConst.TABLE_PERSON,projection,DBConst.COLUMN_SEX+"=?",new String[]{uri.getPathSegments().get(2)},null,null,sortOrder); break; case MatcherConst.BY_NAME: cursor=db.query(DBConst.TABLE_PERSON,projection,DBConst.COLUMN_NAME+"=?",new String[]{uri.getPathSegments().get(2)},null,null,sortOrder); break; default: break; } return cursor; }
One thing to note here is how to retrieve incoming data from Uri.The fetch method used is uri.getPathSegments().get(index).This method takes the String section after AUTHORITY.
String[] is then generated using'/'as the delimiter.
Next comes the update operation.
@Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { int recordID=0; SQLiteDatabase db=helper.getWritableDatabase(); switch (matcher.match(uri)){ case MatcherConst.BY_NONE: recordID=db.update(DBConst.TABLE_PERSON,values,null,null); break; case MatcherConst.BY_AGE: recordID=db.update(DBConst.TABLE_PERSON,values,DBConst.COLUMN_AGE+"=?",new String[]{uri.getPathSegments().get(2)}); break; case MatcherConst.BY_SEX: recordID=db.update(DBConst.TABLE_PERSON,values,DBConst.COLUMN_SEX+"=?",new String[]{uri.getPathSegments().get(2)}); break; case MatcherConst.BY_NAME: recordID=db.update(DBConst.TABLE_PERSON,values,DBConst.COLUMN_NAME+"=?",new String[]{uri.getPathSegments().get(2)}); break; default: break; } return recordID; }
There are also deletions.
public int delete(Uri uri, String selection, String[] selectionArgs) { int recordID=0; SQLiteDatabase db=helper.getWritableDatabase(); switch (matcher.match(uri)){ case MatcherConst.BY_NONE: recordID=db.delete(DBConst.TABLE_PERSON,null,null); break; case MatcherConst.BY_AGE: recordID=db.delete(DBConst.TABLE_PERSON,DBConst.COLUMN_AGE+"=?",new String[]{uri.getPathSegments().get(2)}); break; case MatcherConst.BY_SEX: recordID=db.delete(DBConst.TABLE_PERSON,DBConst.COLUMN_SEX+"=?",new String[]{uri.getPathSegments().get(2)}); break; case MatcherConst.BY_NAME: recordID=db.delete(DBConst.TABLE_PERSON,DBConst.COLUMN_NAME+"=?",new String[]{uri.getPathSegments().get(2)}); break; default: break; } return recordID; }
So how do third parties call the ContentProvider?
7. Use of ContentProvider
Here, we create a new project, contentproviderdemo2, to use where necessary
public ContentResolver getContentResolver()
Get the ContentProvider instance, and you can then pass in the Uri and call the database-related methods.
For example, let's insert four records.
Uri returnUri=null; ContentResolver resolver=getContentResolver(); Uri uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON); ContentValues values=new ContentValues(); values.put(DBConst.COLUMN_NAME,"A"); values.put(DBConst.COLUMN_AGE,10); values.put(DBConst.COLUMN_SEX,"Male"); returnUri=resolver.insert(uri,values); if(returnUri!=null) Log.i(TAG, "return Uri = "+returnUri.toString()); values.put(DBConst.COLUMN_NAME,"B"); values.put(DBConst.COLUMN_AGE,11); values.put(DBConst.COLUMN_SEX,"Male"); returnUri=resolver.insert(uri,values); if(returnUri!=null) Log.i(TAG, "return Uri = "+returnUri.toString()); values.put(DBConst.COLUMN_NAME,"C"); values.put(DBConst.COLUMN_AGE,12); values.put(DBConst.COLUMN_SEX,"Female"); returnUri=resolver.insert(uri,values); if(returnUri!=null) Log.i(TAG, "return Uri = "+returnUri.toString()); values.put(DBConst.COLUMN_NAME,"D"); values.put(DBConst.COLUMN_AGE,13); values.put(DBConst.COLUMN_SEX,"Female"); returnUri=resolver.insert(uri,values); if(returnUri!=null) Log.i(TAG, "return Uri = "+returnUri.toString());
Let's look at the output.
I/com.breakloop.contentproviderdemo2.MainActivity: return Uri = content://com.breakloop.contentproviderdemo1/PERSON/1I/com.breakloop.contentproviderdemo2.MainActivity: return Uri = content://com.breakloop.contentproviderdemo1/PERSON/2I/com.breakloop.contentproviderdemo2.MainActivity: return Uri = content://com.breakloop.contentproviderdemo1/PERSON/3I/com.breakloop.contentproviderdemo2.MainActivity: return Uri = content://com.breakloop.contentproviderdemo1/PERSON/4
Now that the writing is successful, let's check.
public void selectRecord(){ Uri uri; String name="A"; int age=11; String sex="Male"; Log.i(TAG, "Select by Name"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON+"/ByName/"+name); selectRecord(uri); Log.i(TAG, "Select by Age"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON+"/ByAge/"+age); selectRecord(uri); Log.i(TAG, "Select by Sex"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON+"/BySex/"+sex); selectRecord(uri); Log.i(TAG, "Select All"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON); selectRecord(uri); } private void selectRecord(Uri uri){ Cursor cursor; cursor=resolver.query(uri,new String[]{DBConst.COLUMN_AGE, DBConst.COLUMN_NAME, DBConst.COLUMN_SEX},null,null,null); if(cursor!=null){ while(cursor.moveToNext()){ Log.i(TAG, "name = "+cursor.getString(1)+ " age = "+cursor.getInt(0) +" "+cursor.getString(2)); } } }
The output is as follows
I/com.breakloop.contentproviderdemo2.MainActivity: Select by Name I/com.breakloop.contentproviderdemo2.MainActivity: name = A age = 10 Male I/com.breakloop.contentproviderdemo2.MainActivity: Select by Age I/com.breakloop.contentproviderdemo2.MainActivity: name = B age = 11 Male I/com.breakloop.contentproviderdemo2.MainActivity: Select by Sex I/com.breakloop.contentproviderdemo2.MainActivity: name = A age = 10 Male I/com.breakloop.contentproviderdemo2.MainActivity: name = B age = 11 Male I/com.breakloop.contentproviderdemo2.MainActivity: Select All I/com.breakloop.contentproviderdemo2.MainActivity: name = A age = 10 Male I/com.breakloop.contentproviderdemo2.MainActivity: name = B age = 11 Male I/com.breakloop.contentproviderdemo2.MainActivity: name = C age = 12 Female I/com.breakloop.contentproviderdemo2.MainActivity: name = D age = 13 Female
Let's update it again.
public void updateRecord(){ Uri uri; String name="A"; int age=11; String sex="Female"; ContentValues values=new ContentValues(); Log.i(TAG, "Update by Name"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON+"/ByName/"+name); values.put(DBConst.COLUMN_NAME,name+name); update(uri,values); Log.i(TAG, "Update by Age"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON+"/ByAge/"+age); values.clear(); values.put(DBConst.COLUMN_AGE,14); update(uri,values); Log.i(TAG, "Update by Sex"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON+"/BySex/"+sex); values.clear(); values.put(DBConst.COLUMN_AGE,15); update(uri,values); Log.i(TAG, "Update All"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON); values.put(DBConst.COLUMN_SEX,"Male"); update(uri,values); Log.i(TAG, "Select All"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON); selectRecord(uri); } private void update(Uri uri,ContentValues values){ int count; count=resolver.update(uri,values,null,null); Log.i(TAG, "update "+count+" record"); }
give the result as follows
I/com.breakloop.contentproviderdemo2.MainActivity: Update by Name I/com.breakloop.contentproviderdemo2.MainActivity: update 1 record I/com.breakloop.contentproviderdemo2.MainActivity: Update by Age I/com.breakloop.contentproviderdemo2.MainActivity: update 1 record I/com.breakloop.contentproviderdemo2.MainActivity: Update by Sex I/com.breakloop.contentproviderdemo2.MainActivity: update 2 record I/com.breakloop.contentproviderdemo2.MainActivity: Update All I/com.breakloop.contentproviderdemo2.MainActivity: update 4 record I/com.breakloop.contentproviderdemo2.MainActivity: Select All I/com.breakloop.contentproviderdemo2.MainActivity: name = AA age = 15 Male I/com.breakloop.contentproviderdemo2.MainActivity: name = B age = 15 Male I/com.breakloop.contentproviderdemo2.MainActivity: name = C age = 15 Male I/com.breakloop.contentproviderdemo2.MainActivity: name = D age = 15 Male
No more, delete!(Here's what happens to the pre-update database)
public void deleteRecord(){ Uri uri; String name="A"; int age=11; String sex="Female"; Log.i(TAG, "Delete by Name"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON+"/ByName/"+name); delete(uri); Log.i(TAG, "Select All"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON); selectRecord(uri); Log.i(TAG, "Delete by Age"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON+"/ByAge/"+age); delete(uri); Log.i(TAG, "Select All"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON); selectRecord(uri); Log.i(TAG, "Delete by Sex"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON+"/BySex/"+sex); delete(uri); Log.i(TAG, "Select All"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON); selectRecord(uri); Log.i(TAG, "Delete All"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON); delete(uri); Log.i(TAG, "Select All"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON); selectRecord(uri); } private void delete(Uri uri){ int count; count=resolver.delete(uri,null,null); Log.i(TAG, "delete "+count+" record"); }
give the result as follows
I/com.breakloop.contentproviderdemo2.MainActivity: delete 1 record I/com.breakloop.contentproviderdemo2.MainActivity: Select All I/com.breakloop.contentproviderdemo2.MainActivity: name = B age = 11 Male I/com.breakloop.contentproviderdemo2.MainActivity: name = C age = 12 Female I/com.breakloop.contentproviderdemo2.MainActivity: name = D age = 13 Female I/com.breakloop.contentproviderdemo2.MainActivity: Delete by Age I/com.breakloop.contentproviderdemo2.MainActivity: delete 1 record I/com.breakloop.contentproviderdemo2.MainActivity: Select All I/com.breakloop.contentproviderdemo2.MainActivity: name = C age = 12 Female I/com.breakloop.contentproviderdemo2.MainActivity: name = D age = 13 Female I/com.breakloop.contentproviderdemo2.MainActivity: Delete by Sex I/com.breakloop.contentproviderdemo2.MainActivity: delete 2 record I/com.breakloop.contentproviderdemo2.MainActivity: Select All I/com.breakloop.contentproviderdemo2.MainActivity: Delete All I/com.breakloop.contentproviderdemo2.MainActivity: delete 0 record I/com.breakloop.contentproviderdemo2.MainActivity: Select All
At this point, the creation and use of the ContentProvider is covered.
If, just for use, you can just see here!
Later, the answer has not been found in this article!So, just record!
If you have friends you know, look forward to pointing out.
So what else?
Remember getType in ContentProvider?
So far, we have not implemented the getType method.This has no effect on the use of the ContententProvider.So here comes the question....What does getType do?When will it be used?
There are two interpretations of getType on the Web.
1. Used for parsing the returned data.Determine if it is one or more data.If the getType method is implemented, it will be parsed according to the implementation method, which improves the efficiency.Otherwise, the system will automatically resolve.
2. Avoid the new Intent(String action, Uri uri) method failing to start the activity.
For Interpretation 1, no official source was found.And for Explanation 2, I don't know!What can I do to block activity with ContentProvider?
The prototype comment on the implementation of the getType method gives the answer.
The method returns a String of type MIME.The output varies depending on the end of the Uri.
If Uri ends with Path, the return format is
vnd.android.cursor.dir/vnd.<authority>.<path>
If Uri ends with id, the return format is
vnd.android.cursor.item/vnd.<authority>.<path>
Therefore, getType() in our instance is implemented as
@Override public String getType(Uri uri) { Log.i(TAG, "getType: "); String authorityAndPath=MatcherConst.AUTHORITY+"."+DBConst.TABLE_PERSON; String handerPath="vnd.android.cursor.dir/vnd."; String handerID="vnd.android.cursor.item/vnd."; switch (matcher.match(uri)){ case MatcherConst.BY_NONE: return handerPath+authorityAndPath; case MatcherConst.BY_AGE: case MatcherConst.BY_SEX: case MatcherConst.BY_NAME: return handerID+authorityAndPath; default: return null; } }
8. Summary
This article mainly introduces some knowledge of the ContentProvider of the four components in Android. Small friends who think the article is good can pay attention to and share it, and welcome you to come to discuss and communicate.