0

我正在重構遺留代碼以使用Android Architecture Components,並在一種存儲庫模式中設置房間數據庫和排空請求。 因此,演示文稿/域層會要求存儲庫讓LiveData-Objects觀察或告訴他與服務器同步,然後刪除舊的數據庫條目並從服務器中重新提取所有當前數據條目。更新數據庫時,LiveData列表不更新

我已經編寫了同步部分的測試,所以我相信,對象會被正確提取並插入數據庫。但是當編寫一個測試來觀察那個db表的條目(並且測試這些對象是否正確保存了所有需要在將它們放入db之前完成的事情)時,LiveData>我正在觀察,不會被觸發。

在下面的代碼片段中,您可以假設synchronizeFormsWithServer(...)方法確實工作正常,並且正在異步執行數據庫操作。它包含從db中刪除所有不在從服務器獲取的Forms列表中存在的所有Form對象並插入所有新的Form對象的操作。由於在測試開始時的數據庫是空的這不應該的問題,許多

測試將觀察者不會被觸發:

@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代碼(數據庫實現你怎麼倒是前從房間)PECT它:

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

它很可能是,我不明白一些關於LiveData成分,因爲這種使用它們是我第一次,所以也許我有某種根本性錯誤。

幫助每一位非常感謝:)

PS:我碰到THIS後,討論了類似的問題,迷迷糊糊的,但因爲我目前不是在所有使用DI,只需使用的單一實例formrepository(它只有一個formDao關聯的實例)我不認爲這是同一個問題。

回答

1

好吧,所以我找到了解決方案,儘管我不知道,爲什麼它的行爲如此。

記得當我說「不用擔心同步方法」嗎?那麼......事實證明它有一些錯誤,這進一步推遲了解決方案。

我覺得最重要的錯誤是,以更新數據庫中的對象,當網絡反應過來的方法。 我習慣叫

@Update 
void update(Form form) 

在DAO,這對於不明原因沒有按」觸發LiveData-Observer。所以,我把它改成

@Insert(onConflict = OnConflictStrategy.REPLACE) 
void insert(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,但也許你有類似的問題。如果是這樣,請務必在這裏發表評論:)

1

我有一個類似的問題與你 - >LiveData is not updating its value after first call

而不是使用LiveData使用MutableLiveData和MutableLiveData<List<Form>>對象傳遞到存儲庫並做setValue或列表的新內容postValue的。

從我的經驗來看,這並不是很多,顯然觀察者是連接到你首先分配它的對象,並且每一個改變都必須完成。

+0

我很猶豫要使用你的方法,因爲這意味着在一些asynctask或類似的東西中將所有調用包裝到我的倉庫時,Room明確允許在主線程上執行這些操作如果LiveData被返回。 在閱讀您問題中的所有評論/聊天消息之後,我發現它非常奇怪,那個房間的行爲與您的想法相同,即使您認爲是這樣的情況。 如果確實沒有其他選項,我會接受您的答案並這樣做。但也許有人可以更清楚地瞭解這個問題,並找到一種方法,直接從dao返回LiveData :) –

+0

我也很喜歡,因爲它有點奇怪,這表現爲這種方式:) – joao86

+0

這種方法甚至會其他服務更改了數據庫值時更新UI? 因爲是的,如果只在調用存儲庫的get(...)方法時才刷新值,但是如果ContentProvider將某些內容插入到數據庫中,我不認爲UI將顯示直到下一次得到(...)被調用。 在這裏談論你的鏈接問題代碼 –

0

對不起,沒有評論您的文章,我沒有必要的聲望做,但我面臨與LiveData相同的問題。特別是當我的LiveData觀察者是LifecycleActivity或LifecycleFragment的一部分時,一切都很好。但是當我試圖從documentation提議的AppCompatActivity中觀察我的LiveData時,我沒有收到數據更改的事件。我在alpha8和alpha9上都觀察到這種行爲

+0

正如我在我接受的答案中所述,這是一個更新問題(我認爲)。但是,當我嘗試使用實際的LifeCycleOwner(由AppCompatActivity綁定)觀察LiveData時,我會記住您的答案。 –