android - 更新数据库时 LiveData 列表不更新

标签 android observable android-room android-architecture-components android-livedata

我目前正在重构遗留代码以使用 Android 架构组件并在一种存储库模式中设置房间数据库和 volley 请求。 因此表示/领域层要求存储库获取 LiveData-Objects 以观察或告诉他与服务器同步,之后删除旧的数据库条目并从服务器重新获取所有当前条目。

我已经为同步部分编写了测试,所以我确信对象已正确获取并插入到数据库中。但是当编写一个测试来观察那个数据库表的条目时(并测试对象是否被正确保存以及在将它们放入数据库之前需要完成的所有事情)我正在观察的 LiveData> 没有被触发。

在下面的代码 fragment 中,您可以假设 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 代码(数据库是按照您对 room 的期望实现的):

  @Query("SELECT * FROM form")
  LiveData<List<Form>> getAllForms();

很可能是我对 LiveData 组件不了解,因为这是我第一次使用它们,所以我可能从根本上犯了错误。

非常感谢您的每一点帮助:)

PS:我偶然发现了THIS post,它讨论了一个类似的问题,但由于我目前根本没有使用 DI,只使用了 formrepository 的一个实例(它只有一个 formDao 实例相关联),我认为这不是同一个问题。

最佳答案

好的,所以我找到了解决方案,虽然我不知道为什么会这样。

还记得我说过“不要担心同步方法”吗?好吧……事实证明它有一些问题,这进一步延迟了解决方案。

我认为最重要的错误是当网络响应进来时更新数据库中对象的方法。 我曾经打电话

@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 - 更新数据库时 LiveData 列表不更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45976169/

相关文章:

java - 更改 fragment 中的 ActionBar 标题

html - 从自定义包中加载聚合物元素

android - 使用 Room Persistence Library 插入多个表

java - Room 不存储数据

android - Room 数据库中的 FOREIGN KEY 约束失败(代码 787)

android - 使用样式 Theme.Sherlock 时找不到资源

android - 如何计算两个位置之间的距离?

java - 根据变量的值启用或禁用按钮

android - Xamarin 安卓 : Convert PendingResult parameter to SubmitScoreResult

angular - HttpParams 与 Put 和 Post 一起使用将返回类型更改为 Angular 6 中的 Observable<HttpEvent<T>>