[TOC]

What is a content provider?

Content Providers Mainly used in different applications between the realization of data sharing function, he provides a complete set of mechanisms, allowing a program to access another program in the data, but also to ensure the security of the data to be accessed, the current use of content provider ten Android to achieve cross-program data sharing standard way. Content providers can choose which portions of their data to share, thus ensuring the security of our data.

2. How to use content providers to get data from other applications

2.1 Permission Statement

Runtime permissions: a new feature introduced in 6.0 to better protect user privacy.

The usual permission declaration only needs to add the permission to be used in MainFest. 6.0 and later for some permissions, you need to check whether this permission exists in the code at runtime otherwise a dialog box will pop up to apply for permission. If rejected, you will not be able to use it.

Runtime permissions are not required for all permissions, only for user privacy. In addition to being declared in the ManiFest, it is requested again in the code, which will cause the application to throw a SecurityException() ** if the runtime permission is not used

public class MainActivity extends AppCompatActivity {
    private String TAG = "TAG";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        checkSelf();// Check permissions
    }

    private void checkSelf(a) {
        // If you want to check multiple permissions, you can put the permissions to be checked into an array or collection
        if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
            /** * checkSelfPermission checks if the current application has obtained the specified permission, and if not, calls the method that requested the permission
            Log.d(TAG, "CheckSelf: permission allowed");
        } else {
            / * * * through ActivityCompat requestPermissions dynamic application permissions. * the first parameter: the current context * the second parameter: need to apply for the permission string, stored in the array. * The third argument: the query code, request permission to the final result will be through the way of the callback - > onRequestPermissionsResult (); In this method, it tells you if the last request was successful
            ActivityCompat.requestPermissions(MainActivity.this.new String[]{Manifest.permission.READ_CALENDAR,Manifest.permission.CAMERA}, 1); }}@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        /** * The request code is used to determine the specific permission, and the result; * grantResult[] saves the request permission, according to the order of the request permission save */
        switch (requestCode) {
            case 1:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Log.d(TAG, "OnRequestPermissionsResult: authorized");
                    for (int i = 0; i < grantResults.length; i++) {
                        Log.d(TAG, "OnRequestPermissionsResult: authorization situation."+grantResults[i]); }}else {
                    Log.d(TAG, "OnRequestPermissionsResult: you refused authorization");
                }
                break;
            case 2:
                break;
            default:
                break; }}}Copy the code

That’s the basic usage of runtime permissions

2.2 Basic usage and principle of content provider

Content providers are generally used in two ways, one is to use the existing content providers to read and manipulate the data in the corresponding program, the other is to create a content provider to provide external access to the data of our program (is through others (program) to provide the content provider to obtain others (program) want to give us the use of the data), the system’s own SMS, phone book, media library and other procedures have provided similar access interface, we can use this to develop and use again.

If you want to get data from a Content provider, you need the Content-resolver class. The GetContentResolver method in Context can get an instance of this class. Content-resolver provides methods similar to the SqLiteDatabase class for CRUD operations on shared data, with slightly different parameters.

Content providers are urIs that find data sources. Uris consist of authority and PATH. Authority is used to distinguish between different programs, usually using package names, and PATH is used to distinguish between different tables in the same program.

For example, a package called com.example.test has two tables table1,table2;

