Realm.io 和异步查询
Realm.io and asynchronous queries
我们开始在 android 应用项目中使用 Realm.io。但是我们不喜欢 Realm.io API 的一点是没有任何异步方式来查询数据库。在老项目中我们使用的是DbQuery和Sqlite,所以我们习惯于在线程或AsyncTask
的内部进行数据库查询。但令人不安的是,在所有示例中,查询都是在 UiThread
中进行的。这对应用程序性能来说不是一件坏事吗?我们尝试在线程或 AsyncTasks 中进行查询,但是当我们在 UiThread 中访问我们的模型对象时出现错误,说我们无法在不是查询它们的线程中访问 RealObjects。这是我们的示例代码:
service.getDatabaseHelper()
.with(getActivity()) //Context that I use to instance the Realm instance
.onFinishQuery( new DatabaseHelper.IQueryGetCallback<UserRealm>() {
@Override
public void onGetResult(UserRealm[] results) {
for(UserRealm aUser : results){
//Here is where it crashes
Log.d("Log","Username -> "+aUser.getName());
}
}
})
.getUsersFromDb();
//.......
//In our "DAO" class
public void getUsersFromDb(){
new GetQueryTask() {
@Override
public UserRealm[] onQueryReadyToBeExecuted(Realm realmInstance) {
RealmQuery<UserRealm> query = realmInstance.where(UserRealm.class);
RealmResults<UserRealm> result = query.findAll();
// TODO hacer que devuelva un array
ArrayList<UserRealm> users = new ArrayList<UserRealm>();
for (UserRealm u : result) {
//Here we can read the RealObject's fine
users.add(u);
}
return users.toArray(new UserRealm[users.size()]);
}
}.execute();
}
//Our abstract task that wraps all the instantiation-transaction behaviour
public abstract class GetQueryTask<T extends RealmObject> extends AsyncTask<Void, Void, T[]> {
@Override
protected T[] doInBackground(Void... params) {
//We tried to instantiate this class in several places, here
//Send it as parameter through the AsyncTask
//context is set in the with(Context ctx) method.
Realm realm = Realm.getInstance(context);
return onQueryReadyToBeExecuted(realm);
}
public abstract T[] onQueryReadyToBeExecuted(Realm realmInstance);
@Override
protected void onPostExecute(T[] result) {
mCallback.onExecute(result);
}
}
我们主要关心的不是此代码的 "bug",而是是否可以像 Realm.io 开发人员在其示例中所做的那样在 UiThread 中执行查询。如果是这样的话,所有这些异步执行查询的代码将不再是必需的。
这里是 Realm 的基督徒。
您是对的,查询当前需要在使用它们的线程上 运行,这可能会对 UI 线程性能产生负面影响。然而,我们敏锐地意识到这一点,并积极致力于使跨线程移动查询结果成为可能。
也就是说,即使对于合理的大量数据,领域 中的查询也 非常快,并且由于它只加载您实际使用的数据,即使 [=21] =] 在 UI 线程上。
我鼓励您尝试使用您认为合理的任何数据大小并测试您的性能(最好在旧设备上 :))。也可以做一些技巧,比如向键添加索引,在后台线程上进行繁重的查询,将键发送到 UI 线程并在那里重新查询它们。这是一个创可贴,但在某些情况下会起作用 - 遗憾的是不适用于列表。
realm 0.84 现在支持异步查询。
您可以通过将 'io.realm:realm-android:0.84.0-SNAPSHOT' 添加到您的 build.gradle 来尝试一下。有几个新方法
- findAllAsync
- findAllSortedAsync
- findFirstAsync
您必须将 addChangeListener(RealmChangeListener) 添加到 RealmResult 以在查询完成时收到通知。
我们开始在 android 应用项目中使用 Realm.io。但是我们不喜欢 Realm.io API 的一点是没有任何异步方式来查询数据库。在老项目中我们使用的是DbQuery和Sqlite,所以我们习惯于在线程或AsyncTask
的内部进行数据库查询。但令人不安的是,在所有示例中,查询都是在 UiThread
中进行的。这对应用程序性能来说不是一件坏事吗?我们尝试在线程或 AsyncTasks 中进行查询,但是当我们在 UiThread 中访问我们的模型对象时出现错误,说我们无法在不是查询它们的线程中访问 RealObjects。这是我们的示例代码:
service.getDatabaseHelper()
.with(getActivity()) //Context that I use to instance the Realm instance
.onFinishQuery( new DatabaseHelper.IQueryGetCallback<UserRealm>() {
@Override
public void onGetResult(UserRealm[] results) {
for(UserRealm aUser : results){
//Here is where it crashes
Log.d("Log","Username -> "+aUser.getName());
}
}
})
.getUsersFromDb();
//.......
//In our "DAO" class
public void getUsersFromDb(){
new GetQueryTask() {
@Override
public UserRealm[] onQueryReadyToBeExecuted(Realm realmInstance) {
RealmQuery<UserRealm> query = realmInstance.where(UserRealm.class);
RealmResults<UserRealm> result = query.findAll();
// TODO hacer que devuelva un array
ArrayList<UserRealm> users = new ArrayList<UserRealm>();
for (UserRealm u : result) {
//Here we can read the RealObject's fine
users.add(u);
}
return users.toArray(new UserRealm[users.size()]);
}
}.execute();
}
//Our abstract task that wraps all the instantiation-transaction behaviour
public abstract class GetQueryTask<T extends RealmObject> extends AsyncTask<Void, Void, T[]> {
@Override
protected T[] doInBackground(Void... params) {
//We tried to instantiate this class in several places, here
//Send it as parameter through the AsyncTask
//context is set in the with(Context ctx) method.
Realm realm = Realm.getInstance(context);
return onQueryReadyToBeExecuted(realm);
}
public abstract T[] onQueryReadyToBeExecuted(Realm realmInstance);
@Override
protected void onPostExecute(T[] result) {
mCallback.onExecute(result);
}
}
我们主要关心的不是此代码的 "bug",而是是否可以像 Realm.io 开发人员在其示例中所做的那样在 UiThread 中执行查询。如果是这样的话,所有这些异步执行查询的代码将不再是必需的。
这里是 Realm 的基督徒。 您是对的,查询当前需要在使用它们的线程上 运行,这可能会对 UI 线程性能产生负面影响。然而,我们敏锐地意识到这一点,并积极致力于使跨线程移动查询结果成为可能。
也就是说,即使对于合理的大量数据,领域 中的查询也 非常快,并且由于它只加载您实际使用的数据,即使 [=21] =] 在 UI 线程上。
我鼓励您尝试使用您认为合理的任何数据大小并测试您的性能(最好在旧设备上 :))。也可以做一些技巧,比如向键添加索引,在后台线程上进行繁重的查询,将键发送到 UI 线程并在那里重新查询它们。这是一个创可贴,但在某些情况下会起作用 - 遗憾的是不适用于列表。
realm 0.84 现在支持异步查询。
您可以通过将 'io.realm:realm-android:0.84.0-SNAPSHOT' 添加到您的 build.gradle 来尝试一下。有几个新方法
- findAllAsync
- findAllSortedAsync
- findFirstAsync
您必须将 addChangeListener(RealmChangeListener) 添加到 RealmResult 以在查询完成时收到通知。