更新数据库时,LiveData列表不会更新 [英] LiveData List doesn't update when updating database

查看:1244
本文介绍了更新数据库时,LiveData列表不会更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我已经为同步部分编写了测试,所以可以肯定,对象已正确获取并插入到数据库中.但是,当编写测试以观察该数据库表的条目(并测试对象是否正确保存了所有内容,然后再将它们放入数据库中时,需要执行这些操作)时,我观察到的LiveData>不会被触发. /p>

在下面的代码段中,您可以假设syncnizeFormsWithServer(...)方法可以正常工作,并且正在异步执行数据库操作.它包含一些操作,这些操作将从db中删除所有不存在于从服务器获取的Form列表中的Form-Object,并插入所有新的Form-Object.由于测试开始时数据库为空,因此没关系

不触发观察者的测试:

  @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实例),所以我认为这不是同一个问题. /p>

解决方案

好,所以我找到了解决方案,尽管我不知道为什么会这样.

还记得我说过不用担心同步方法"吗?嗯...事实证明,这有很多问题,这进一步延误了解决方案.

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

@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个表单,然后每个表单都会更改一次(第一次加载包含减少数据的所有表单的列表,第二次从服务器加载每个项目时,再次替换db中的旧值,新值中包含更多数据).

我不知道这是否对您有帮助@ joao86,但也许您有类似的问题.如果是这样,请确保在此处评论:)

I'm currently refactoring legacy code to use Android Architecture Components and set up a room db and volley requests within a kind of repository pattern. So the presentation/domain layer asks the repository to get LiveData-Objects to observe or tell him to synchronize with the server, after which old db entries are deleted and all current ones refetched from the server.

I've written tests for the synchronization part, so I'm sure, that the objects get fetched and inserted to the database correctly. But when writing a test to observe the entries of that db table (and test if the objects were saved correctly with everything there needs to be done before putting them into db) the LiveData> I'm observing, doesn't get triggered.

In the following snippet you can assume, that the synchronizeFormsWithServer(...) method does work correctly and is performing database operations asynchronously. It contains operations which deletes all Form-Objects from the db which are not present in the list of Forms fetched from the server and inserts all new ones. Since at the start of the test the database is empty this shouldn't matter that much

The test in which the observer doesn't get triggered:

  @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());
   }

The FormRepository code:

  @Override
  public LiveData<List<Form>> allForms()
   {
    return formDatastore.getAllForms();
   }

The datastore:

  @Override
  public LiveData<List<Form>> getAllForms()
   {
    return database.formDao().getAllForms();
   }

The formDao code (database is implemented how you'd expect it from room):

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

It may very well be, that I didn't understand something about the LiveData-Components, because this is my first time using them, so maybe I got something fundamentally wrong.

Every bit of help is very much appreciated :)

PS: I stumbled across THIS post, which discusses a similar issue, but since I'm currently not using DI at all and just use a single instance of the formrepository (which has only one instance of formDao associated) I don't think it's the same problem.

解决方案

Ok, so I found the solution, although I don't know, why it behaves that way.

Remember when I said "don't worry about the synchronize method"? Well... turns out there were a couple of things wrong with it, which delayed the solution further.

I think the most important error there was the method to update the objects in the database when the network response came in. I used to call

@Update
void update(Form form)

in the dao, which for unknown reasons doesn't trigger the LiveData-Observer. So I changed it to

@Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(Form form);

After doing this I could get the Form-LiveData from my repository as easy as

LiveData<List<Form>> liveData = formRepository.allForms();

Then subscribe to it as usual. The previously failed test looks like this now:

  @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());
   }

I know that exactly 19 Forms will get fetched from the server and then every Form will get changed once (first time I load a list containing all Forms with reduced data, and the second time I load every item from the server again replacing the old value in the db with the new value with more data).

I don't know if this will help you @joao86 but maybe you have a similar issue. If so, please make sure to comment here :)

这篇关于更新数据库时,LiveData列表不会更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