更新数据库时,LiveData List不会更新

Ant*_*ell 2 android observable android-room android-livedata android-architecture-components

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

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

在下面的代码片段中,您可以假设,synchronizeFormsWithServer(...)方法可以正常工作,并且异步执行数据库操作.它包含从db中删除所有Form-Objects的操作,这些操作从服务器获取的Forms列表中不存在并插入所有新的Form-Objects.因为在测试开始时数据库是空的,所以这应该不重要

观察者未被触发的测试:

  @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());
   }
Run Code Online (Sandbox Code Playgroud)

FormRepository代码:

  @Override
  public LiveData<List<Form>> allForms()
   {
    return formDatastore.getAllForms();
   }
Run Code Online (Sandbox Code Playgroud)

数据存储区:

  @Override
  public LiveData<List<Form>> getAllForms()
   {
    return database.formDao().getAllForms();
   }
Run Code Online (Sandbox Code Playgroud)

formDao代码(数据库实现了你从房间里期待它的方式):

  @Query("SELECT * FROM form")
  LiveData<List<Form>> getAllForms();
Run Code Online (Sandbox Code Playgroud)

很可能,我对LiveData-Components没有任何了解,因为这是我第一次使用它们,所以也许我得到了一些根本错误的东西.

非常感谢每一点帮助:)

PS:我偶然发现了这篇文章,讨论了一个类似的问题,但由于我现在根本没有使用DI而只使用formrepository的一个实例(只有一个formDao实例关联)我认为不是一样的问题.

Ant*_*ell 8

好的,所以我找到了解决方案,虽然我不知道,为什么它的表现如此.

还记得我说"不要担心同步方法"吗?好吧......事实证明它存在一些问题,这进一步推迟了解决方案.

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

@Update
void update(Form form)
Run Code Online (Sandbox Code Playgroud)

在dao中,由于未知原因不会触发LiveData-Observer.所以我改成了

@Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(Form form);
Run Code Online (Sandbox Code Playgroud)

执行此操作后,我可以从我的存储库中获取Form-LiveData一样简单

LiveData<List<Form>> liveData = formRepository.allForms();
Run Code Online (Sandbox Code Playgroud)

然后像往常一样订阅它.以前失败的测试现在看起来像这样:

  @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());
   }
Run Code Online (Sandbox Code Playgroud)

我知道将从服务器获取正好19个表单然后每个表单将被更改一次(第一次加载包含所有具有减少数据的表单的列表,并且第二次我再次从服务器加载每个项目替换旧值在具有更多数据的新值的数据库中).

我不知道这对你@ joao86是否有帮助,但也许你有类似的问题.如果是这样,请务必在这里发表评论:)

  • 你拯救了我的一天 (2认同)

Tob*_*ias 7

您必须在所有地方使用相同的数据库实例。

=> 为此使用单例