ContentProvider for IPC inter process communication

Posted by zipdisk on Wed, 11 Dec 2019 04:15:25 +0100

ContentProvider for interprocess communication

First, introduce
1. The underlying implementation is Binder
2. In addition to the onCreate method running on the main thread, the other four methods are called back from the outside and run in the Binder thread pool.
3. To register ContentProvider, an attribute android:authorities = "XXXXX" is required to uniquely identify ContentProvider, through which external applications can access it

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.contentprovider">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <application
      	...
        <provider
            android:name=".views.MyContentProvider"
            android:authorities="com.example.contentprovider.views.provider"
            android:enabled="true"
            android:exported="true"
            android:process=":provider" />
    </application>
</manifest>

Specify that the Uri to access ContentProvider is authorities + database name

public static final String DB_TABLE = "contacts";
public static final String AUTHORITIES = "com.example.contentprovider.views.provider";
public static final Uri CONTACTS_URI = Uri.parse("content://" + AUTHORITIES + "/" + DB_TABLE);

II. Create ContentProvider
1. Create a help class to create and update the database

public class DBHelper extends SQLiteOpenHelper {

    private static final String DB_NAME = "contact.db";
    private static final String DB_TABLE = "contacts";
    private static final int DB_VERSION = 1;
    public DBHelper(Context context) {
        super(context, DB_NAME,null, DB_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        sqLiteDatabase.execSQL("create table contacts(" +
                "id integer primary key autoincrement," +
                "name text," +
                "phone text," +
                "email text," +
                "address text)");
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
        if (newVersion > oldVersion) {
            sqLiteDatabase.execSQL("DROP TABLE IF EXISTS tb_words");
            onCreate(sqLiteDatabase);
        }
    }
}

2. Create a subclass of ContentProvider and override its 6 methods
(I) UriMatcher class is mainly used to match Uri. The use method is as follows
Step 1, initialize:
UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
Step 2 register the required Uri:
mUriMatcher.addURI(AUTHORITIES, DB_TABLE, URI_CODE_ONE);
mUriMatcher.addURI(AUTHORITIES, DB_TABLE + "/#", URI_CODE_TWO);
Part 3: matching the registered Uri: mUriMatcher.match(uri) returns the registration ID
switch (mUriMatcher.match(uri)) {
case URI_CODE_ONE:
cursor = db.query(DB_TABLE, projection, selection, selectionArgs,null,null,null);
break;
case URI_CODE_TWO:
String id = uri.getPathSegments().get(1);
cursor = db.query(DB_TABLE, projection, ContactsColumns.CONTACTS_ID +
"= ?",
new String[]{id + (!TextUtils.isEmpty(selection) ? "AND" + selection : "")},
null, null, null);
break;

(II) ContentUris class is used to get the ID part after the Uri path
1. Add ID to the path: withappendedid (URI, ID)
public static final Uri CONTACTS_URI = Uri.parse("content://" + AUTHORITIES + "/" + DB_TABLE);
Add ID to the Uri through the withAppendedId method
Uri resultUri = ContentUris.withAppendedId(uri, 10);
Finally, the resultUri is: content://com.example.content provider.views.provider/contacts/10
2. Get ID from path: parseid (URI)
Uri uri = Uri.parse("content://com.example.contentprovider.views.provider/contacts/10")
long resultId = ContentUris.parseId(uri);
The result is 10
You can also use String id = uri.getPathSegments().get(1); get ID
ContentProvider Code:

public class MyContentProvider extends ContentProvider {

    private static UriMatcher mUriMatcher;
    public static final String DB_TABLE = "contacts";
    public static final String AUTHORITIES = "com.example.contentprovider.views.provider";
    public static final Uri CONTACTS_URI = Uri.parse("content://" + AUTHORITIES + "/" + DB_TABLE);
    public static final int URI_CODE_ONE = 1;
    public static final int URI_CODE_TWO = 2;

    private DBHelper mDBHelper;
    private Context mContext;
    private SQLiteDatabase db;
	//The program executes the static block first, and the UriMatcher is specially used to add the Uri to be matched for the ContentProvider
    static {
        mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        mUriMatcher.addURI(AUTHORITIES, DB_TABLE, URI_CODE_ONE);
        mUriMatcher.addURI(AUTHORITIES, DB_TABLE + "/#", URI_CODE_TWO);
    }

    @Override
    public boolean onCreate() {
        mContext = getContext();
        mDBHelper = new DBHelper(mContext);
        return true;
    }

    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
                        @Nullable String[] selectionArgs, @Nullable String sortOrder) {
            Cursor cursor;
            //Instantiate database
            db = mDBHelper.getReadableDatabase();
            //Determine whether to access the Uri according to the Uri queried by the foreground
            switch (mUriMatcher.match(uri)) {
                case URI_CODE_ONE:
                    cursor = db.query(DB_TABLE, projection, selection, selectionArgs,null,null,null);
                    break;
                case URI_CODE_TWO:
                    String id = uri.getPathSegments().get(1);
                    cursor = db.query(DB_TABLE, projection, ContactsColumns.CONTACTS_ID +
                                    "= ?",
                            new String[]{id + (!TextUtils.isEmpty(selection) ? "AND" + selection : "")},
                            null, null, null);
                    break;
                default:
                    throw new IllegalArgumentException("unknown uri :" + uri);
            }
            return cursor;
    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        switch (mUriMatcher.match(uri)) {
            case URI_CODE_ONE:
               return "vnd.android.cursor.dir/vnd.contacts";
            case URI_CODE_TWO:
                return "vnd.android.cursor.item/vnd.contacts";
            default:throw new IllegalArgumentException("unknown uri" + uri);
        }
    }

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
        db = mDBHelper.getWritableDatabase();
        long newId;
        if (mUriMatcher.match(uri) != URI_CODE_ONE) {
            throw new IllegalArgumentException("unknown uri" + uri);
        }
        Uri newUri = null;
        newId = db.insert(DB_TABLE, null, contentValues);
        if (newId > 0) {
            newUri = ContentUris.withAppendedId(CONTACTS_URI, newId);
            try {
                getContext().getContentResolver().notifyChange(newUri, null);
            } catch (NullPointerException e) {
                e.printStackTrace();
            }
        }
        return newUri;
    }

