所以我在过去几个月一直在使用IOS开发,并广泛使用了Core Data和NSFetchedResultsController。
Core Data + NSFetchedResultsController:自动检测对数据库的更改并相应地更新表元素。
现在我已经切换到Android开发,我一直在寻找相同的上述内容。我看过各种不同的课程,有点困惑。
我认为值得一提的是我使用的是greendao,我正在使用它生成的ContentProvider。
这是我有点不确定的地方。这是我的假设。
swap()
内的onLoadFinished()
,从而导致表的更新。 记住上面的内容,我创建了一个ContentProvider并实现了LoaderManager,但是当我持久化一个新对象(使用greenDao)时,函数onLoadFinished()
没有被调用 - 这让我开始质疑我是不是正确理解过程。这是一段代码,用于显示到目前为止我通常编码的内容。
public class MissionPageFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
// Various initialization methods
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getLoaderManager().initLoader(0, savedInstanceState, this);
}
@Override
public Loader onCreateLoader(int id, Bundle args) {
ContentProvider.daoSession = Main.daoSession;
Uri uri = ContentProvider.CONTENT_URI;
// Other initializations
CursorLoader cursorLoader = new CursorLoader(getContext(), uri, projections, null, null, null);
return cursorLoader;
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
System.out.println("Should be called when a new item is persisted... but not called =(");
}
// Other methods
}
如果有人能够确认我是否正确地考虑了这个过程和/或了解可能出现的问题,我会非常感激。
以下是greenDao生成的ContentProvider子类中query()
函数的片段。
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
int uriType = sURIMatcher.match(uri);
switch (uriType) {
case MISSION_DIR:
queryBuilder.setTables(TABLENAME);
break;
case MISSION_ID:
queryBuilder.setTables(TABLENAME);
queryBuilder.appendWhere(PK + "="
+ uri.getLastPathSegment());
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
SQLiteDatabase db = getDatabase();
Cursor cursor = queryBuilder.query(db, projection, selection,
selectionArgs, null, null, sortOrder);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
我只是想分享一下如何使用GreenDao实现上述所有类。让我知道是否有更好的方法来做到这一点,但我觉得这已经足够了。
通过将以下代码片段添加到GreenDaoGenerator类来生成ContentProvider子类
Entity entity = new Entity();
entity.addContentProvider();
检查是否正确调用了ContentProvider子类方法。将javadoc部件添加到AndroidManifest.xml。对我来说,我还必须将生成的ContentProvider类BASE_PATH
变量更改为另一个变量,如下所示。
public static final String BASE_PATH = "MYTABLENAME";
将LoaderManager,Loader添加到Activity / Fragment类,就像我上面写的那样。您还必须在使用ContentProvider之前设置daoSession
对象。我已将下面的代码段移动到另一个初始化程序类,以便其他Activity / Fragment类也可以使用它。
ContentProvider.daoSession = Main.daoSession;
我正在使用RecyclerView,所以我将https://gist.github.com/skyfishjy/443b7448f59be978bc59提供的CursorRecyclerViewAdapter类子类化了一些自定义。如果使用ListView,则应该能够使用简单的CursorAdapter。由于Loader
正在侦听更新,因此Adapter
无需侦听更新。
现在ContentProvider子类能够根据此行更新视图
getContext().getContentResolver().notifyChange(uri, null);
由GreenDao自动生成。这意味着您可以将ContentProvider用于所有CRUD操作,并且视图将相应地自动更新。这似乎打败了使用ORM的目的。因此,我现在进行正常的GreenDao操作,并在每次插入,删除,更新后手动调用notifyChange
。
GreenDaoObj obj = new GreenDaoObj();
obj.insert();
getContext.getContentResolver().notifyChange(MyContentProvider.CONTENT_URI, null);
我认为没有比这更好的方法,因为我真的不想触摸GreenDao为Model和Dao对象生成的代码。我想可以添加自定义CRUD函数来嵌套生成的CRUD方法,但这应该是微不足道的。
我一直在环顾四周,并没有一个记录良好的方法来使用GreenDao和Loader / LoaderManager,所以我想我会在这里组织这个。希望这有助于任何计划实施此项目的人。
答案 0 :(得分:3)
只有一些事情你没有完全正确。
ContentProvider
是提供数据访问权限的Android组件。该数据可以存储在关系数据库,平面文件,远程服务器等中。提供者具有类似REST的通用接口,并且可以作为您拥有的不同数据存储选项的抽象层。 ContentProvider
也可以从外部应用程序访问(如果配置正确),这使它们成为在应用程序之间共享数据的默认方式。访问它们并不需要LoaderManager
。应通过ContentResolver
。LoaderManager
负责Loader
生命周期并与Activity
和Fragment
生命周期协调。Loader
提供了一种生命周期感知方式,可将数据加载到活动或片段中。 CursorLoader
是一个特殊的实现,带有一系列功能 - 它使用工作线程来保持UI线程的加载,使用ContentResolver
抽象来访问ContentProvider
和还会设置ContentObserver
。 ContentObserver
将侦听查询URL的更新,并在需要时重新加载数据。为了让ContentObserver
通知正常工作,您必须确保有一些事情到位。首先,您的ContentProvider
应该将更改传播给观察者。这是使用getContext().getContentResolver().notifyChange(url, observer)
完成的。然后,如果您有CursorLoader
对通知的网址执行了查询,则会自动重新加载。