房间持久性库和内容提供者
Room persistence library and Content provider
最近几天我一直在学习新的Android架构组件。在跟进了一些博客文章、文档和教程之后,我对每个组件都越来越清楚了。但突然我意识到我们的老朋友 Content Provider 是怎么回事。我可能听起来很傻,因为在写这个问题之前我花了很多时间搜索,我是唯一提出这个问题的人吗?我没有得到任何有用的解决方案。不管怎样,如果我想用本地数据库构建一个应用程序,我现在显然会选择新的体系结构组件(实时数据、视图模型、房间),而无需进一步考虑这将非常有助于使应用程序的健壮性提高 10 倍。但是如果我想让其他应用程序访问我的数据库数据,例如 To Widget 如何将 Content Provider 与 Room 集成?
if I want to build up an app with local DB , I will now obviously choose new Architecture Components (live data , view model , room )
我不会在那里使用 "obviously" 这个词。架构组件是一个选项,但不是必需的。
But If I want my DB datas accessible to other app , for instance To Widget How do I integrate Content Provider with Room ?
应用小部件与 ContentProvider
无关。恕我直言,很少 应用程序应该通过 ContentProvider
向第三方公开数据库,没有 应用程序应该使用 ContentProvider
纯粹供内部使用。
话虽如此,您有几个选择:
不要使用 Room,至少对于要通过 ContentProvider
公开的表
将 Room 用于内部用途,然后通过在您的 RoomDatabase
上调用 getOpenHelper()
为 ContentProvider
使用经典的 SQLite 编程技术
在 ContentProvider
中使用 Room,编写您自己的代码以从您检索(对于 query()
)或创建的 Room 实体构建 MatrixCursor
用于其他操作的实体(对于 insert()
、update()
、delete()
等)
顺便说一句,我也有同样的问题。我找到了一个样本 here 来回答我的问题。希望它对你也一样。
简而言之,这是在将从内容提供者的 query()
方法调用的 DAO 对象中。
/**
* Select all cheeses.
*
* @return A {@link Cursor} of all the cheeses in the table.
*/
@Query("SELECT * FROM " + Cheese.TABLE_NAME)
Cursor selectAll();
注意它是如何 returns Cursor
对象的。其他的操作,你可以在示例中更详细地自己看。
我认为这是@CommonsWare 回答中的第 3 项选择。
Room Library 没有对 Content Provider 的任何特殊支持。只能自己写Content Provider,然后用Room查询一个数据库。
如果你想使用 Android 架构组件并且你想使用 SQL 基于站点的内容提供者,请考虑使用 Kripton Persistence Library:它允许 生成来自数据库查询的实时数据,为您生成内容提供程序,等等。至少但不是最后:当你只需要写 where 条件时,为什么你必须写整个 SQL?
澄清一下,我是 Kripton Persistence Library 的作者。我写它是因为我没有找到一个独特的库来满足我在持久性管理方面的所有需求(是的,因为我喜欢编程)。
我用 Kripton 编写了 Google Content Provider Sample 的转换版本。你可以找到它 here.
只是为了简化阅读。使用 Kripton,你只需要定义一个 DAO 接口。内容提供者将由注解生成。在 Kripton 中转换的同一个 DAO 将是:
@BindContentProviderPath(path = "cheese")
@BindDao(Cheese.class)
public interface CheeseDao {
@BindSqlSelect(fields="count(*)")
int count();
@BindContentProviderEntry
@BindSqlInsert
long insert(String name);
@BindContentProviderEntry()
@BindSqlSelect
List<Cheese> selectAll();
@BindContentProviderEntry(path = "${id}")
@BindSqlSelect(where ="id=${id}")
Cheese selectById(long id);
@BindContentProviderEntry(path = "${id}")
@BindSqlDelete(where ="id=${id}")
int deleteById(long id);
@BindContentProviderEntry(path = "${cheese.id}")
@BindSqlUpdate(where="id=${cheese.id}")
int update(Cheese cheese);
}
生成的内容提供程序使用 URI 公开 DAO 的方法。为了清楚起见,我在这里只放了生成的 JavaDoc(总是由 Kripton 生成)。
its wiki, my site and on my articles .
上有关 Kripton 的更多信息
晚 post 但我最近遇到了同样的问题。最终最终将相同的房间数据库实例用于本地和内容提供者目的。
所以应用程序本身像往常一样使用 Room 数据库,Content Provider "wraps" Room 数据库与 "open helper" 如下:
class DatabaseProvider : ContentProvider() {
override fun onCreate(): Boolean {
return true
}
override fun query(uri: Uri?, projection: Array<out String?>?, selection: String?, selectionArgs: Array<out String?>?, sortOrder: String?): Cursor? {
val db = roomDatabase.openHelper.readableDatabase
db.query(...)
}
override fun insert(uri: Uri?, values: ContentValues?): Uri? {
val db = roomDatabase.openHelper.writableDatabase
db.insert(...)
}
override fun update(uri: Uri?, values: ContentValues?, selection: String?, selectionArgs: Array<out String?>?): Int {
val db = roomDatabase.openHelper.writableDatabase
db.update(...)
}
override fun delete(uri: Uri?, selection: String?, selectionArgs: Array<out String?>?): Int {
val db = roomDatabase.openHelper.writableDatabase
db.delete(...)
}
override fun getType(uri: Uri?): String? {
}
}
你最好使用 SupportOpenHelper
public class MyContentProvider extends ContentProvider {
public MyContentProvider() {
}
@Override
public String getType(Uri uri) {
// TODO: Implement this to handle requests for the MIME type of the data
// at the given URI.
throw new UnsupportedOperationException("Not yet implemented");
}
UserDatabase database;
@Override
public boolean onCreate() {
database = Room.databaseBuilder(getContext(), UserDatabase.class, "user.db").allowMainThreadQueries().build();
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
return database.query(SupportSQLiteQueryBuilder.builder("user").selection(selection, selectionArgs).columns(projection).orderBy(sortOrder).create());
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return database.getOpenHelper().getWritableDatabase().update("user", 0, values, selection, selectionArgs);
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return database.getOpenHelper().getWritableDatabase().delete("user", selection, selectionArgs);
}
@Override
public Uri insert(Uri uri, ContentValues values) {
long retId = database.getOpenHelper().getWritableDatabase().insert("user", 0, values);
return ContentUris.withAppendedId(uri, retId);
}
}
最近几天我一直在学习新的Android架构组件。在跟进了一些博客文章、文档和教程之后,我对每个组件都越来越清楚了。但突然我意识到我们的老朋友 Content Provider 是怎么回事。我可能听起来很傻,因为在写这个问题之前我花了很多时间搜索,我是唯一提出这个问题的人吗?我没有得到任何有用的解决方案。不管怎样,如果我想用本地数据库构建一个应用程序,我现在显然会选择新的体系结构组件(实时数据、视图模型、房间),而无需进一步考虑这将非常有助于使应用程序的健壮性提高 10 倍。但是如果我想让其他应用程序访问我的数据库数据,例如 To Widget 如何将 Content Provider 与 Room 集成?
if I want to build up an app with local DB , I will now obviously choose new Architecture Components (live data , view model , room )
我不会在那里使用 "obviously" 这个词。架构组件是一个选项,但不是必需的。
But If I want my DB datas accessible to other app , for instance To Widget How do I integrate Content Provider with Room ?
应用小部件与 ContentProvider
无关。恕我直言,很少 应用程序应该通过 ContentProvider
向第三方公开数据库,没有 应用程序应该使用 ContentProvider
纯粹供内部使用。
话虽如此,您有几个选择:
不要使用 Room,至少对于要通过
ContentProvider
公开的表
将 Room 用于内部用途,然后通过在您的
上调用RoomDatabase
getOpenHelper()
为ContentProvider
使用经典的 SQLite 编程技术在
ContentProvider
中使用 Room,编写您自己的代码以从您检索(对于query()
)或创建的 Room 实体构建MatrixCursor
用于其他操作的实体(对于insert()
、update()
、delete()
等)
顺便说一句,我也有同样的问题。我找到了一个样本 here 来回答我的问题。希望它对你也一样。
简而言之,这是在将从内容提供者的 query()
方法调用的 DAO 对象中。
/**
* Select all cheeses.
*
* @return A {@link Cursor} of all the cheeses in the table.
*/
@Query("SELECT * FROM " + Cheese.TABLE_NAME)
Cursor selectAll();
注意它是如何 returns Cursor
对象的。其他的操作,你可以在示例中更详细地自己看。
我认为这是@CommonsWare 回答中的第 3 项选择。
Room Library 没有对 Content Provider 的任何特殊支持。只能自己写Content Provider,然后用Room查询一个数据库。
如果你想使用 Android 架构组件并且你想使用 SQL 基于站点的内容提供者,请考虑使用 Kripton Persistence Library:它允许 生成来自数据库查询的实时数据,为您生成内容提供程序,等等。至少但不是最后:当你只需要写 where 条件时,为什么你必须写整个 SQL?
澄清一下,我是 Kripton Persistence Library 的作者。我写它是因为我没有找到一个独特的库来满足我在持久性管理方面的所有需求(是的,因为我喜欢编程)。
我用 Kripton 编写了 Google Content Provider Sample 的转换版本。你可以找到它 here.
只是为了简化阅读。使用 Kripton,你只需要定义一个 DAO 接口。内容提供者将由注解生成。在 Kripton 中转换的同一个 DAO 将是:
@BindContentProviderPath(path = "cheese")
@BindDao(Cheese.class)
public interface CheeseDao {
@BindSqlSelect(fields="count(*)")
int count();
@BindContentProviderEntry
@BindSqlInsert
long insert(String name);
@BindContentProviderEntry()
@BindSqlSelect
List<Cheese> selectAll();
@BindContentProviderEntry(path = "${id}")
@BindSqlSelect(where ="id=${id}")
Cheese selectById(long id);
@BindContentProviderEntry(path = "${id}")
@BindSqlDelete(where ="id=${id}")
int deleteById(long id);
@BindContentProviderEntry(path = "${cheese.id}")
@BindSqlUpdate(where="id=${cheese.id}")
int update(Cheese cheese);
}
生成的内容提供程序使用 URI 公开 DAO 的方法。为了清楚起见,我在这里只放了生成的 JavaDoc(总是由 Kripton 生成)。
its wiki, my site and on my articles .
上有关 Kripton 的更多信息晚 post 但我最近遇到了同样的问题。最终最终将相同的房间数据库实例用于本地和内容提供者目的。
所以应用程序本身像往常一样使用 Room 数据库,Content Provider "wraps" Room 数据库与 "open helper" 如下:
class DatabaseProvider : ContentProvider() {
override fun onCreate(): Boolean {
return true
}
override fun query(uri: Uri?, projection: Array<out String?>?, selection: String?, selectionArgs: Array<out String?>?, sortOrder: String?): Cursor? {
val db = roomDatabase.openHelper.readableDatabase
db.query(...)
}
override fun insert(uri: Uri?, values: ContentValues?): Uri? {
val db = roomDatabase.openHelper.writableDatabase
db.insert(...)
}
override fun update(uri: Uri?, values: ContentValues?, selection: String?, selectionArgs: Array<out String?>?): Int {
val db = roomDatabase.openHelper.writableDatabase
db.update(...)
}
override fun delete(uri: Uri?, selection: String?, selectionArgs: Array<out String?>?): Int {
val db = roomDatabase.openHelper.writableDatabase
db.delete(...)
}
override fun getType(uri: Uri?): String? {
}
}
你最好使用 SupportOpenHelper
public class MyContentProvider extends ContentProvider {
public MyContentProvider() {
}
@Override
public String getType(Uri uri) {
// TODO: Implement this to handle requests for the MIME type of the data
// at the given URI.
throw new UnsupportedOperationException("Not yet implemented");
}
UserDatabase database;
@Override
public boolean onCreate() {
database = Room.databaseBuilder(getContext(), UserDatabase.class, "user.db").allowMainThreadQueries().build();
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
return database.query(SupportSQLiteQueryBuilder.builder("user").selection(selection, selectionArgs).columns(projection).orderBy(sortOrder).create());
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return database.getOpenHelper().getWritableDatabase().update("user", 0, values, selection, selectionArgs);
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return database.getOpenHelper().getWritableDatabase().delete("user", selection, selectionArgs);
}
@Override
public Uri insert(Uri uri, ContentValues values) {
long retId = database.getOpenHelper().getWritableDatabase().insert("user", 0, values);
return ContentUris.withAppendedId(uri, retId);
}
}