更新数据库时 LiveData 列表不更新
LiveData List doesn't update when updating database
我目前正在重构遗留代码以使用 Android 架构组件并在一种存储库模式中设置房间数据库和 volley 请求。
因此 presentation/domain 层要求存储库获取 LiveData-Objects 以观察或告诉他与服务器同步,之后删除旧的数据库条目并从服务器重新获取所有当前条目。
我已经为同步部分编写了测试,所以我确信对象已正确获取并插入到数据库中。但是当编写一个测试来观察那个数据库的条目时 table (并测试对象是否正确保存以及在将它们放入数据库之前需要完成的所有事情)我正在观察的 LiveData> 没有被触发。
在下面的代码片段中,您可以假设 synchronizeFormsWithServer(...) 方法确实正常工作并且正在异步执行数据库操作。它包含从数据库中删除所有不存在于从服务器获取的表单列表中的表单对象的操作,并插入所有新的表单对象。因为在测试开始时数据库是空的,所以这无关紧要
观察者未被触发的测试:
@Test
public void shouldSaveFormsFromServerIntoDb() throws Exception
{
Lifecycle lifecycle = Mockito.mock(Lifecycle.class);
when(lifecycle.getCurrentState()).thenReturn(Lifecycle.State.RESUMED);
LifecycleOwner owner = Mockito.mock(LifecycleOwner.class);
when(owner.getLifecycle()).thenReturn(lifecycle);
final CountDownLatch l = new CountDownLatch(19);
formRepository.allForms().observe(owner, formList ->
{
if (formList != null && formList.isEmpty())
{
for (Form form : formList)
{
testForm(form);
l.countDown();
}
}
});
formRepository.synchronizeFormsWithServer(owner);
l.await(2, TimeUnit.MINUTES);
assertEquals(0, l.getCount());
}
FormRepository代码:
@Override
public LiveData<List<Form>> allForms()
{
return formDatastore.getAllForms();
}
数据存储:
@Override
public LiveData<List<Form>> getAllForms()
{
return database.formDao().getAllForms();
}
formDao 代码(数据库是按照您期望的方式实现的):
@Query("SELECT * FROM form")
LiveData<List<Form>> getAllForms();
很可能是,我对 LiveData-Components 不太了解,因为这是我第一次使用它们,所以我可能从根本上犯了错误。
非常感谢您的每一点帮助:)
PS:我偶然发现了 post,它讨论了一个类似的问题,但由于我目前根本没有使用 DI,只是使用了formrepository(只有一个 formDao 实例关联)我不认为这是同一个问题。
我和你有类似的问题 -->
不使用 LiveData,而是使用 MutableLiveData 并将 MutableLiveData<List<Form>>
对象传递给存储库,并对列表的新内容执行 setValue
或 postValue
。
根据我的经验,这并不多,显然观察者也连接到您首先分配给它的对象,并且必须对该对象进行每次更改。
好的,所以我找到了解决方案,虽然我不知道为什么会这样。
还记得我说过 "don't worry about the synchronize method" 吗?好吧...事实证明它有一些问题,这进一步延迟了解决方案。
我认为最重要的错误是当网络响应进来时更新数据库中对象的方法。
我曾经打电话给
@Update
void update(Form form)
在 dao 中,由于未知原因,它不会触发 LiveData-Observer。所以我把它改成了
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(Form form);
完成此操作后,我可以像
一样简单地从我的存储库中获取 Form-LiveData
LiveData<List<Form>> liveData = formRepository.allForms();
那就照常订阅吧。
之前失败的测试现在看起来像这样:
@Test
public void shouldSaveFormsFromServerIntoDb() throws Exception
{
Lifecycle lifecycle = Mockito.mock(Lifecycle.class);
when(lifecycle.getCurrentState()).thenReturn(Lifecycle.State.RESUMED);
LifecycleOwner owner = Mockito.mock(LifecycleOwner.class);
when(owner.getLifecycle()).thenReturn(lifecycle);
final CountDownLatch l = new CountDownLatch(19);
final SortedList<Form> sortedForms = new SortedList<Form>(Form.class, new SortedList.Callback<Form>()
{
@Override
public int compare(Form o1, Form o2)
{
return o1.getUniqueId().compareTo(o2.getUniqueId());
}
@Override
public void onChanged(int position, int count)
{
Log.d(LOG_TAG, "onChanged: Form at position " + position + " has changed. Count is " + count);
for (int i = 0; i < count; i++)
{
l.countDown();
}
}
@Override
public boolean areContentsTheSame(Form oldItem, Form newItem)
{
return (oldItem.getContent() != null && newItem.getContent() != null && oldItem.getContent().equals(newItem.getContent())) || oldItem.getContent() == null && newItem.getContent() == null;
}
@Override
public boolean areItemsTheSame(Form item1, Form item2)
{
return item1.getUniqueId().equals(item2.getUniqueId());
}
@Override
public void onInserted(int position, int count)
{
}
@Override
public void onRemoved(int position, int count)
{
}
@Override
public void onMoved(int fromPosition, int toPosition)
{
}
});
LiveData<List<Form>> ld = formRepository.allForms();
ld.observe(owner, formList ->
{
if (formList != null && !formList.isEmpty())
{
Log.d(LOG_TAG, "shouldSaveFormsFromServerIntoDb: List contains " + sortedForms.size() + " Forms");
sortedForms.addAll(formList);
}
});
formRepository.synchronizeFormsWithServer(owner);
l.await(2, TimeUnit.MINUTES);
assertEquals(0, l.getCount());
}
我知道将从服务器获取恰好 19 个表单,然后每个表单都会更改一次(第一次我加载一个包含所有表单的列表并减少数据,第二次我从服务器加载每个项目再次用具有更多数据的新值替换数据库中的旧值。
我不知道这是否对你有帮助@joao86 但也许你有类似的问题。如果是这样,请确保在这里发表评论:)
您必须在所有地方使用相同的数据库实例。
=> 为此使用单例
我目前正在重构遗留代码以使用 Android 架构组件并在一种存储库模式中设置房间数据库和 volley 请求。 因此 presentation/domain 层要求存储库获取 LiveData-Objects 以观察或告诉他与服务器同步,之后删除旧的数据库条目并从服务器重新获取所有当前条目。
我已经为同步部分编写了测试,所以我确信对象已正确获取并插入到数据库中。但是当编写一个测试来观察那个数据库的条目时 table (并测试对象是否正确保存以及在将它们放入数据库之前需要完成的所有事情)我正在观察的 LiveData> 没有被触发。
在下面的代码片段中,您可以假设 synchronizeFormsWithServer(...) 方法确实正常工作并且正在异步执行数据库操作。它包含从数据库中删除所有不存在于从服务器获取的表单列表中的表单对象的操作,并插入所有新的表单对象。因为在测试开始时数据库是空的,所以这无关紧要
观察者未被触发的测试:
@Test
public void shouldSaveFormsFromServerIntoDb() throws Exception
{
Lifecycle lifecycle = Mockito.mock(Lifecycle.class);
when(lifecycle.getCurrentState()).thenReturn(Lifecycle.State.RESUMED);
LifecycleOwner owner = Mockito.mock(LifecycleOwner.class);
when(owner.getLifecycle()).thenReturn(lifecycle);
final CountDownLatch l = new CountDownLatch(19);
formRepository.allForms().observe(owner, formList ->
{
if (formList != null && formList.isEmpty())
{
for (Form form : formList)
{
testForm(form);
l.countDown();
}
}
});
formRepository.synchronizeFormsWithServer(owner);
l.await(2, TimeUnit.MINUTES);
assertEquals(0, l.getCount());
}
FormRepository代码:
@Override
public LiveData<List<Form>> allForms()
{
return formDatastore.getAllForms();
}
数据存储:
@Override
public LiveData<List<Form>> getAllForms()
{
return database.formDao().getAllForms();
}
formDao 代码(数据库是按照您期望的方式实现的):
@Query("SELECT * FROM form")
LiveData<List<Form>> getAllForms();
很可能是,我对 LiveData-Components 不太了解,因为这是我第一次使用它们,所以我可能从根本上犯了错误。
非常感谢您的每一点帮助:)
PS:我偶然发现了
我和你有类似的问题 -->
不使用 LiveData,而是使用 MutableLiveData 并将 MutableLiveData<List<Form>>
对象传递给存储库,并对列表的新内容执行 setValue
或 postValue
。
根据我的经验,这并不多,显然观察者也连接到您首先分配给它的对象,并且必须对该对象进行每次更改。
好的,所以我找到了解决方案,虽然我不知道为什么会这样。
还记得我说过 "don't worry about the synchronize method" 吗?好吧...事实证明它有一些问题,这进一步延迟了解决方案。
我认为最重要的错误是当网络响应进来时更新数据库中对象的方法。 我曾经打电话给
@Update
void update(Form form)
在 dao 中,由于未知原因,它不会触发 LiveData-Observer。所以我把它改成了
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(Form form);
完成此操作后,我可以像
一样简单地从我的存储库中获取 Form-LiveDataLiveData<List<Form>> liveData = formRepository.allForms();
那就照常订阅吧。 之前失败的测试现在看起来像这样:
@Test
public void shouldSaveFormsFromServerIntoDb() throws Exception
{
Lifecycle lifecycle = Mockito.mock(Lifecycle.class);
when(lifecycle.getCurrentState()).thenReturn(Lifecycle.State.RESUMED);
LifecycleOwner owner = Mockito.mock(LifecycleOwner.class);
when(owner.getLifecycle()).thenReturn(lifecycle);
final CountDownLatch l = new CountDownLatch(19);
final SortedList<Form> sortedForms = new SortedList<Form>(Form.class, new SortedList.Callback<Form>()
{
@Override
public int compare(Form o1, Form o2)
{
return o1.getUniqueId().compareTo(o2.getUniqueId());
}
@Override
public void onChanged(int position, int count)
{
Log.d(LOG_TAG, "onChanged: Form at position " + position + " has changed. Count is " + count);
for (int i = 0; i < count; i++)
{
l.countDown();
}
}
@Override
public boolean areContentsTheSame(Form oldItem, Form newItem)
{
return (oldItem.getContent() != null && newItem.getContent() != null && oldItem.getContent().equals(newItem.getContent())) || oldItem.getContent() == null && newItem.getContent() == null;
}
@Override
public boolean areItemsTheSame(Form item1, Form item2)
{
return item1.getUniqueId().equals(item2.getUniqueId());
}
@Override
public void onInserted(int position, int count)
{
}
@Override
public void onRemoved(int position, int count)
{
}
@Override
public void onMoved(int fromPosition, int toPosition)
{
}
});
LiveData<List<Form>> ld = formRepository.allForms();
ld.observe(owner, formList ->
{
if (formList != null && !formList.isEmpty())
{
Log.d(LOG_TAG, "shouldSaveFormsFromServerIntoDb: List contains " + sortedForms.size() + " Forms");
sortedForms.addAll(formList);
}
});
formRepository.synchronizeFormsWithServer(owner);
l.await(2, TimeUnit.MINUTES);
assertEquals(0, l.getCount());
}
我知道将从服务器获取恰好 19 个表单,然后每个表单都会更改一次(第一次我加载一个包含所有表单的列表并减少数据,第二次我从服务器加载每个项目再次用具有更多数据的新值替换数据库中的旧值。
我不知道这是否对你有帮助@joao86 但也许你有类似的问题。如果是这样,请确保在这里发表评论:)
您必须在所有地方使用相同的数据库实例。
=> 为此使用单例