The standard Uri format is (:// the previous content is protocol):

​ content://com.example.test/table1

​ content://com.example.test/table2

This makes it clear which program and which table we want to access. So content providers’ CRUDs only accept Uri arguments to determine the location.

Looking for:

Uri uri=Uri.parse("content://com.example.test/table2");

Cursor cursor=getContentResolver().quert(uri,projection,selection,selectionArgs,sortOrder);

Quert () method parameters Corresponding SQL section describe
uri from table_name Specifies a table under an application to be queried
projection select column1,column2 Specifies the column name for the query
selection where column =value Specify constraints on where
selectionArgs Provide specific values for placeholders in where
sortOrder order by column1,column2 Specifies how to sort the query results

Fetching a value from a cursor is the same as the operation of a database. Select the type of data you want to retrieve and then select the column name

. String data=cursor.getString(cursor.getColumnIndex("columnName")); .Copy the code

Insert:

Just like a database, you assemble the data into ContentValues

ContentValues values=new ContentValues();
 values.put("columnName1"."value1");
 values.put("columnName2"."value2");
  getContentResolver().insert(uri,values);
Copy the code

Update:

ContentValues values=new ContentValues();
values.put("columnName1"."value1");
getContentResolver().update(Uri.parse(""),contentValues,"where column1=?".new String[]{"1"});
Copy the code

Update () : The first parameter specifies the location of the data; The second parameter specifies what value to update to; The third parameter specifies the condition; The fourth parameter specifies the default value in the WHERE condition statement;

Delete:

getContentResolver().delete(Uri.parse(""),"column=?".new String[]{"1"});
Copy the code

Parameters are similar to the above ones. There’s not much more to explain.

2.3 Use content providers to get data

Let’s use the content provider provided by the system to get the phone number of the name in the address book. Make sure you actually save several phone numbers in the address book.

1. Obtain the READ_CANTACTS permission first, otherwise the data cannot be read and an error will be reported.

2. The usage of query statements is similar to that of databases

public class MainActivity extends AppCompatActivity {
    private String TAG = "TAG";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_CONTACTS) ! = PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(MainActivity.this.new String[]{Manifest.permission.READ_CONTACTS}, 1);
        } else{ getData(); }}private void getData(a) {
        Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null.null.null.null);
        	/ / incoming Uri is ContactsContract.Com monData - Kinds. Phone class already help we encapsulate a constant
        // Click open source to see:
        //public static final Uri CONTENT_URI = Uri.withAppendedPath(Data.CONTENT_URI,
                    "phones");
        if(cursor ! =null) {
            while (cursor.moveToNext()) {
                String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
        / / ContactsContract.Com monDataKinds. Phone. DISPLAY_NAME is a constant, to save the data of the name of the class. The same below
                String phone = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                Log.d(TAG, "getData: " + name + "-"+ phone); }}}@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case 1:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    getData();
                } else {
                    Log.d(TAG, "OnRequestPermissionsResult: you click refused to!");
                }
                break;
            default:
                break; }}}Copy the code

Run the program to see the name printed with the phone number.

The main content is in getData(); In the method, the specific explanation is written in the comments, as long as you know the principle then becomes very convenient to use.

3. Create your own content provider

Basic knowledge:

Create a ContentProvider by creating a new class that inherits the ContentProvider, but must override the six methods in it;

Rewrite method: The return value use
onCreate(); boolean Called when the content provider is initialized. This is where the creation and upgrade of the database is usually done. Returning true indicates successful initialization of the content provider,false fails.
query(uri,projection, selection, selectionArgs, sortOrder); Cursor It finds data from content providers, uses uri parameters to determine which tables to look for, uses projection to determine which columns to look for, Selection to determine search criteria,selectionArgs to fill in default values for criteria in Selection, and sortOrder to check query nodes Fruit sorting; Query results into Cursor return;
insert(uri, values); Uri Add a piece of data to the content provider, using the URI to determine the table to be added to, and place the data to be added in the values parameter; Return a Cursor that represents the new record when added successfully.
update(uri, values, selection, selectionArgs); int Update existing data in the content provider, using the Uri parameter to determine which table to update, the new data is stored in values (only the values written here are updated), and the selection and selectIonArgs parameters are used to constrain which rows to update. The number of affected rows is returned as the return value
delete(uri, selection, selectionArgs) int Delete data in the content provider. The URI parameter is used to determine which table data to delete, and the selection and selectionArgs parameters are used to constrain which rows to delete. The number of deleted rows is returned as a return value;
getType(uri)(); String Returns the corresponding MIME type string based on the Uri passed in

Description of the two formats of Uri:

​ content://com.example.test/table1/1;

Exampke. test indicates that the caller expects to access data 1 in table Table1 in the com.exampke.test application

​ content://com.example.test/table1;

Exampke. test: indicates that the caller expects to access all data from table Table1 in the com.exampke.test application

However, wildcards are usually used to match the two formats:

: Matches a number of any length

#* : matches characters of any length

The content of the above can be written as: the content: / / com. Example. The test / * or the content: / / com. Example. The test/table1 / #

getType(); Returned data

​ content://com.example.test/table1/1;

​ content://com.example.test/table1;

Again, take these two examples.

MIME string: starts with VND +. + Android.cursor. dir/(or Android.cursor.item /) + VND. + AUTHORITY +. + PATH

​ vnd.android.cursor.dir/vnd.com.example.test.table1;

​ vnd.android.cursor.item/vnd.com.example.test.table1

