【发布时间】:2015-06-03 19:50:07
【问题描述】:
Realm.getInstance(context) 很少会返回已经关闭的领域实例。这怎么可能?
根据https://realm.io/news/using-realm-with-rxjava/,我将 Realm 与 RxJava 一起使用
特别是,这个方法会抛出一个IllegalStateException: This Realm instance has already been closed, making it unusable.
@Override
public void call(final Subscriber<? super RealmList<T>> subscriber) {
final Realm realm = Realm.getInstance(context);
subscriber.add(Subscriptions.create(new Action0() {
@Override
public void call() {
try {
realm.close();
} catch (RealmException ex) {
subscriber.onError(ex);
}
}
}));
RealmList<T> object;
realm.beginTransaction(); //THROWS EXCEPTION
//...
}
如果我注释掉 realm.close(); 问题,没问题。虽然我认为这会导致本机内存泄漏。
对于为什么会发生这种情况,我最好的猜测是对该方法进行了多次调用,如果这些方法调用完美排列,那么可以检索已经关闭的领域实例?
编辑:通过使用Schedulers.io(),我收到很多Calling close() on a Realm that is already closed 警告。我的猜测是,在我完成使用.io() 线程之后,领域实例会自动关闭。不知道为什么会发生这种情况。
EDIT2:通过切换到使用 Schedulers.newThread() 而不是 Schedulers.io() 作为我的 observables,问题不再出现。但我看到很多Remember to call close() on all Realm instances 警告。我很确定我正在关闭它们,所以我对此感到非常困惑。
EDIT3:通过切换到使用AndroidSchedulers.mainThread(),没有错误。除了我的 Realm 调用在主线程上运行,这很糟糕。我猜为什么这不会导致警告是因为realm 现在位于主线程上,这也是调用realm.close() 的地方(通过rx.subscriber)。
EDIT4:这是我的领域可观察调用的逻辑。
@Override
public Observable<List<ImageArticleCategoryEntity>> getArticleBuckets() {
return RealmObservable.list(context, GET_ARTICLE_BUCKETS)
.filter(FILTER_OUT_NULL_OR_EMPTY_LIST)
.switchIfEmpty(refreshAndSaveAndLoadNewDataFromDb)
.map(CONVERT_FROM_REALMLIST_TO_IMAGE_ARTICLE_ENTITYLIST);
}
public void loadArticleImages() {
articleRepo.getArticleBuckets()
.subscribeOn(RealmThread.get())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<List<ImageArticleCategoryEntity>>() {
@Override
public void onCompleted() {
Timber.v("Loading article images complete!");
if (view != null)
view.hideLoadingAnimation();
}
@Override
public void onError(Throwable e) {
Timber.e("Error loading article images", e);
Log.e("tag", "Error loading article images", e);
if (view != null) {
view.hideLoadingAnimation();
view.showLoadingErrorToast();
}
}
@Override
public void onNext(List<ImageArticleCategoryEntity> integerImageArticleCategoryEntityHashMap) {
if (view != null)
view.loadArticleImages(integerImageArticleCategoryEntityHashMap);
}
});
【问题讨论】:
-
您是否 100% 确定
Realm.getInstance(context)实际上返回了一个关闭的实例?我认为您可能应该将 Realm 绑定到服务中的活动计数、活动的生命周期或保留的无头片段的生命周期。 -
我不在主线程上执行 IO 操作,这似乎是您的建议,因为领域实例不能跨线程传递。是的,我 100% 确定这正在发生。我尝试了一个捕获
IllegalStateException的try/catch 块。在捕获中,我通过realm.getInstance(context)得到了一个新的realm,并在之后立即调用了realm.beginTransaction()。再次抛出异常。 -
哦,好的。对,你不能跨线程共享 Realm。
-
@EpicPandaForce 是的。我没有那样做。我的领域实例只在同一个线程上使用。
-
你什么时候打电话给
unsubscribe来订阅领域?