使用 Dagger 从不正确的线程访问的领域
Realm accessed from incorrect thread, with Dagger
我目前正在一个简单的项目中学习 Dagger、RxJava、Realm 和 MVP。
基本上这个应用程序可以做的是它可以查看、添加、删除和更新数据库中的数据,我正在使用 Realm。
我决定遵循 MVP 架构并应用存储库模式以及后端层的数据操作。
为了额外学习,我为架构中的依赖注入添加了 Dagger。
在此之前,我开发了一个没有应用 MVP 和存储库模式的应用程序,甚至没有考虑 Dagger 和 RxJava。一切似乎都运行良好,没有来自 Realm 线程系统的任何错误。也许是因为我把所有东西都绑在一个 class.
所以,既然我要放弃那种方法,我现在在用新方法实现它时遇到了麻烦,我认为这种方法耦合更松散,如果正确实现应该会更好。
介绍完了,言归正传。
我现在面临的问题是 Realm 总是给我这个错误:
Exception has been thrown: Realm accessed from incorrect thread.
我怀疑我的 Dagger 图管理不当(尤其是在提供 Realm 实例时),因此每当我查询数据时,它都会给我错误。
因此,我的 Dagger 组件如下所示:
@Singleton
@Component(modules = {ContextModule.class, RepositoryModule.class, PresenterModule.class})
public interface AppComponent {
/* Inejct application */
void inject(FourdoApp fourdoApp);
/* Realm Helper */
void inject(DatabaseRealm databaseRealm);
/* Activity */
void inject(MainActivity mainActivity);
void inject(TaskDetailActivity taskDetailActivity);
/* Presenter*/
void inject(MainPresenter mainPresenter);
void inject(TaskDetailPresenter taskDetailPresenter);
/* Model repository*/
void inject(TaskRepositoryImpl taskRepository);
}
里面RepositoryModule.class
;
@Module
public class RepositoryModule {
@Provides
@Singleton
Repository<Task> provideTaskRepository() {
return new TaskRepositoryImpl();
}
// Here I provide DatabaseRealm class instance
@Provides
@Singleton
public DatabaseRealm provideDatabaseRealm() {
return new DatabaseRealm();
}
}
不确定我这样做是否正确。您可以查看 DI here.
的来源
为了发生数据请求,在 MainActivity
中,我注入了 MainPresenter
并调用 onRequestData
接口从 Presenter 请求它。从那里,Presenter 将为所述数据调用 Repository。
public class MainActivity extends BaseActivity implements MainContract.View {
@Inject
MainPresenter mainPresenter;
// ...
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Injecting MainActivity class
Injector.getAppComponent().inject(this);
mainPresenter.attachView(this);
// Requesting for data from Presenter
mainPresenter.onRequestData();
}
// ...
@Override
public void onRequestDataSuccess(List<String> taskList) {
doAdapter.addAll(taskList);
doAdapter.notifyDataSetChanged();
}
}
在 MainPresenter 中,我注入了 Repository 接口以从 TaskRepositoryImpl
请求数据库中的真实数据。
public class MainPresenter extends BasePresenter<MainContract.View> implements MainContract.Presenter {
@Inject
Repository<Task> taskRepository;
public MainPresenter() {
Injector.getAppComponent().inject(this);
}
@Override
public void onRequestData() {
requestData();
}
private void requestData() {
taskRepository.findAll()
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.map(this::mapToStringList)
.subscribe(new Observer<List<String>>() {
@Override
public void onNext(List<String> strings) { // Error in this line
if (strings.size() > 0) {
mView.onRequestDataSuccess(strings);
} else {
mView.showEmpty();
}
}
});
}
}
在 TaskRepositoryImpl
中,我是这样处理 findAll
的 return 来自 DatabaseRealm
的数据:
@Override
public Observable<List<Task>> findAll() {
return Observable.create(subscriber -> {
try {
List<Task> models = databaseRealm.findAll(Task.class);
subscriber.onNext(models);
subscriber.onComplete();
} catch (Exception e) {
subscriber.onError(e);
}
});
}
DatabaseRealm
的代码如下:
public class DatabaseRealm {
@Inject
Context context;
RealmConfiguration realmConfiguration;
public DatabaseRealm() {
Injector.getAppComponent().inject(this);
}
public void setup() {
if (realmConfiguration == null) {
Realm.init(context);
realmConfiguration = new RealmConfiguration.Builder()
.deleteRealmIfMigrationNeeded()
.build();
Realm.setDefaultConfiguration(realmConfiguration);
} else {
throw new IllegalStateException("Realm already configured");
}
}
public Realm getRealmInstance() {
return Realm.getDefaultInstance();
}
public <T extends RealmObject> T add(T model) {
Realm realm = getRealmInstance();
realm.beginTransaction();
realm.copyToRealm(model);
realm.commitTransaction();
return model;
}
public <T extends RealmObject> T update(T model) {
Realm realm = getRealmInstance();
realm.beginTransaction();
realm.copyToRealmOrUpdate(model);
realm.commitTransaction();
return model;
}
public <T extends RealmObject> T remove(T model) {
Realm realm = getRealmInstance();
realm.beginTransaction();
realm.copyToRealm(model);
realm.deleteAll();
realm.commitTransaction();
return model;
}
public <T extends RealmObject> List<T> findAll(Class<T> clazz) {
return getRealmInstance().where(clazz).findAll();
}
public void close() {
getRealmInstance().close();
}
}
这个有缺陷的代码的完整源代码是正确的here。
我想声明一下,我对 Dagger 中使用的 Realm 实例知之甚少。
我遵循 this tutorial 的 Repository Design Pattern with Realm,但它不包括用于依赖项注入的 Dagger。
有人可以指导我为什么它总是告诉我从错误的线程调用 Realm 吗?
您只需要在 Application
class 中设置一次 RealmConfigration
并使用 Realm.getDeafultInstance()
方法访问 Realm 数据库
使用 Dagger,您只需要在构造函数中传递领域实例
你可以关注这个 Example 并分叉它
它与您发布的代码不完全相同 here.But 它可能有助于通过 MVP、RxJava 和 Realm 更好地理解 dagger
我想你会因为这个而得到这个错误:
@Override
public Observable<List<Task>> findAll() {
return Observable.create(subscriber -> {
try {
List<Task> models = databaseRealm.findAll(Task.class);
subscriber.onNext(models);
subscriber.onComplete();
} catch (Exception e) {
subscriber.onError(e);
}
});
}
您正在订阅 io Thread
,但您在 Main Thread
中插入了 databaseRealm
。
如果您在 observable 的创建中获取实例,您将不会收到此错误。
@Override
public Observable<List<Task>> findAll() {
return Observable.create(subscriber -> {
try {
Realm realm = getRealmInstance();
List<Task> models = realm.findAll(Task.class);
subscriber.onNext(models);
subscriber.onComplete();
} catch (Exception e) {
subscriber.onError(e);
}
});
}
我目前正在一个简单的项目中学习 Dagger、RxJava、Realm 和 MVP。
基本上这个应用程序可以做的是它可以查看、添加、删除和更新数据库中的数据,我正在使用 Realm。
我决定遵循 MVP 架构并应用存储库模式以及后端层的数据操作。
为了额外学习,我为架构中的依赖注入添加了 Dagger。
在此之前,我开发了一个没有应用 MVP 和存储库模式的应用程序,甚至没有考虑 Dagger 和 RxJava。一切似乎都运行良好,没有来自 Realm 线程系统的任何错误。也许是因为我把所有东西都绑在一个 class.
所以,既然我要放弃那种方法,我现在在用新方法实现它时遇到了麻烦,我认为这种方法耦合更松散,如果正确实现应该会更好。
介绍完了,言归正传。
我现在面临的问题是 Realm 总是给我这个错误:
Exception has been thrown: Realm accessed from incorrect thread.
我怀疑我的 Dagger 图管理不当(尤其是在提供 Realm 实例时),因此每当我查询数据时,它都会给我错误。
因此,我的 Dagger 组件如下所示:
@Singleton
@Component(modules = {ContextModule.class, RepositoryModule.class, PresenterModule.class})
public interface AppComponent {
/* Inejct application */
void inject(FourdoApp fourdoApp);
/* Realm Helper */
void inject(DatabaseRealm databaseRealm);
/* Activity */
void inject(MainActivity mainActivity);
void inject(TaskDetailActivity taskDetailActivity);
/* Presenter*/
void inject(MainPresenter mainPresenter);
void inject(TaskDetailPresenter taskDetailPresenter);
/* Model repository*/
void inject(TaskRepositoryImpl taskRepository);
}
里面RepositoryModule.class
;
@Module
public class RepositoryModule {
@Provides
@Singleton
Repository<Task> provideTaskRepository() {
return new TaskRepositoryImpl();
}
// Here I provide DatabaseRealm class instance
@Provides
@Singleton
public DatabaseRealm provideDatabaseRealm() {
return new DatabaseRealm();
}
}
不确定我这样做是否正确。您可以查看 DI here.
的来源为了发生数据请求,在 MainActivity
中,我注入了 MainPresenter
并调用 onRequestData
接口从 Presenter 请求它。从那里,Presenter 将为所述数据调用 Repository。
public class MainActivity extends BaseActivity implements MainContract.View {
@Inject
MainPresenter mainPresenter;
// ...
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Injecting MainActivity class
Injector.getAppComponent().inject(this);
mainPresenter.attachView(this);
// Requesting for data from Presenter
mainPresenter.onRequestData();
}
// ...
@Override
public void onRequestDataSuccess(List<String> taskList) {
doAdapter.addAll(taskList);
doAdapter.notifyDataSetChanged();
}
}
在 MainPresenter 中,我注入了 Repository 接口以从 TaskRepositoryImpl
请求数据库中的真实数据。
public class MainPresenter extends BasePresenter<MainContract.View> implements MainContract.Presenter {
@Inject
Repository<Task> taskRepository;
public MainPresenter() {
Injector.getAppComponent().inject(this);
}
@Override
public void onRequestData() {
requestData();
}
private void requestData() {
taskRepository.findAll()
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.map(this::mapToStringList)
.subscribe(new Observer<List<String>>() {
@Override
public void onNext(List<String> strings) { // Error in this line
if (strings.size() > 0) {
mView.onRequestDataSuccess(strings);
} else {
mView.showEmpty();
}
}
});
}
}
在 TaskRepositoryImpl
中,我是这样处理 findAll
的 return 来自 DatabaseRealm
的数据:
@Override
public Observable<List<Task>> findAll() {
return Observable.create(subscriber -> {
try {
List<Task> models = databaseRealm.findAll(Task.class);
subscriber.onNext(models);
subscriber.onComplete();
} catch (Exception e) {
subscriber.onError(e);
}
});
}
DatabaseRealm
的代码如下:
public class DatabaseRealm {
@Inject
Context context;
RealmConfiguration realmConfiguration;
public DatabaseRealm() {
Injector.getAppComponent().inject(this);
}
public void setup() {
if (realmConfiguration == null) {
Realm.init(context);
realmConfiguration = new RealmConfiguration.Builder()
.deleteRealmIfMigrationNeeded()
.build();
Realm.setDefaultConfiguration(realmConfiguration);
} else {
throw new IllegalStateException("Realm already configured");
}
}
public Realm getRealmInstance() {
return Realm.getDefaultInstance();
}
public <T extends RealmObject> T add(T model) {
Realm realm = getRealmInstance();
realm.beginTransaction();
realm.copyToRealm(model);
realm.commitTransaction();
return model;
}
public <T extends RealmObject> T update(T model) {
Realm realm = getRealmInstance();
realm.beginTransaction();
realm.copyToRealmOrUpdate(model);
realm.commitTransaction();
return model;
}
public <T extends RealmObject> T remove(T model) {
Realm realm = getRealmInstance();
realm.beginTransaction();
realm.copyToRealm(model);
realm.deleteAll();
realm.commitTransaction();
return model;
}
public <T extends RealmObject> List<T> findAll(Class<T> clazz) {
return getRealmInstance().where(clazz).findAll();
}
public void close() {
getRealmInstance().close();
}
}
这个有缺陷的代码的完整源代码是正确的here。
我想声明一下,我对 Dagger 中使用的 Realm 实例知之甚少。
我遵循 this tutorial 的 Repository Design Pattern with Realm,但它不包括用于依赖项注入的 Dagger。
有人可以指导我为什么它总是告诉我从错误的线程调用 Realm 吗?
您只需要在 Application
class 中设置一次 RealmConfigration
并使用 Realm.getDeafultInstance()
方法访问 Realm 数据库
使用 Dagger,您只需要在构造函数中传递领域实例
你可以关注这个 Example 并分叉它
它与您发布的代码不完全相同 here.But 它可能有助于通过 MVP、RxJava 和 Realm 更好地理解 dagger
我想你会因为这个而得到这个错误:
@Override
public Observable<List<Task>> findAll() {
return Observable.create(subscriber -> {
try {
List<Task> models = databaseRealm.findAll(Task.class);
subscriber.onNext(models);
subscriber.onComplete();
} catch (Exception e) {
subscriber.onError(e);
}
});
}
您正在订阅 io Thread
,但您在 Main Thread
中插入了 databaseRealm
。
如果您在 observable 的创建中获取实例,您将不会收到此错误。
@Override
public Observable<List<Task>> findAll() {
return Observable.create(subscriber -> {
try {
Realm realm = getRealmInstance();
List<Task> models = realm.findAll(Task.class);
subscriber.onNext(models);
subscriber.onComplete();
} catch (Exception e) {
subscriber.onError(e);
}
});
}