3.1 Basic Creation steps

Create a class that inherits from ContentProvider and rewrite the six methods

The content provider must be registered in manifest.xml or it cannot be used

<provider
            android:name=".MyProvider" 
            android:authorities="com.example.h.content_demo_provider"
            android:enabled="true"
            android:exported="true" />
Copy the code

The first argument: class name

The second argument: is usually used with the package name to distinguish content providers between different programs

Third parameter: enable

The fourth parameter: indicates that access is allowed by other applications

Create a new content provider:


public class MyProvider extends ContentProvider {
    public static final int BOOK_DIT = 0;
    public static final int BOOK_ITEM = 1;
    public static final int CATEGORY_DIR = 2;
    public static final int CATEGORT_ITEM = 3;
    public static UriMatcher sUriMatcher;
    public static final String AUTHORITY = "com.example.h.content_demo_provider";
    private MyDatabaseHelper mMyDatabaseHelper;
    private SQLiteDatabase db;

    {
        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        sUriMatcher.addURI(AUTHORITY, "book", BOOK_DIT);
        sUriMatcher.addURI(AUTHORITY, "book/#", BOOK_ITEM);
        sUriMatcher.addURI(AUTHORITY, "category", CATEGORY_DIR);
        sUriMatcher.addURI(AUTHORITY, "category/#", CATEGORT_ITEM);
        //UriMatcher can match urIs by calling its match() method, which returns the third argument we filled in when we added the URI above


    }

    @Override
    /** * is called when initializing the content provider, which is usually used to create and upgrade the database
    public boolean onCreate(a) {
        // Initializes the resources required by the current content provider
        mMyDatabaseHelper = new MyDatabaseHelper(getContext(), "info.db".null.1);
        db = mMyDatabaseHelper.getWritableDatabase();
        Log.d(TAG, "OnCreate: Content provider initialization complete");
        return true;
        
    }

    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        // query method to determine which table of which program you want to query by parsing the URI. Match with UriMatchder and return the code you entered earlier in addUri() if any
        
        Cursor cursor = null;
        switch (sUriMatcher.match(uri)) {
            case BOOK_DIT:
                cursor = db.query("book", projection, selection, selectionArgs, null.null,
                        sortOrder);
                Log.d(TAG, "Query: query the entire table" + cursor);
                return cursor;
            case BOOK_ITEM:
                String itemId = uri.getPathSegments().get(1);
                cursor = db.query("book", projection, "id=?".new String[]{itemId}, null.null,
                        sortOrder);
                /** *.getPathsegments () splits the content URI permissions with/and places the split result in a list of strings. * returns a list [0] containing the path and [1] containing the ID */
                return cursor;
            case CATEGORT_ITEM:
                String itemId2 = uri.getPathSegments().get(1);
                cursor = db.query("category", projection, "id=?".new String[]{itemId2}, null.null,
                        sortOrder);
                return cursor;
            case CATEGORY_DIR:
                cursor = db.query("category", projection, selection, selectionArgs, null.null,
                        sortOrder);
                return cursor;
            default:
                returncursor; }}@Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        switch (sUriMatcher.match(uri)) {
            case BOOK_DIT:
                return "vnd.android.cursor.dir/vnd.com.example.h.content_demo_provider.book";

            case BOOK_ITEM:
                return "vnd.android.cursor.item/vnd.com.example.h.content_demo_provider.book";
            case CATEGORT_ITEM:
                return "vnd.android.cursor.item/vnd.com.example.h.content_demo_provider.category";
            case CATEGORY_DIR:
                return "vnd.android.cursor.dir/vnd.com.example.h.content_demo_provider.category";
            default:
                return null; }}@Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        Uri uriReturn = null;
        switch (sUriMatcher.match(uri)) {
            case BOOK_DIT:
            case BOOK_ITEM:
                long value = db.insert("book".null, values);
                uriReturn = Uri.parse("content://" + AUTHORITY + "/book/" + value);
                return uriReturn;
            // Returns the row ID of the newly inserted row, or -1 if an error occurs
            case CATEGORT_ITEM:
            case CATEGORY_DIR:
                long value2 = db.insert("category".null, values);
                uriReturn = Uri.parse("content://" + AUTHORITY + "/category/" + value2);
                return uriReturn;
            default:
                returnuriReturn; }}@Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        int deleteRows = 0;
        switch (sUriMatcher.match(uri)) {
            case BOOK_DIT:
                deleteRows = db.delete("book", selection, selectionArgs);
                return deleteRows;
            case BOOK_ITEM:
                String itemId1 = uri.getPathSegments().get(1);
                deleteRows = db.delete("book"."id=?".new String[]{itemId1});
                return deleteRows;
            case CATEGORT_ITEM:
                String itemId2 = uri.getPathSegments().get(1);
                deleteRows = db.delete("category"."id=?".new String[]{itemId2});
                return deleteRows;
            case CATEGORY_DIR:
                deleteRows = db.delete("category", selection, selectionArgs);
                return deleteRows;
            default:
                returndeleteRows; }}@Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
        int updateRows = 0;
        switch (sUriMatcher.match(uri)) {
            case BOOK_DIT:
                updateRows = db.update("book", values, selection, selectionArgs);
                return updateRows;
            case BOOK_ITEM:
                String itemId1 = uri.getPathSegments().get(1);
                updateRows = db.update("book", values, "id=?".new String[]{itemId1});
                return updateRows;
            case CATEGORT_ITEM:
                String itemId2 = uri.getPathSegments().get(1);
                updateRows = db.update("category", values, "id=?".new String[]{itemId2});
                return updateRows;
            case CATEGORY_DIR:
                updateRows = db.update("category", values, selection, selectionArgs);
                return updateRows;
            default:
                returnupdateRows; }}}Copy the code

