Reputation: 677
Android Architectural components introduced new concept to store application data locally: Room.
Previously using a ContentProvider
we can expose a database to other applications. How to we do the same with Room?
Upvotes: 5
Views: 5959
Reputation: 5637
To expose a database to other apps you still need ContentProvider
. But, with help of Room
, you may access the data in your database easier in your provider application.
A snippet on ContentProvider that work with Room.
you can do like @lomza answer, but I suggest to use @CommonsWare answer. since it gives the client more flexibility to query the data (if your business say so otherwise, you can go query with @Dao)
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
@Nullable String[] selectionArgs, @Nullable String sortOrder) {
final int code = MATCHER.match(uri);
if (code == CODE_CHEESE_DIR) {
final Context context = getContext();
if (context == null) {
return null;
}
SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
builder.setTables(Cheese.TABLE_NAME);
String query = builder.buildQuery(projection, selection, null, null, sortOrder, null);
final Cursor cursor = SampleDatabase.getInstance(context)
.getOpenHelper()
.getWritableDatabase()
.query(query, selectionArgs);
cursor.setNotificationUri(context.getContentResolver(), uri);
return cursor;
} else {
throw new IllegalArgumentException("Unknown URI: " + uri);
}
}
And let say you have DAO like this.
@Dao
public interface ChesseDAO {
@Query("SELECT * FROM " + Chesse.TABLE_NAME)
LiveData<Cheese> read();
}
So, you in the application you can access data with Room
or ContentProvider
is up to you.
A snippet on Access data via ContentProvider directly.
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
... someview setup...
// test
LoaderManager.getInstance(this).initLoader(1, null, mLoaderCallbacks);
}
private LoaderManager.LoaderCallbacks<Cursor> mLoaderCallbacks = new LoaderManager.LoaderCallbacks<Cursor>() {
String[] projections = new String[] {
Chesse.COLUMN_ID
Cheese.COLUMN_NAME
};
@NonNull
@Override
public Loader<Cursor> onCreateLoader(int id, @Nullable Bundle args) {
return new CursorLoader(
YourActivity.this,
SampleContentProvider.URI_CHEESE,
projections,
null, null, null);
}
@Override
public void onLoadFinished(@NonNull Loader<Cursor> loader, Cursor cursor) {
if (cursor != null && cursor.moveToFirst()) {
String chesseName = cursor.getString(cursor.getColumnIndex(Cheese.COLUMN_NAME));
Toast.makeText(YourActivity.this, chesseName, Toast.LENGTH_LONG).show();
}
}
@Override
public void onLoaderReset(@NonNull Loader<Cursor> loader) {
}
};
A snippet on Access data via Room
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
... someview setup...
// test
SampleDatabase.getInstance(this).chesse().read().observe(this, chesse -> {
Toast.makeText(YourActivity.this, chesse.name, Toast.LENGTH_LONG).show();
});
}
Upvotes: 6
Reputation: 9716
Check the code of Room with Content Providers Sample on GitHub. There isn't much magic around using Room with ContentProvider. For instance, insert() looks like this:
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
switch (MATCHER.match(uri)) {
case CODE_CHEESE_DIR:
final Context context = getContext();
if (context == null) {
return null;
}
final long id = SampleDatabase.getInstance(context).cheese()
.insert(Cheese.fromContentValues(values));
context.getContentResolver().notifyChange(uri, null);
return ContentUris.withAppendedId(uri, id);
case CODE_CHEESE_ITEM:
throw new IllegalArgumentException("Invalid URI, cannot insert with ID: " + uri);
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
}
Upvotes: 2
Reputation: 1006869
How to expose database to other apps when we create database using Room?
The most likely answer: use a ContentProvider
. The biggest difference is that you will use your RoomDatabase
and its getOpenHelper()
method, rather than working with SQLiteOpenHelper
yourself. You would use the same sort of methods for queries, inserts, updates, and deletes as before, though SupportSQLiteDatabase
has a slightly different API than does SQLiteDatabase
.
There is nothing stopping you from having your ContentProvider
use @Dao
methods to get objects back, but then you have to turn around and convert them back into Cursor
objects (in the case of query()
), and this may be tedious.
As with non-Room databases, you are also welcome to expose Room databases through any other IPC mechanism that suits your needs, such as a bound service with an AIDL-defined interface. Room has no direct relationship with those IPC mechanisms, but neither does SQLiteDatabase
.
Upvotes: 7