我正在编写一些代码以将记录插入Sqlite数据库(如果表为空)。在插入任何数据之前,它会使Web服务调用LoveToDo.basecampClient().fetchMe()
以返回一些数据。
我使用SqlBrite进行数据库访问,使用Retrofit进行Web访问。这是我的代码:
Observable.just(LoveToDo.briteDatabase())
.map(new Func1<BriteDatabase, Integer>() {
@Override
public Integer call(BriteDatabase briteDatabase) {
Cursor cursor = briteDatabase.query("SELECT * FROM Accounts");
try {
return cursor.getCount();
} finally {
cursor.close();
}
}
})
.flatMap(new Func1<Integer, Observable<Person>>() {
@Override
public Observable<Person> call(Integer count) {
if ( count == 0 ) {
return LoveToDo.basecampClient().fetchMe();
}
return null;
}
})
.map(new Func1<Person, Boolean>() {
@Override
public Boolean call(Person person) {
if ( person == null ) return false;
BriteDatabase database = LoveToDo.briteDatabase();
long count = database.insert(Account.TABLE, new Account.Builder()
.accountId(Settings.accountId)
.userName(Settings.userName)
.password(Settings.password)
.agent(Settings.agent)
.personId(person.id)
.build()
);
return count > 0;
}
})
.subscribeOn(Schedulers.io())
.observeOn( Schedulers.io() )
.subscribe();
毋庸置疑,我不认为这是很棒的代码。我想做的是找出如何将这段代码转化为好的东西。因此,让我们使用它并挑选它的可怕性。
首先,我应该在一个运营商中组合数据库和Web服务调用操作。例如:
Observable.just(LoveToDo.briteDatabase())
.flatMap(new Func1<BriteDatabase, Observable<Person>>() {
@Override
public Observable<Person> call(BriteDatabase briteDatabase) {
Cursor cursor = briteDatabase.query("SELECT * FROM Accounts");
int count;
try {
count = cursor.getCount();
} finally {
cursor.close();
}
if ( count == 0 ) {
return LoveToDo.basecampClient().fetchMe();
}
return null;
}
})
.map(new Func1<Person, Boolean>() {
@Override
public Boolean call(Person person) {
if ( person == null ) return false;
BriteDatabase database = LoveToDo.briteDatabase();
long count = database.insert(Account.TABLE, new Account.Builder()
.accountId(Settings.accountId)
.userName(Settings.userName)
.password(Settings.password)
.agent(Settings.agent)
.personId(person.id)
.build()
);
return count > 0;
}
})
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe();
或者是否有充分的理由将这些操作隔离在链中?
第二件让我感到困惑的是这是一个后台操作 - 由于此代码,不会直接更新用户界面。这就是无参数subscribe()
函数调用的原因。但是当出现异常时会发生什么?这是否意味着我必须做以下事情?
.subscribe(new Action1<Boolean>() {
@Override
public void call(Boolean aBoolean) {
// Do nothing
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
// Do something with the exception
}
});
顺便说一下,当subscribeOn
设置为后台线程时,是否需要observeOn
?
第三,链是用SqlBrite观察者启动的。在链的后面我再次需要SqlBrite,所以我使用单例LoveToDo.briteDatabase()
访问它。这是一个坏主意吗?有更好的方法吗?
最后,有没有办法break;
链?如果我能放弃我正在做的事情而不是在每一步检查丢失的数据,那就太好了
答案 0 :(得分:3)
我看到很多问题。
NameModel
,其中包含Observable创建到subscribe()之前的所有逻辑。在那里有所有需要的逻辑,孤立。onError
Func是个好主意,除非你在某个地方之前发现所有可能的错误。使用onErrorReturn。如果出现问题,onError可以帮助您,例如通知用户。在订阅中更新某些内容而不是从链内部更新内容也是一种很好的做法,从而隔离了运营商的内容。subscribeOn
使流程位于后台,而不是observeOn
。所以不,如果您不更改帖子example here,则不需要observeOn
。.lift()
运算符从内部取消订阅链。根据评论进行更新:
从第二个上面的2个,但我更喜欢这样的东西:
Observable.just(LoveToDo.briteDatabase())
.flatMap(briteDatabase -> {
Cursor cursor = briteDatabase.query("SELECT * FROM Accounts");
int count;
try {
count = cursor.getCount();
} finally {
cursor.close();
}
if (count == 0) {
return LoveToDo.basecampClient().fetchMe()
.map(person -> insertPerson(person, briteDatabase));
}
// if you want to track the account creation
return just(false);
})
.subscribeOn(Schedulers.io())
.subscribe(personInserted -> {
// do something if the person was created or not
}, e -> {
});
private Boolean insertPerson(Person person, BriteDatabase briteDatabase) {
long count = briteDatabase.insert(Account.TABLE, new Account.Builder()
.accountId(Settings.accountId)
.userName(Settings.userName)
.password(Settings.password)
.agent(Settings.agent)
.personId(person.id)
.build());
return count > 0;
}