【问题标题】:LiveData List doesn't update when updating database更新数据库时 LiveData 列表不更新
【发布时间】:2018-02-09 02:21:10
【问题描述】:

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

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

在下面的 sn-p 中,您可以假设 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:我偶然发现了THIS 帖子,它讨论了一个类似的问题,但是由于我目前根本没有使用 DI,而只使用了一个 formrepository 实例(它只关联了一个 formDao 实例)我不要认为这是同一个问题。

【问题讨论】:

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


    【解决方案1】:

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

    还记得我说过“不要担心同步方法”吗?嗯...原来有一些问题,这进一步延迟了解决方案。

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

    @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,但也许你有类似的问题。如果是这样,请务必在此处发表评论:)

    【讨论】:

    • 你拯救了我的一天
    【解决方案2】:

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

    => 为此使用单例

    【讨论】:

    • 是的,这就是答案。 @Update 有效,@Query 和 UPDATE 查询有效。它只是有不同的数据库实例导致问题。请参阅 medium.com/@BladeCoder/… 了解有关单例的精彩 kotlin 帖子(带有上下文,房间数据库需要)
    【解决方案3】:

    我和你有类似的问题 --> LiveData is not updating its value after first call

    不要使用 LiveData,而是使用 MutableLiveData 并将 MutableLiveData&lt;List&lt;Form&gt;&gt; 对象传递给 Repository 并对列表的新内容执行 setValuepostValue

    根据我的经验,这并不多,显然观察者也与您首先分配的对象相关联,并且必须对该对象进行每次更改。

    【讨论】:

    • 我对使用你的方法犹豫不决,因为这意味着如果返回 LiveData,当 Room 明确允许在主线程上进行此类操作时,这意味着将对我的存储库的所有调用包装在某个 asynctask 或类似的东西中。在阅读了您问题中的所有 cmets/聊天消息后,我觉得很奇怪,那个房间的行为方式与您的想法一样,即使您似乎也是如此如果真的没有其他选择,我会接受您的回答并做那样。但也许有人可以更深入地了解这个问题,并找到一种直接从 dao 返回 LiveData 的方法:)
    • 我也很喜欢,因为这种行为有点奇怪:)
    • 当其他一些服务更改数据库值时,这种方法是否会更新 UI?因为是的,如果您只在调用存储库的 get(...) 方法时刷新值,那没问题,但是如果例如 ContentProvider 将某些内容插入到数据库中,我认为 UI 不会显示更改直到下一次调用 get(...)。在这里谈论您的链接问题代码
    • 您可能是对的,但我遵循了developer.android.com/topic/libraries/architecture/guide.html 中的示例,这就是他们在那里解释的内容。
    • 根据该链接中提供的信息,我认为我没有做错任何事情。我的想法是我认为谷歌提供的信息在这一点上是不够的,也许是因为这仍然是 alpha
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-17
    • 2020-09-02
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多