我目前正在一个简单的项目中学习Dagger,RxJava,Realm和MVP。
这个应用程序基本上可以做的是它可以查看,添加,删除和更新数据库中的数据,我使用的是Realm。
我决定遵循MVP架构并应用存储库模式以及后端层的数据操作。
为了进行额外的学习,我在架构中添加了Dagger用于依赖注入。
在此之前,我开发了一个应用程序,但没有应用MVP或存储库模式,甚至没有考虑Dagger和RxJava。所有似乎都运行良好,没有来自Realm线程系统的任何错误。也许是因为我把所有东西都捆绑在一个班级里。
所以,既然我已经摆脱了这种方法,我现在无法在新方法中实现它,我认为这种方法更松散,如果正确实施则应该更好。
足够的介绍,让我们回到主题。
我现在面临的问题是Realm总是给我这个错误:
抛出异常:从不正确的线程访问Realm。
我怀疑我的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
的处理方式,它应该从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使用了Realm的存储库设计模式,但它并没有包含Dagger的依赖注入。
有人可以指导我为什么总是说我从不正确的线程中调用Realm?
答案 0 :(得分:2)
我认为你因此而得到这个错误:
@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
,但是您在databaseRealm
注入Main Thread
。
如果你在你的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);
}
});
}
答案 1 :(得分:1)
您只需在RealmConfigration
课程中设置Application
一次,并使用Realm.getDeafultInstance()
方法访问Realm数据库
使用Dagger,您只需要在构造函数
中传递realm实例您可以按照此Example并将其分叉
它与你在这里发布的代码不完全相同。但是,使用MVP,RxJava和Realm可能有助于更好地理解匕首