1. Application scenarios

  1. ContentProvider provides a unified interface for storing and reading data
  2. Using ContentProviders, applications can share data
  3. Much of android’s built-in data is in the form of ContentProviders for developers to call (video, audio, images, contacts, etc.)

2. Related concepts

When an application inherits the ContentProvider class and overwrites the methods used to provide and store data, it can share its data with other applications. Data can be shared externally by other methods, but the data access mode varies with the data storage mode. For example, if data is shared externally by file, read/write data is required. Using SharedPreferences to share data, you need to use the SharedPreferences API to read and write data. The advantage of using ContentProvider to share data is that data access is unified.

2) the Uri class introduction Uri Uri = Uri. Parse (” content: / / com. Changcheng. Provider. Contactprovider/contact “) in the content The query strings used in providers are different from standard SQL queries. Many operations such as Select, add, delete, modify are performed using a special URI that consists of three parts: “Content ://”, which represents the path to the data, and an optional ID that identifies the data. Here are some sample URIs:

Content: / / media/internal/images this URI will return the equipment of all images stored on the content: / / contacts/people/this URI will return all the contact information on the equipment The content: / / contacts/people / 45 this URI returns a single result (ID in the contact information for the contact record 45)

Although this query string format is common, it can seem a little confusing. For this purpose, Android provides a series of helper classes (in the Android.provider package) that contain a lot of query strings in the form of class variables, which is a little easier to understand. Therefore, As the content above: / / contacts/people / 45 this URI can be written as the following form:

Uri person = ContentUris.withAppendedId(People.CONTENT_URI, 45);

Then perform the data query:

Cursor cur = managedQuery(person, null, null, null);

This query returns a cursor containing all the data fields, and we can retrieve all the data by iterating over the cursor:

package com.wissen.testApp; public class ContentProviderDemo extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); displayRecords(); } private void displayRecords() {String columns[] = new String[] {people.name, people.number};} private void displayRecords() {String columns[] = new String[] {people.name, people.number}; Uri mContacts = People.CONTENT_URI; Cursor cur = managedQuery(mContacts, columns, WHERE column null, // WHERE the argument is null // order-by); if (cur.moveToFirst()) { String name = null; String phoneNo = null; Name = cur.getString(cur.getColumnIndex(people.name)); phoneNo = cur.getString(cur.getColumnIndex(People.NUMBER)); Toast.maketext (this, name + "" + phoneNo, toast.length_long).show(); } while (cur.moveToNext()); }}}Copy the code

The above example demonstrates how a table of contact information can be used to read the specified data columns name and number in turn.

To modify the record, we can use the contentresolver.update () method to modify the data.

private void updateRecord(int recNo, String name) {
    Uri uri = ContentUris.withAppendedId(People.CONTENT_URI, recNo);
    ContentValues values = new ContentValues();
    values.put(People.NAME, name);
    getContentResolver().update(uri, values, null, null);
}
Copy the code

Now you can call the above method to update the specified record:

UpdateRecord (10, “XYZ”); // Change the name value of the 10 record to “XYZ”

Add a record: To add a record, we call the contentresolver.insert () method, which takes the target URI of the record to be added and a Map object containing the value of the new record. The return value of the call is the URI of the new record, including the record number. In the example above we used Content providers based on the contact book standard. Now let’s go ahead and create an insertRecord() method to add data to the contact book:

private void insertRecords(String name, String phoneNo) { ContentValues values = new ContentValues(); values.put(People.NAME, name); Uri uri = getContentResolver().insert(People.CONTENT_URI, values); The d (" ANDROID ", uri. The toString ()); Uri numberUri = Uri.withAppendedPath(uri, People.Phones.CONTENT_DIRECTORY); values.clear(); values.put(Contacts.Phones.TYPE, People.Phones.TYPE_MOBILE); values.put(People.NUMBER, phoneNo); getContentResolver().insert(numberUri, values); }Copy the code

We can then call insertRecords(name, phoneNo) to add the contact name and phone number to the contact book.

Delete records: the getContextResolver Content Provider. The delete () method can be used to delete records, the following records to delete all the contact information of the equipment:

private void deleteRecords() {
    Uri uri = People.CONTENT_URI;
    getContentResolver().delete(uri, null, null);
}
Copy the code

You can also specify WHERE conditions to delete specific records:

GetContentResolver ().delete(uri, “NAME=” + “‘ XYZ XYZ ‘”, null);

This will delete the record whose name is’ XYZ XYZ ‘.

  1. Create a ContentProvider

To create our own Content Provider, we need to follow these steps: A. Create a class that inherits the ContentProvider parent class

B. Define a class variable named CONTENT_URI that is a public static final Uri. You must specify a unique string value for it. Public static final Uri CONTENT_URI = Uri. Parse (” content: / / com. Google. Android. MyContentProvider “);

C. Define the column names you want to return to the client. If you are using an Android database, you must define a column called _ID to indicate the uniqueness of each record.

D. Create your data storage system. Most Content providers use the Android file system or SQLite database to hold data, but you can store it any way you want.

E. If you want to store byte data, such as bitmap files, the data column is actually a URI string representing the actual saved file, which is used to read the corresponding file data. Content Providers that handle this type of data need to implement a field called _data, which lists the exact path of the file on the Android file system. This field is used not only by the client, but also by the ContentResolver. The client can invoke the ContentResolver. OpenOutputStream () method to handle the URI points to document resources; The ContentResolver itself has higher permissions than the client, so it can access the data file directly.

F. Declare a public static String variable that specifies the column to be returned from the cursor.

G. Query returns an object of type Cursor. All write methods such as INSERT (), update(), and delete() will be listened on. We can notify listeners about data updates by using the ContentResover().notifychange () method.

H. Use the tag in AndroidMenifest. XML to set the Content Provider.

I. If you are dealing with a relatively new type of data, you must first define a new MIME type to be returned by contentProvider.geType (URL). MIME types come in two forms: one for a specified single record, and one for multiple records. Here is a common format:

VND. Android. Cursor. The item/VND. Yourcompanyname. Contenttype (a single record of the MIME type), for instance, A request to the URI of the train information such as the content: / / com. Example. Transportationprovider/trains / 122 Might return typevnd. Android. The cursor. The item/VND example. The rail such a MIME type.

VND. Android. Cursor. Dir/VND. Yourcompanyname. Contenttype (multiple records the MIME type), for instance, A URI request all train information such as the content: / / com. Example. Transportationprovider/trains may return VND. Android. The cursor. Dir/VND. Example. The rail such a MIME Type.

The following code creates a Content Provider that simply stores the user name and displays all the user names (using the SQLLite database to store this data) :

Public class MyUsers {public static final String AUTHORITY = "com. Wissen. MyContentProvider"; Public static final class User implements BaseColumns {public static final Uri CONTENT_URI = Uri. Parse (" content: / / com. Wissen. MyContentProvider "); Public static final String USER_NAME = "USER_NAME"; }}Copy the code

The above class defines the CONTENT_URI of the Content Provider, along with the data column. Now we’ll define the actual Content Provider class based on the above class:

public class MyContentProvider extends ContentProvider { private SQLiteDatabase sqlDB; private DatabaseHelper dbHelper; Private static final String DATABASE_NAME = "users.db"; private static final int DATABASE_VERSION= 1; Private static final String TABLE_NAME= "User"; Private static Final String TAG = "MyContentProvider"; private static class DatabaseHelper extends SQLiteOpenHelper { DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @override public void onCreate(SQLiteDatabase db) {// Create a table for storing data. ExecSQL (" Create table "+ TABLE_NAME +" (_id) INTEGER PRIMARY KEY AUTOINCREMENT, USER_NAME TEXT); ); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, Db. execSQL(" DROP TABLE IF EXISTS "+ TABLE_NAME); onCreate(db); } } @Override public int delete(Uri uri, String s, String[] as) { return 0; } @Override public String getType(Uri uri) { return null; } @Override public Uri insert(Uri uri, ContentValues contentvalues) { sqlDB = dbHelper.getWritableDatabase(); Long rowId = sqldb. insert(TABLE_NAME, "", contentvalues); if (rowId > 0) { Uri rowUri = ContentUris.appendId(MyUsers.User.CONTENT_URI.buildUpon(), rowId).build(); getContext().getContentResolver().notifyChange(rowUri, null); return rowUri; } throw new SQLException(" Failed to insert row into "+ URI); } @Override public boolean onCreate() { dbHelper = new DatabaseHelper(getContext()); return (dbHelper == null) ? false : true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); SQLiteDatabase db = dbHelper.getReadableDatabase(); qb.setTables(TABLE_NAME); Cursor c = qb.query(db, projection, selection, null, null, null, sortOrder); c.setNotificationUri(getContext().getContentResolver(), uri); return c; } @Override public int update(Uri uri, ContentValues contentvalues, String s, String[] as) { return 0; }}Copy the code

A ContentProvider named MyContentProvider has been created to add and read records from the Sqlite database.

The entry to the Content Provider needs to be configured in androidmanifest.xml:

After that, let’s use the defined Content Provider:

1) Add access to the ContentProvider for your application.

2) Get the ContentResolver object using the getContentResolver() method.

3) Call the ContentResolver class’s query() method to query the data, which returns a Cursor object.

4) Analyze the Cursor object and obtain the required data.

5) Close the Cursor object by calling the close() method of the Cursor class.

public class MyContentDemo extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); InsertRecord (" MyUser "); displayRecords(); } private void insertRecord(String userName) { ContentValues values = new ContentValues(); values.put(MyUsers.User.USER_NAME, userName); getContentResolver().insert(MyUsers.User.CONTENT_URI, values); } private void displayRecords() { String columns[] = new String[] { MyUsers.User._ID, MyUsers.User.USER_NAME }; Uri myUri = MyUsers.User.CONTENT_URI; Cursor cur = managedQuery(myUri, columns,null, null, null ); if (cur.moveToFirst()) { String id = null; String userName = null; do { id = cur.getString(cur.getColumnIndex(MyUsers.User._ID)); userName = cur.getString(cur.getColumnIndex(MyUsers.User.USER_NAME)); Toast.maketext (this, id + "" + userName, toast.length_long).show(); toast.maketext (this, id +" "+ userName, toast.length_long). } while (cur.moveToNext()); }}}Copy the code