-
Basic definition and characteristics of ContentProvider -
How to implement a customized ContentProvider -
The functions provided by the ContentProvider and the permission control of external applications -
Some common usage scenarios of ContentProvider -
Best Practices and Precautions for Using ContentProvider
-
In actual development, we often encounter scenarios where multiple applications need to share data, such as the address book application needs to be accessed by other applications. -
If data is shared directly through files or databases, some problems will arise, such as difficult control of data access permissions, inconsistent data formats, etc. -
ContentProvider provides a standardized data sharing mechanism, which can easily share data between different applications.
-
Data security is a top priority in mobile application development. If the database or file is directly exposed, it is easy to cause the risk of data leakage and tampering. -
The ContentProvider can finely control data access permissions, and developers can set read and write permissions according to requirements to fully protect data security. -
When other applications request access to data, the ContentProvider will perform permission verification to prevent unauthorized access.
-
Different applications may use different data storage methods, such as SQLite, file system, etc. This will bring some complexity to data access. -
The ContentProvider provides a standardized CRUD interface for data access. Developers do not need to care about the underlying data storage details, but can focus on the implementation of business logic. -
This unified interface not only simplifies the development, but also greatly improves the maintainability of the code.
-
Android applications are based on process isolation, and data between different applications is isolated. -
The ContentProvider implements inter process communication based on Binder mechanism, making data interaction between applications more smooth. -
Through the ContentProvider, developers can realize data sharing between applications without caring about the underlying details of interprocess communication.
-
Step 1: Inherit ContentProvider Class, and implement 6 abstract methods. -
Step 2: AndroidManifest.xml Declare the ContentProvider and its Authority in. -
Step 3: Use in other applications ContentResolver Access the data provided by the ContentProvider.
public class MyContentProvider extends ContentProvider {
//Declare the Authority, which is the unique identifier of the ContentProvider
public static final String AUTHORITY = "com.example.mycontentprovider" ;
//Declare Uri constants for building Uri
public static final Uri CONTENT_URI = Uri . parse ( "content://" + AUTHORITY + "/users" ) ;
//Declare table name constants
private static final String TABLE_NAME = "users" ;
//Declare database related objects
private SQLiteDatabase db ;
private MySQLiteOpenHelper dbHelper ;
@Override
public boolean onCreate ( ) {
//Initialize database dbHelper = new MySQLiteOpenHelper ( getContext ( ) ) ; db = dbHelper . getWritableDatabase ( ) ;
return true ;
}
@Override
public Cursor query ( Uri uri, String [ ] projection, String selection, String [ ] selectionArgs, String sortOrder ) {
//Execute query operation
return db . query ( TABLE_NAME , projection, selection, selectionArgs, null , null , sortOrder ) ;
}
@Override
public Uri insert ( Uri uri, ContentValues values ) {
//Perform Insert Operation
long id = db . insert ( TABLE_NAME , null , values ) ;
return ContentUris . withAppendedId ( CONTENT_URI , id ) ;
}
@Override
public int update ( Uri uri, ContentValues values, String selection, String [ ] selectionArgs ) {
//Perform update operation
return db . update ( TABLE_NAME , values, selection, selectionArgs ) ;
}
@Override
public int delete ( Uri uri, String selection, String [ ] selectionArgs ) {
//Perform the delete operation
return db . delete ( TABLE_NAME , selection, selectionArgs ) ;
}
@Override
public String getType ( Uri uri ) {
//Return the MIME type, taking "vnd. android. cursor. dir/vnd. com. example. mycontentprovider. users" as an example
return "vnd.android.cursor.dir/vnd." + AUTHORITY + "." + TABLE_NAME ;
}
}
< provider
android: name = " .MyContentProvider "
android: authorities = " com.example.mycontentprovider "
android: exported = " true " />
//Build Uri
Uri uri = MyContentProvider . CONTENT_URI ;
//Execute query operation
Cursor cursor = getContentResolver ( ) . query ( uri, null , null , null , null ) ;
//Traversal query results
while ( cursor . moveToNext ( ) ) {
int id = cursor . getInt ( cursor . getColumnIndex ( "id" ) ) ;
String name = cursor . getString ( cursor . getColumnIndex ( "name" ) ) ;
//Processing data
Log . d ( "MyApp" , "id: " + id + ", name: " + name ) ;
}
-
Android system comes with some ContentProviders, such as Contacts, Media, Calendar, etc. Through these ContentProviders, developers can access system level data, such as address books, pictures, calendars, etc. -
These system level ContentProviders provide standardized interfaces, so developers can easily obtain and operate system data without caring about the underlying implementation.
-
In actual development, there is often a need to share data between multiple applications. For example, social applications need to obtain user contact information. -
Developers can customize the ContentProvider to expose the data inside the application to other applications. By setting appropriate read/write permissions, data security can be ensured and data sharing between applications can be realized.
-
In addition to realizing data sharing between applications, the ContentProvider can also be used for data persistence within applications. -
For example, developers can combine Room or SQLite to use the ContentProvider as the external interface of the application's internal database to provide standardized data access methods for the upper layer's ViewModel and UI layer.
-
In recent years, with the wide application of Android Jetpack, ViewModel and LiveData have become the mainstream solutions to realize data-driven UI. -
In this architecture, the ContentProvider can be used as a data source to provide a standardized data access interface for ViewModel, which is responsible for observing data changes and refreshing the UI in real time. This design can greatly improve the maintainability and testability of the code.
-
The ContentProvider can be used not only to share structured data, but also to share file data. -
Developers can customize the ContentProvider to expose the file resources inside the application to other applications, such as sharing files or pictures across applications.
-
Authority is the unique identifier of the ContentProvider, which should be unique and readable. It usually takes the form of anti domain name, such as "com. example. myprovider". -
Uri is an identifier used to access ContentProvider data. It should follow certain naming conventions, such as“ content://com.example.myprovider/users "。 -
Rational design of Authority and Uri can improve the readability and maintainability of code, and is also conducive to permission control.
public class MyContentProvider extends ContentProvider {
public static final String AUTHORITY = "com.example.mycontentprovider" ;
public static final Uri CONTENT_URI = Uri . parse ( "content://" + AUTHORITY + "/users" ) ;
@Override
public Uri insert ( Uri uri, ContentValues values ) {
//Perform Insert Operation
long id = db . insert ( TABLE_NAME , null , values ) ;
return ContentUris . withAppendedId ( CONTENT_URI , id ) ;
}
@Override
public Cursor query ( Uri uri, String [ ] projection, String selection, String [ ] selectionArgs, String sortOrder ) {
//Determine whether the operation object is a single record or a collection of records
if ( ContentUris . parseId ( uri ) != - one ) {
//Query a single record selection = BaseColumns . _ID + " = ?" ; selectionArgs = new String [ ] { String . valueOf ( ContentUris . parseId ( uri ) ) } ;
}
//Execute query operation
return db . query ( TABLE_NAME , projection, selection, selectionArgs, null , null , sortOrder ) ;
}
}
-
The ContentProvider provides a flexible permission control mechanism. Developers can set different permissions for different operations (add, delete, modify, query). -
Reasonable control of read and write permissions can improve the security of data and prevent unauthorized access. At the same time, it can flexibly control the access range of other applications to data according to business requirements.
public class MyContentProvider extends ContentProvider { public static final String AUTHORITY = "com.example.mycontentprovider"; private static final String TABLE_NAME = "users"; @Override public boolean onCreate() { //Initialize database // ... return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { //Check access if (getContext().checkCallingOrSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Permission denied to access the data"); } //Execute query operation return db.query(TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder); } @Override public Uri insert(Uri uri, ContentValues values) { //Check access if (getContext().checkCallingOrSelfPermission(Manifest.permission.WRITE_CONTACTS) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Permission denied to access the data"); } //Perform Insert Operation long id = db.insert(TABLE_NAME, null, values); return ContentUris.withAppendedId(CONTENT_URI, id); } //The implementation of other methods is similar }
-
MIME type describes the data type returned by the ContentProvider. You should set a reasonable MIME type according to the actual situation. -
The correct MIME type can help other applications correctly parse and process the data provided by the ContentProvider.
@Override
public String getType ( Uri uri ) {
//Return the corresponding MIME type according to Uri
if ( uri . equals ( CONTENT_URI ) ) {
return "vnd.android.cursor.dir/vnd." + AUTHORITY + "." + TABLE_NAME ;
} else if ( ContentUris . parseId ( uri ) != - one ) {
return "vnd.android.cursor.item/vnd." + AUTHORITY + "." + TABLE_NAME ;
}
throw new IllegalArgumentException ( "Unknown URI " + uri ) ;
}
-
Pay attention to thread safety to avoid data contention problems during multithreaded access -
When implementing various methods of the ContentProvider, you should reasonably handle possible exceptions, such as database operation exceptions, permission verification failures, etc. -
Reasonable exception handling can improve the robustness of applications, and is also conducive to locating and solving problems.
private final ReentrantLock lock = new ReentrantLock ( ) ;
@Override
public Cursor query ( Uri uri, String [ ] projection, String selection, String [ ] selectionArgs, String sortOrder ) { lock . lock ( ) ;
try {
//Execute query operation
return db . query ( TABLE_NAME , projection, selection, selectionArgs, null , null , sortOrder ) ;
} finally { lock . unlock ( ) ;
}
}
@Override
public Uri insert ( Uri uri, ContentValues values ) { lock . lock ( ) ;
try {
//Perform Insert Operation
long id = db . insert ( TABLE_NAME , null , values ) ;
return ContentUris . withAppendedId ( CONTENT_URI , id ) ;
} finally { lock . unlock ( ) ;
}
}