Emerging methods:

uri.getPathSegments().get(1); //getPathSegments() returns a set that splits the uri after authority (get(0) and id (get(1)) so that the selected ID can be used as a conditional query against the database.

3.2 Cross-program data acquisition

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private Button btn1, btn2, btn3, btn4;
    private Uri mUriBook = Uri.parse("content://com.example.h.content_demo_provider/book");
    private Uri mUriCategory = Uri.parse("content://com.example.h.content_demo_provider/category");

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        //randomInsert();
        iQuery();

    }

    private void initView(a) {
        btn1 = findViewById(R.id.button);
        btn2 = findViewById(R.id.button2);
        btn3 = findViewById(R.id.button4);
        btn4 = findViewById(R.id.button5);
        btn4.setOnClickListener(this);
        btn3.setOnClickListener(this);
        btn2.setOnClickListener(this);
        btn1.setOnClickListener(this);
    }

    private void iQuery(a) {
        Cursor cursor = getContentResolver().query(mUriBook, null.null.null.null);
        if(cursor ! =null) {
            while (cursor.moveToNext()) {
                String id = cursor.getString(cursor.getColumnIndex("id"));
                String name = cursor.getString(cursor.getColumnIndex("name"));
                String author = cursor.getString(cursor.getColumnIndex("author")); System.out.println(id + name + author); }}else {
            System.out.println("Empty"); }}private void randomInsert(a) {
        ContentValues contentValues1 = new ContentValues();
        ContentValues contentValues2 = new ContentValues();
        for (int i = 0; i < 5; i++) {
            contentValues1.put("name"."name" + i);
            contentValues1.put("author"."author" + i);
            System.out.println(getContentResolver().insert(mUriBook, contentValues1));
            contentValues2.put("type"."type" + i);
            contentValues2.put("code"."code" + i);
            System.out.println(getContentResolver().insert(mUriCategory, contentValues2)); ;
        }
        // This method simply writes a bit of data to the database in another application through the content provider to facilitate subsequent CRUD.
    }

    private void iDelete(String value) {
        ContentValues contentValues = new ContentValues();
        int x = 0;
        Uri uri = Uri.parse("content://com.example.h.content_demo_provider/book/" + value);
        x = getContentResolver().delete(uri, null.null);
        Log.d("TAG"."IDelete: deleted return value :" + x);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button:
                iQuery();
                break;
            case R.id.button2:
                break;
            case R.id.button4:
                iDelete("1");
                break;
            case R.id.button5:
                break;
            default:
                break; }}}Copy the code

Basically, you define the Uri and you pass it to the content provider, tell it what you want to do, and then it will tell you what you want to do with the result of the execution in the return value, and the update function and the other ones are pretty much unparsed,

3.3 summarize

From the above experience, it gives me the impression that some program A provides A content provider (which is essentially CRUD to the database in the program but can restrict it to the data it wants), and then program B wants to access some data in program A, Program B can CRUD through Uri to the extent that program A allows