title: Room Database doesn't run my implemented transaction on background thread
body: <p><strong>This question is a solution I've tried for my other <a href="https://stackoverflow.com/questions/69289074/recyclerview-adapter-depends-on-two-sources-of-data">question</a>, so if you have a solution to the first one that avoids this question problems, I'm all ears.</strong></p>
  <p>So I have this method in Dao (<code>getPageCombinedData</code>) that is annotated with <code>@transaction</code> and should return a MediatorLiveData, I thought since MediatorLiveData is a subclass of LiveData, then Room will provide the necessary code to return it using background thread as quoted from its documentation.</p>
  <blockquote>
  <p>When Room queries return LiveData, the queries are automatically run asynchronously on a background thread.</p>
  </blockquote>
  <p>but instead I got the exception telling me that I'm running my query on Main Thread</p>
  <pre><code>java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
  </code></pre>
  <p>I firstly tried making this with an Executer on another thread but I found out that whenever the database gets updated, it will never reach my observer with the new data as my code looked like this</p>
  <p>my ViewModel code</p>
  <pre><code>public LiveData&lt;PagesCombinedData&gt; getPageCombinedData(){
      MediatorLiveData&lt;PagesCombinedData&gt;dataLiveObj = new MediatorLiveData&lt;&gt;();
      executor.execute(()-&gt;{
                  UserPageRelation userRelation = scheduleDB.userDao().getAllUserPages().getValue();
                  dataLiveObj .postValue(scheduleDB.userDao().getPagesCombinedData().getValue());
              });
  return dataLiveObj;
  }
  </code></pre>
  <p>where that way will only update the returned LiveData only once when the thread finish executing and whenever the database gets updated, my observer in UI Fragment will never know about it.</p>
  <p>so now I don't know how should I return this Mediator in order for my UI to observe it and update the UI whenever data is updated in the database.</p>
  <p>My Fragment's code that should observe the Mediator</p>
  <pre><code>pagesViewModel.getPageCombinedData().observe(getViewLifecycleOwner(), pagesCombinedData -&gt; {
              pagesAdapter.setUserPages(pagesCombinedData.getUserEntities());
              pagesAdapter.setPageEntities(pagesCombinedData.getPageEntities());
              pagesAdapter.notifyDataSetChanged();
  });
  </code></pre>
  <p>My PagesViewModel Code :</p>
  <pre><code>public LiveData&lt;PagesCombinedData&gt; getPageCombinedData(){
          return scheduleDB.userDao().getPagesCombinedData();
  }
  </code></pre>
  <p>my UserDao code that should construct the Mediator Object :</p>
  <pre><code>@Dao
  public abstract class UserDao {
      @Transaction
      public MediatorLiveData&lt;PagesCombinedData&gt; getPagesCombinedData (){
          MediatorLiveData &lt;PagesCombinedData&gt; dataMediator  = new MediatorLiveData&lt;&gt;();
          LiveData&lt;List&lt;PageEntity&gt;&gt; value1 = getAllPages();
          LiveData&lt;UserPageRelation&gt; value2 = getAllUserPages();
          dataMediator.addSource(value1, value -&gt; dataMediator.setValue(combineData(value1,value2)));
          dataMediator.addSource(value2, value -&gt; dataMediator.setValue(combineData(value1,value2)));
          return dataMediator;
      }
      private PagesCombinedData combineData(LiveData&lt;List&lt;PageEntity&gt;&gt; pages,LiveData&lt;UserPageRelation&gt; userPages ){
          return new PagesCombinedData(pages.getValue()==null?new ArrayList&lt;&gt;():pages.getValue()
                  ,userPages.getValue()==null ?new ArrayList&lt;&gt;():userPages.getValue().getUserPages());
      }
      @Query(&quot;Select * from page&quot;)
      public abstract LiveData&lt;List&lt;PageEntity&gt;&gt; getAllPages ();
      @Transaction
      @Query(&quot;Select * from user limit 1&quot;)
      public abstract LiveData&lt;UserPageRelation&gt; getAllUserPages ();   
  }
  </code></pre>
  <hr />
  <h2>Update</h2>
  <p>tried to move my code into the ViewModel but it tells me that I can't addsource on a background thread because it uses observeForever -_-*</p>
  <p>the code I tried in  my ViewModel</p>
  <pre><code>private MediatorLiveData&lt;PagesCombinedData&gt; pagesCombinedData;
  private ExecutorService executor ;
  public LiveData&lt;PagesCombinedData&gt; getPageCombinedData(){
          if (pagesCombinedData==null){
              pagesCombinedData = new MediatorLiveData&lt;&gt;();
              pagesCombinedData.setValue(new PagesCombinedData());
          }
          executor.execute(()-&gt;{
              LiveData&lt;List&lt;PageEntity&gt;&gt; value1 = scheduleDB.userDao().getAllPages();
              LiveData&lt;UserPageRelation&gt; value2 = scheduleDB.userDao().getAllUserPages();
              pagesCombinedData.addSource(value1, value -&gt; pagesCombinedData.setValue(combineData(value1,value2)));
              pagesCombinedData.addSource(value2, value -&gt; pagesCombinedData.setValue(combineData(value1,value2)));
          });
          return pagesCombinedData;
      }
  </code></pre>
  <p>the exception I got (line 59 is <code>addSource</code> line)</p>
  <pre><code>java.lang.IllegalStateException: Cannot invoke observeForever on a background thread
          at androidx.lifecycle.LiveData.assertMainThread(LiveData.java:487)
          at androidx.lifecycle.LiveData.observeForever(LiveData.java:224)
          at androidx.lifecycle.MediatorLiveData$Source.plug(MediatorLiveData.java:141)
          at androidx.lifecycle.MediatorLiveData.addSource(MediatorLiveData.java:96)
          at com.example.pretest.schedule.pages.PagesViewModel.lambda$getPageCombinedData$2$PagesViewModel(PagesViewModel.java:59)
          at com.example.pretest.schedule.pages.-$$Lambda$PagesViewModel$Z3rbrO9SPtD8Pwpbh3mfk47DjVE.run(lambda)
          at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
          at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
          at java.lang.Thread.run(Thread.java:841)
  </code></pre>
  <p>just tell me plain and simple, is what I'm trying to achieve impossible ?</p>