    @Override
    public int delete(@NonNull Uri uri, @Nullable String whereCause, @Nullable String[] whereArgs) {
        db = mDBHelper.getWritableDatabase();
        int count;
        switch (mUriMatcher.match(uri)) {
            case URI_CODE_ONE:
                count = db.delete(DB_TABLE,whereCause,whereArgs);
                break;
            case URI_CODE_TWO:
                String id = uri.getPathSegments().get(1);
                count = db.delete(DB_TABLE,ContactsColumns.CONTACTS_ID
                        +"=" + "?",new String[]{id + (!TextUtils.isEmpty(whereCause) ?
                        "AND" + whereCause : "")});
                break;
            default:throw new IllegalArgumentException("unknown uri" + uri);
        }
        getContext().getContentResolver().notifyChange(uri,null);
        return count;
    }

    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues contentValues,
                      @Nullable String whereCouse, @Nullable String[] whereArgs) {
        db = mDBHelper.getWritableDatabase();
        int count;
        switch (mUriMatcher.match(uri)) {
            case URI_CODE_ONE:
                count = db.update(DB_TABLE,contentValues,whereCouse,whereArgs);
                break;
            case URI_CODE_TWO:
                long id = ContentUris.parseId(uri);
                count = db.update(DB_TABLE,contentValues,ContactsColumns.CONTACTS_ID
                        +"= ?",new String[]{id + (!TextUtils.isEmpty(whereCouse) ?
                        "AND" + whereCouse : "")});
                break;
            default:throw new IllegalArgumentException("unknown uri" + uri);
        }
        getContext().getContentResolver().notifyChange(uri,null);
        return count;
    }
}

Topics: Mobile Android Database Attribute xml