0

現在、Android Architecture Componentsを使用するためにレガシーコードをリファクタリングしています。一種のリポジトリパターンでルームのdbとvolleyのリクエストを設定しています。 したがって、プレゼンテーション/ドメイン層は、LiveDataオブジェクトを取得してサーバーと同期するようにLiveDataオブジェクトを取得するようにリポジトリに依頼します。その後、古いdbエントリは削除され、現在のすべてのエントリがサーバーから再フェッチされます。データベースの更新時にLiveDataのリストが更新されない

私は同期部分のテストを書いたので、オブジェクトがフェッチされ、データベースに正しく挿入されると確信しています。しかし、そのdbテーブルのエントリを観察するためのテストを書くとき(そしてオブジェクトが正しく保存されているかどうかテストして、それらをdbに入れる前に行う必要があります)、LiveData>私は観察しています。

次のスニペットでは、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コード(あなたは元をいただきたいどのようにデータベースが実装されています)部屋からそれをPECT:

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

それは非常によく、これはそれらを使用して、私は初めてなので、多分私は根本的に間違って何かを得たので、私は、LiveData・コンポーネントについて何かを理解していなかったということであってもよいです。

ヘルプのすべてのビットは、非常に高く評価される:)

PSを:私は同様の問題を論じてTHISポスト、全体でつまずいたが、私は現在、すべてのDIを使用していないのでただの単一のインスタンスを使用しますformrepository(formDaoのインスタンスが1つしか関連付けられていない)は同じ問題だとは思わない。

答えて

1

オクラホマ、私は解決策を見つけましたが、わかりませんが、なぜそのように動作しますか?

私は「同期メソッドについて心配しないでください」と言いましたか?まあ...それにはいくつかの問題があったことが判明し、解決策がさらに遅れました。

私が最も重要なエラーネットワーク応答が入って​​来たときに、データベース内のオブジェクトを更新する方法があったと思います。 私は「未知の理由のためにdoesnのDAOに

@Update 
void update(Form form) 

を呼び出すために使用LiveData-Observerをトリガします。だから、私はその後、いつものようにそれに加入

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

ほど簡単では私のリポジトリからフォームLiveDataを得ることができ、これを行った後

@Insert(onConflict = OnConflictStrategy.REPLACE) 
void insert(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); 

    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フォームがサーバーからフェッチされますことを知っているし、その後、すべてのフォームが一度変更されます(最初の時間は、私が低減されたデータを持つすべてのフォームを含むリストを読み込みます2回目には、データベースからすべてのアイテムを再度ロードして、dbの古い値を新しい値で置き換えてより多くのデータを置き換えます)。

これが@ joao86に役立つかどうかは分かりませんが、おそらく同様の問題があります。もしそうなら、ここにコメントするようにしてください:)

1

私はあなたと同様の問題だった - その代わりLiveData使用MutableLiveDataを使用する>LiveData is not updating its value after first call

をしてリポジトリにMutableLiveData<List<Form>>オブジェクトを渡すと、リストの新しいコンテンツのsetValueまたはpostValueを行います。

これは私の経験ではあまりありませんが、オブザーバーは最初に割り当てたオブジェクトに接続されており、すべての変更をそのオブジェクトに対して行う必要があります。

+0

私はあなたのアプローチを使用することを躊躇しています。それは、ルームが明示的にメインスレッド上でそのような操作を許可しているときに、 LiveDataが返された場合。 あなたの質問にあるすべてのコメント/チャットメッセージを読んだ後、私はそれが非常に奇妙で、その部屋はあなたが思うように振る舞い、たとえそれが事実だと思われるとしても見つかりません 本当に他の選択肢がない場合は、そのようにしてください。しかし、おそらく誰かが問題にもっと光を当てて、DAOから直接LiveDataを返す方法を見つけることができます:) –

+0

これはあまりにも奇妙なので、私はこれがこのように動作するので嬉しいでしょう:) – joao86

+0

他のサービスがDB値を変更したときにUIを更新しますか? リポジトリのget(...)メソッドを呼び出すときに値をリフレッシュするだけで問題はありませんが、たとえばContentProviderが何かをDBに挿入すると、UIには表示されません次のTime get(...)が呼び出されるまで変更されます。 リンク先の質問コードについてここでお答えください –

0

あなたの投稿にコメントしていないと申し訳ありませんが、私はまだ必要な評判はありませんが、私はLiveDataで同じ問題に直面しています。具体的には、私のLiveDataオブザーバがLifecycleActivityまたはLifecycleFragmentの一部であるときに、すべてがうまくいきました。しかし、私はdocumentationから提案されたAppCompatActivityの中で私のLiveDataを観察しようとしたとき、私はデータ変更のイベントを得ていません。私はalpha8とalpha9の両方でこの動作を観察しています

+0

私が受け入れた回答で述べたように、DAOのアップデートの問題でした(私は思っています)。しかし、実際のLifeCycleOwnerをAppCompatActivityでバインドしてLiveDataを観察しようとすると、私はあなたの答えを念頭に置いていきます。 –

関連する問題