Android 使用 RxJava 的 Room:使用循环从 Room 获取数据
Android Room with RxJava: get data from Room with the loop
我是 RxJava 和 Room 的新手。我想做的是 运行 从数据库中获取数据的 for 循环。 for 循环从每月的第一天迭代到每月的最后一天。
这是此查询的 Dao
。
@Query("SELECT SUM(duration) FROM xxx WHERE timeStamp >= :start and timeStamp <= :end and userId = :userId")
Flowable<Integer> getDuration(String userId, long start, long end);
下面是我如何使用 RxJava 获得结果。
Calendar day1 = Calendar.getInstance();
Calendar day2 = Calendar.getInstance();
int maxLoopIndex = day1.getActualMaximum(Calendar.DAY_OF_MONTH);
day1.setFirstDayOfWeek(Calendar.MONDAY);
day2.setFirstDayOfWeek(Calendar.MONDAY);
day1.set(Calendar.DATE, day1.getActualMinimum(Calendar.DATE));
day2.set(Calendar.DATE, day2.getActualMinimum(Calendar.DATE));
day1.set(Calendar.HOUR_OF_DAY, 0);
day1.set(Calendar.MINUTE, 0);
day1.set(Calendar.SECOND, 0);
day1.set(Calendar.MILLISECOND, 0);
day2.set(Calendar.HOUR_OF_DAY, 23);
day2.set(Calendar.MINUTE, 59);
day2.set(Calendar.SECOND, 59);
day2.set(Calendar.MILLISECOND, 999);
ArrayList<Pair<Long, Long>> maxDayCount = new ArrayList<>();
//Get all the timeStamp in a month, where maxDayCount can be 30, 31, 28, 29.
for (int i = 0; i < maxDayCount; i++) {
Pair<Long, Long> P = Pair.create(day1.getTimeInMillis(), day2.getTimeInMillis());
pairArrayList.add(P);
day1.add(Calendar.DATE, 1);
day2.add(Calendar.DATE, 1);
}
// Using Flowable.formIterable to run through the list and get the data from room
Flowable.fromIterable(pairArrayList)
.flatMap(new Function<Pair<Long, Long>, Flowable<Integer>>() {
@Override
public Flowable<Integer> apply(@NonNull Pair<Long, Long> date) throws Exception {
return roomdb.Dao().getDuration(
User.getCurUser().getId(), date.first, date.second
);
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Integer>() {
@Override
public void accept(@NonNull Integer source) throws Exception {
Log.d(TAG, "Duration: "+source);
// I want to get the index of pairArrayList to store the duration in
// corresponding array
}
});
但是在订阅中我可以通过房间得到结果 return 但是我无法在 pairArrayList 中得到哪个索引是 运行。有什么办法可以获得索引吗?此外,有没有更好的方法可以通过循环从房间获取数据?
让我们从最终结构开始。它应该包含月份和持续时间:
class DayDuration {
public Integer day;
public Long duration;
public DayDuration(Integer day, Long duration) {
this.day = day;
this.duration = duration;
}
@Override
public boolean equals(Object o) { /* implementation */ }
@Override
public int hashCode() { /* implementation */ }
}
创建最终 Flowable
发出请求项的内容可能类似于以下代码。我使用 ThreetenBP 库来处理 date/time 操作,因为 Android Calendar
API 简直就是地狱。建议您也这样做:
class SO64870062 {
private Flowable<Long> getDuration(String userId, long start, long end) {
return Flowable.fromCallable(() -> start); // mock data
}
@NotNull
private Flowable<LocalDate> getDaysInMonth(YearMonth yearMonth) { // (1)
LocalDate start = LocalDate.of(yearMonth.getYear(), yearMonth.getMonthValue(), 1);
LocalDate end = start.with(TemporalAdjusters.lastDayOfMonth());
return Flowable.create(emitter -> {
LocalDate current = start;
while (!current.isAfter(end)) { // (2)
emitter.onNext(current);
current = current.plusDays(1);
}
emitter.onComplete();
}, BackpressureStrategy.BUFFER);
}
@NotNull
private Flowable<DayDuration> getDurationForDay(String userId, LocalDate localDate) {
long startDayMillis = localDate.atStartOfDay().atZone(ZoneOffset.UTC) // (3)
.toInstant()
.toEpochMilli();
long endDayMillis = localDate.atTime(LocalTime.MAX).atZone(ZoneOffset.UTC)
.toInstant()
.toEpochMilli();
return getDuration(userId, startDayMillis, endDayMillis) // (4)
.map(duration -> new DayDuration(localDate.getDayOfMonth(), duration));
}
public Flowable<DayDuration> getDayDurations(String userId, YearMonth yearMonth) {
return getDaysInMonth(yearMonth)
.flatMap(localDate -> getDurationForDay(userId, localDate));
}
}
重要和有趣的部分:
- 函数
getDaysInMonth()
创建 Flowable
发出所请求月份的所有天数的内容。
- 从开始(一个月的第一天)到结束(一个月的最后一天)日期并发出所有日期的迭代。
- 确保在数据库中的时间戳内设置您使用的区域。为了简单起见,我使用了
UTC
。
- 将数据库中的持续时间与当前日期相结合。
最后但同样重要的是,让我们检查它是否正常工作:
public class SO64870062Test {
@Test
public void whenDaysRequestedForApril2020ThenEmitted() {
SO64870062 tested = new SO64870062();
TestSubscriber<DayDuration> testSubscriber = tested
.getDayDurations("userId", YearMonth.of(2020, 11))
.test();
testSubscriber.assertValueCount(30);
testSubscriber.assertValueAt(1, new DayDuration(2, 1604275200000L));
testSubscriber.assertComplete();
}
}
我是 RxJava 和 Room 的新手。我想做的是 运行 从数据库中获取数据的 for 循环。 for 循环从每月的第一天迭代到每月的最后一天。
这是此查询的 Dao
。
@Query("SELECT SUM(duration) FROM xxx WHERE timeStamp >= :start and timeStamp <= :end and userId = :userId")
Flowable<Integer> getDuration(String userId, long start, long end);
下面是我如何使用 RxJava 获得结果。
Calendar day1 = Calendar.getInstance();
Calendar day2 = Calendar.getInstance();
int maxLoopIndex = day1.getActualMaximum(Calendar.DAY_OF_MONTH);
day1.setFirstDayOfWeek(Calendar.MONDAY);
day2.setFirstDayOfWeek(Calendar.MONDAY);
day1.set(Calendar.DATE, day1.getActualMinimum(Calendar.DATE));
day2.set(Calendar.DATE, day2.getActualMinimum(Calendar.DATE));
day1.set(Calendar.HOUR_OF_DAY, 0);
day1.set(Calendar.MINUTE, 0);
day1.set(Calendar.SECOND, 0);
day1.set(Calendar.MILLISECOND, 0);
day2.set(Calendar.HOUR_OF_DAY, 23);
day2.set(Calendar.MINUTE, 59);
day2.set(Calendar.SECOND, 59);
day2.set(Calendar.MILLISECOND, 999);
ArrayList<Pair<Long, Long>> maxDayCount = new ArrayList<>();
//Get all the timeStamp in a month, where maxDayCount can be 30, 31, 28, 29.
for (int i = 0; i < maxDayCount; i++) {
Pair<Long, Long> P = Pair.create(day1.getTimeInMillis(), day2.getTimeInMillis());
pairArrayList.add(P);
day1.add(Calendar.DATE, 1);
day2.add(Calendar.DATE, 1);
}
// Using Flowable.formIterable to run through the list and get the data from room
Flowable.fromIterable(pairArrayList)
.flatMap(new Function<Pair<Long, Long>, Flowable<Integer>>() {
@Override
public Flowable<Integer> apply(@NonNull Pair<Long, Long> date) throws Exception {
return roomdb.Dao().getDuration(
User.getCurUser().getId(), date.first, date.second
);
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Integer>() {
@Override
public void accept(@NonNull Integer source) throws Exception {
Log.d(TAG, "Duration: "+source);
// I want to get the index of pairArrayList to store the duration in
// corresponding array
}
});
但是在订阅中我可以通过房间得到结果 return 但是我无法在 pairArrayList 中得到哪个索引是 运行。有什么办法可以获得索引吗?此外,有没有更好的方法可以通过循环从房间获取数据?
让我们从最终结构开始。它应该包含月份和持续时间:
class DayDuration {
public Integer day;
public Long duration;
public DayDuration(Integer day, Long duration) {
this.day = day;
this.duration = duration;
}
@Override
public boolean equals(Object o) { /* implementation */ }
@Override
public int hashCode() { /* implementation */ }
}
创建最终 Flowable
发出请求项的内容可能类似于以下代码。我使用 ThreetenBP 库来处理 date/time 操作,因为 Android Calendar
API 简直就是地狱。建议您也这样做:
class SO64870062 {
private Flowable<Long> getDuration(String userId, long start, long end) {
return Flowable.fromCallable(() -> start); // mock data
}
@NotNull
private Flowable<LocalDate> getDaysInMonth(YearMonth yearMonth) { // (1)
LocalDate start = LocalDate.of(yearMonth.getYear(), yearMonth.getMonthValue(), 1);
LocalDate end = start.with(TemporalAdjusters.lastDayOfMonth());
return Flowable.create(emitter -> {
LocalDate current = start;
while (!current.isAfter(end)) { // (2)
emitter.onNext(current);
current = current.plusDays(1);
}
emitter.onComplete();
}, BackpressureStrategy.BUFFER);
}
@NotNull
private Flowable<DayDuration> getDurationForDay(String userId, LocalDate localDate) {
long startDayMillis = localDate.atStartOfDay().atZone(ZoneOffset.UTC) // (3)
.toInstant()
.toEpochMilli();
long endDayMillis = localDate.atTime(LocalTime.MAX).atZone(ZoneOffset.UTC)
.toInstant()
.toEpochMilli();
return getDuration(userId, startDayMillis, endDayMillis) // (4)
.map(duration -> new DayDuration(localDate.getDayOfMonth(), duration));
}
public Flowable<DayDuration> getDayDurations(String userId, YearMonth yearMonth) {
return getDaysInMonth(yearMonth)
.flatMap(localDate -> getDurationForDay(userId, localDate));
}
}
重要和有趣的部分:
- 函数
getDaysInMonth()
创建Flowable
发出所请求月份的所有天数的内容。 - 从开始(一个月的第一天)到结束(一个月的最后一天)日期并发出所有日期的迭代。
- 确保在数据库中的时间戳内设置您使用的区域。为了简单起见,我使用了
UTC
。 - 将数据库中的持续时间与当前日期相结合。
最后但同样重要的是,让我们检查它是否正常工作:
public class SO64870062Test {
@Test
public void whenDaysRequestedForApril2020ThenEmitted() {
SO64870062 tested = new SO64870062();
TestSubscriber<DayDuration> testSubscriber = tested
.getDayDurations("userId", YearMonth.of(2020, 11))
.test();
testSubscriber.assertValueCount(30);
testSubscriber.assertValueAt(1, new DayDuration(2, 1604275200000L));
testSubscriber.assertComplete();
}
}