是否可以将两个 LiveData 做成一个 LiveData?
Is it possible to make one LiveData of two LiveDatas?
我有两个 DAO、两个存储库和两个 POJO。有什么方法可以创建两个的一个 Livedata?我需要它来为 Recyclerview 制作单个列表。
POJO 是相似的对象。
费用库:
public class ExpenseRepository {
private ExpenseDao expenseDao;
private LiveData<List<Expense>> allExpenses;
public ExpenseRepository(Application application) {
ExpenseIncomeDatabase database = ExpenseIncomeDatabase.getInstance(application);
expenseDao = database.expenseDao();
allExpenses = expenseDao.getExpensesByDay();
}
public LiveData<List<Expense>> getAllExpensesByDay() {
return allExpenses;
}
收入库:
public class IncomeRepository {
private IncomeDao incomeDao;
private LiveData<List<Income>> allIncomes;
public IncomeRepository(Application application) {
ExpenseIncomeDatabase database = ExpenseIncomeDatabase.getInstance(application);
incomeDao = database.incomeDao();
allIncomes = incomeDao.getIncomesByDay();
}
public LiveData<List<Income>> getAllIncomesByDay() {
return allIncomes;
}
ExpenseDao:
@Dao
public interface ExpenseDao {
@Query("SELECT * FROM expense_table ORDER BY day")
LiveData<List<Expense>> getExpensesByDay();
收入道:
@Dao
public interface IncomeDao {
@Query("SELECT * FROM income_table ORDER BY day")
LiveData<List<Income>> getIncomesByDay();
DailyViewModel:
public class DailyFragmentViewModel extends AndroidViewModel {
private ExpenseRepository expenseRepository;
private IncomeRepository incomeRepository;
private LiveData<Pair<List<Expense>, List<Income>>> combined;
private ExpenseDao expenseDao;
private IncomeDao incomeDao;
public DailyFragmentViewModel(@NonNull Application application) {
super(application);
expenseRepository = new ExpenseRepository(application);
incomeRepository = new IncomeRepository(application);
combined = new DailyCombinedLiveData(expenseDao.getExpensesByDay(), incomeDao.getIncomesByDay());
}
public LiveData<Pair<List<Expense>, List<Income>>> getExpensesAndIncomes() {
return combined;
}
我猜你想把它们结合起来,是吗?您将需要一个 MediatorLiveData,但是说您现在需要 Object 的人是错误的。你需要的是 MediatorLiveData<Pair<List<Expense>, List<Income>>>
.
public class CombinedLiveData extends MediatorLiveData<Pair<List<Expense>, List<Income>>> {
private List<Expense> expenses = Collections.emptyList();
private List<Income> incomes = Collections.emptyList();
public CombinedLiveData(LiveData<List<Expense>> ld1, LiveData<List<Income>> ld2) {
setValue(Pair.create(expenses, incomes));
addSource(ld1, expenses -> {
if(expenses != null) {
this.expenses = expenses;
}
setValue(Pair.create(expenses, incomes));
});
addSource(ld2, incomes -> {
if(incomes != null) {
this.incomes = incomes;
}
setValue(Pair.create(expenses, incomes));
});
}
}
您可以使它成为通用的,它是 combineLatest
的实现,用于使用 2-arity (Pair) 的元组的两个 LiveData。
编辑: 像这样:
public class CombinedLiveData2<A, B> extends MediatorLiveData<Pair<A, B>> {
private A a;
private B b;
public CombinedLiveData2(LiveData<A> ld1, LiveData<B> ld2) {
setValue(Pair.create(a, b));
addSource(ld1, a -> {
if(a != null) {
this.a = a;
}
setValue(Pair.create(a, b));
});
addSource(ld2, b -> {
if(b != null) {
this.b = b;
}
setValue(Pair.create(a, b));
});
}
}
请注意,在这种情况下我无法将 Collections.emptyList()
设置为 A
和 B
的初始值,您将需要检查 null
s当您访问该对中的数据时。
编辑: 您可以使用库 https://github.com/Zhuinden/livedata-combinetuple-kt (Kotlin) or https://github.com/Zhuinden/livedata-combineutil-java/ (Java) 做同样的事情。
而不是让 class 添加 2 个实时数据,另一个 class 添加 3 个实时数据,等等。我们可以使用更抽象的方式,我们可以添加尽可能多的实时数据我们想要。
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
/**
* CombinedLiveData is a helper class to combine results from multiple LiveData sources.
* @param liveDatas Variable number of LiveData arguments.
* @param combine Function reference that will be used to combine all LiveData data.
* @param R The type of data returned after combining all LiveData data.
* Usage:
* CombinedLiveData<SomeType>(
* getLiveData1(),
* getLiveData2(),
* ... ,
* getLiveDataN()
* ) { datas: List<Any?> ->
* // Use datas[0], datas[1], ..., datas[N] to return a SomeType value
* }
*/
class CombinedLiveData<R>(vararg liveDatas: LiveData<*>,
private val combine: (datas: List<Any?>) -> R) : MediatorLiveData<R>() {
private val datas: MutableList<Any?> = MutableList(liveDatas.size) { null }
init {
for(i in liveDatas.indices){
super.addSource(liveDatas[i]) {
datas[i] = it
value = combine(datas)
}
}
}
}
在 kotlin 中创建了这个扩展函数
fun <A, B> LiveData<A>.zipWith(stream: LiveData<B>): LiveData<Pair<A, B>> {
val result = MediatorLiveData<Pair<A, B>>()
result.addSource(this) { a ->
if (a != null && stream.value != null) {
result.value = Pair(a, stream.value!!)
}
}
result.addSource(stream) { b ->
if (b != null && this.value != null) {
result.value = Pair(this.value!!, b)
}
}
return result
}
我有两个 DAO、两个存储库和两个 POJO。有什么方法可以创建两个的一个 Livedata?我需要它来为 Recyclerview 制作单个列表。 POJO 是相似的对象。
费用库:
public class ExpenseRepository {
private ExpenseDao expenseDao;
private LiveData<List<Expense>> allExpenses;
public ExpenseRepository(Application application) {
ExpenseIncomeDatabase database = ExpenseIncomeDatabase.getInstance(application);
expenseDao = database.expenseDao();
allExpenses = expenseDao.getExpensesByDay();
}
public LiveData<List<Expense>> getAllExpensesByDay() {
return allExpenses;
}
收入库:
public class IncomeRepository {
private IncomeDao incomeDao;
private LiveData<List<Income>> allIncomes;
public IncomeRepository(Application application) {
ExpenseIncomeDatabase database = ExpenseIncomeDatabase.getInstance(application);
incomeDao = database.incomeDao();
allIncomes = incomeDao.getIncomesByDay();
}
public LiveData<List<Income>> getAllIncomesByDay() {
return allIncomes;
}
ExpenseDao:
@Dao
public interface ExpenseDao {
@Query("SELECT * FROM expense_table ORDER BY day")
LiveData<List<Expense>> getExpensesByDay();
收入道:
@Dao
public interface IncomeDao {
@Query("SELECT * FROM income_table ORDER BY day")
LiveData<List<Income>> getIncomesByDay();
DailyViewModel:
public class DailyFragmentViewModel extends AndroidViewModel {
private ExpenseRepository expenseRepository;
private IncomeRepository incomeRepository;
private LiveData<Pair<List<Expense>, List<Income>>> combined;
private ExpenseDao expenseDao;
private IncomeDao incomeDao;
public DailyFragmentViewModel(@NonNull Application application) {
super(application);
expenseRepository = new ExpenseRepository(application);
incomeRepository = new IncomeRepository(application);
combined = new DailyCombinedLiveData(expenseDao.getExpensesByDay(), incomeDao.getIncomesByDay());
}
public LiveData<Pair<List<Expense>, List<Income>>> getExpensesAndIncomes() {
return combined;
}
我猜你想把它们结合起来,是吗?您将需要一个 MediatorLiveData,但是说您现在需要 Object 的人是错误的。你需要的是 MediatorLiveData<Pair<List<Expense>, List<Income>>>
.
public class CombinedLiveData extends MediatorLiveData<Pair<List<Expense>, List<Income>>> {
private List<Expense> expenses = Collections.emptyList();
private List<Income> incomes = Collections.emptyList();
public CombinedLiveData(LiveData<List<Expense>> ld1, LiveData<List<Income>> ld2) {
setValue(Pair.create(expenses, incomes));
addSource(ld1, expenses -> {
if(expenses != null) {
this.expenses = expenses;
}
setValue(Pair.create(expenses, incomes));
});
addSource(ld2, incomes -> {
if(incomes != null) {
this.incomes = incomes;
}
setValue(Pair.create(expenses, incomes));
});
}
}
您可以使它成为通用的,它是 combineLatest
的实现,用于使用 2-arity (Pair) 的元组的两个 LiveData。
编辑: 像这样:
public class CombinedLiveData2<A, B> extends MediatorLiveData<Pair<A, B>> {
private A a;
private B b;
public CombinedLiveData2(LiveData<A> ld1, LiveData<B> ld2) {
setValue(Pair.create(a, b));
addSource(ld1, a -> {
if(a != null) {
this.a = a;
}
setValue(Pair.create(a, b));
});
addSource(ld2, b -> {
if(b != null) {
this.b = b;
}
setValue(Pair.create(a, b));
});
}
}
请注意,在这种情况下我无法将 Collections.emptyList()
设置为 A
和 B
的初始值,您将需要检查 null
s当您访问该对中的数据时。
编辑: 您可以使用库 https://github.com/Zhuinden/livedata-combinetuple-kt (Kotlin) or https://github.com/Zhuinden/livedata-combineutil-java/ (Java) 做同样的事情。
而不是让 class 添加 2 个实时数据,另一个 class 添加 3 个实时数据,等等。我们可以使用更抽象的方式,我们可以添加尽可能多的实时数据我们想要。
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
/**
* CombinedLiveData is a helper class to combine results from multiple LiveData sources.
* @param liveDatas Variable number of LiveData arguments.
* @param combine Function reference that will be used to combine all LiveData data.
* @param R The type of data returned after combining all LiveData data.
* Usage:
* CombinedLiveData<SomeType>(
* getLiveData1(),
* getLiveData2(),
* ... ,
* getLiveDataN()
* ) { datas: List<Any?> ->
* // Use datas[0], datas[1], ..., datas[N] to return a SomeType value
* }
*/
class CombinedLiveData<R>(vararg liveDatas: LiveData<*>,
private val combine: (datas: List<Any?>) -> R) : MediatorLiveData<R>() {
private val datas: MutableList<Any?> = MutableList(liveDatas.size) { null }
init {
for(i in liveDatas.indices){
super.addSource(liveDatas[i]) {
datas[i] = it
value = combine(datas)
}
}
}
}
在 kotlin 中创建了这个扩展函数
fun <A, B> LiveData<A>.zipWith(stream: LiveData<B>): LiveData<Pair<A, B>> {
val result = MediatorLiveData<Pair<A, B>>()
result.addSource(this) { a ->
if (a != null && stream.value != null) {
result.value = Pair(a, stream.value!!)
}
}
result.addSource(stream) { b ->
if (b != null && this.value != null) {
result.value = Pair(this.value!!, b)
}
}
return result
}