I have a situation which I haven't been able to solve via RxJava2 operators.
I have a list of "Matches" I retrieve from Room. Here is my Match POJO.
public class Match {
#PrimaryKey
private int id;
#Ignore
Team rivalTeam;
}
Here is my Dao for this table.
#Dao
public interface MatchDao {
#Query("select * from `match` where homeTeamId= :homeTeamId")
Single<List<Match>> getMatchesByTeamId(int homeTeamId);
}
My target is to create an observable which will pull out these matches and then merge it with an observable which would be returning the rivalTeam.
Here is my Team Dao
#Dao
public interface TeamDao {
#Query("select * from teams where id = :teamId")
Single<Team> getTeamById(int teamId);
}
What I have achieved is this.
private Single<List<Match>> fetchMatches(Team team) {
return matchDao.
getMatchesByTeamId(team.getId()).toObservable().
flatMapIterable(matches -> matches).
map(match -> teamDao.getTeamById(**match.getRivalId()**).toObservable() // this doesn't work ofcourse since map can't return an observable.);
}
I know I have to perhaps zip both observables , but how would I go about doing that since the second observable is dependent on the first?.
If zip would have worked on a single source , I would have been able to do a
match.setRivalTeam(team) in the zipper method.
Hints?
Related
I am using Room and I have written the Dao class as follows.
Dao
#Dao
interface ProjectDao {
#Query("SELECT * FROM project")
fun getAllProjects(): Flow<List<Project>>
...etc
}
and this Flow is converted to LiveData through asLiveData() in ViewModel and used as follows.
ViewModel
#HiltViewModel
class MainViewModel #Inject constructor(
private val projectRepo: ProjectRepository
) : ViewModel() {
val allProjects = projectRepo.allProjects.asLiveData()
...
}
Activity
mainViewModel.allProjects.observe(this) { projects ->
adapter.submitList(projects)
...
}
When data change occurs, RecyclerView is automatically updated by the Observer. This is a normal example I know.
However, in my project data in Flow, what is the most correct way to get the data of the position selected from the list?
I have already written code that returns a value from data that has been converted to LiveData, but I think there may be better code than this solution.
private fun getProject(position: Int): Project {
return mainViewModel.allProjects.value[position]
}
Please give me suggestion
Room has in built support of flow.
#Dao
interface ProjectDao {
#Query("SELECT * FROM project")
fun getAllProjects(): Flow<List<Project>>
//lets say you are saving the project from any place one by one.
#Insert()
fun saveProject(project :Project)
}
if you call saveProject(project) from any place, your ui will be updated automatically. you don't have to make any unnecessary call to update your ui. the moment there is any change in project list, flow will update the ui with new dataset.
to get the data of particular position, you can get it from adapter list. no need to make a room call.
I am posting this because same issue is already there on stackoverflow but no solution on this. I am using Room library for db operations. I have created data classes with #Embedded and #Relation with other tables. Now the issue is when I put join queries with multiple where conditions on main as well as joined tables, it returns all/incorrect data of joined tables. This shows it ignores the conditions I have put in a DAO class query. Important thing is when I run the same query on a database externally (using stetho in chrome) it works as expected. Please help me with this as this is highly critical issue. Room version: 2.4.0
This is the data class:
data class ProductFull{
#Embedded val product: ProductMaster,
#Relation(
entity = ProductZone::class,
parentColumn = "productId",
entityColumn = "productId",
)
var productZone: ProductZone? = null,
}
This is the DAO class method:
#Query("select * from ProductMaster as pm inner join ProductZone as pz on pz.productId = pm.productId where pz.zoneId = 3")
abstract suspend fun getTempProducts(): List<ProductFull>
Above query returns data in productZone field of data class having zoneId = 1. Whereas it should only return zones having zoneId = 3.
When using #Relation room builds the underlying query(ies) to get ALL children (ProductZones) for each parent (ProductMaster) that the query selects.
A convenience annotation which can be used in a POJO to automatically fetch relation entities. When the POJO is returned from a query, all of its relations are also fetched by Room.
https://developer.android.com/reference/kotlin/androidx/room/Relation
A get-around is two have 2 dao's one that selects the parents and the other that selects the required children and a function (use an abstract class rather than an interface for the Dao's) that gets the parents using the first query and then for each parent gets the required children using the second query.
The function should be annotated with #Transaction, to allow this also annotate it with #Query("")
You would want something like:-
#Transaction
#Query("SELECT * FROM productmaster JOIN productzone on productmaster.productId = productzone.productId WHERE productzone.zoneId = 3")
abstract fun getTempProducts(): List<ProductFull>
#Query("SELECT * FROM productzone WHERE productId=:productId AND zoneId=3")
abstract fun getTempZone(productId: Long): ProductZone
#Transaction
#Query("")
fun buildFullProducts(): List<ProductFull> {
var rv = getTempProducts()
for (pf: ProductFull in rv) {
pf.productZone = getTempZone(pf.product.productId!!)
}
return rv
}
and use the buildFullProducts function to retrieve the list of ProductFull's
How can I do a room transaction across 2 different DAOs usin rxjava?
I have this code that I would like to use with Rxjava but I need it to return some kind of observable
#Transaction
fun insertStoreWithPictures(store: Store, pictures: List<StorePicture>) {
insertStore(store)
insertPictures(pictures)
}
The store DAO
#Dao
abstract public class store {
#Insert
Single<Long> insert(store entity);
}
The storePicture DAO
#Dao
abstract public class storePicture {
#Insert
Completable insert(storePicture... entity);
}
I think you can use zip or combine operator of RxJava. It would create an observable from an iterators observable source.
Best example you can follow to achieve the same - https://blog.mindorks.com/understanding-rxjava-zip-operator-with-example
I am using Component libraries in my android app. in some case it is needed to use Livedata and observe its data but sometimes I just want to get some ordinary list not Livedata , How can I do that? query DB in simple way
p.s : I use getValue() but it returns null
Use query like this in DAO:
#Query("SELECT * FROM TABLE_NAME")
fun getListOfData(): List<Data>?
this will provide you list of data from your table, just like the select query passed in #Query parameter.
Edit:
When calling from main thread, you can use handler to do your job in background like below:
//Method from where you want your data from Db.
fun getMyList() {
Thread {
(your db object).(your dao).getListOfData()
}.start()
}
or you can allow your db to execute on main thread when building your room db like below (Though i wouldn't recommend this) :
Room.databaseBuilder(
...
)
.allowMainThreadQueries()
.build()
You can simply write query in your Dao which has return type as List and call from your ViewModel where you need those data.
Example :
//YourDao
#Query("SELECT * FROM YourTable")
List<YourModel> getAllYourTableData();
//YourRepo
public static List<YourModel> getAllData(){
return getYourModelDao.getAllYourTableData();
}
//Your ViewModel
public void someFunctionWhereYouNeedNormalData(){
//assign to list
YourRepo.getAllData();
}
Assuming you have knowledge about repo pattern in android arch components.
What i want to achieve is to wrap a specific type for room database query result
The same as we doing now with android.arch.persistence.room:rxjava2 library that helps to expose RxJava2 Types like Observables and Flowables in the result
example :
abstract Single<User> find(String id);
Is there any specific Adapter or a way that can help to acheive this wrapping ? or create and artifact same as android.arch.persistence.room:rxjava2
for Coroutines as an example
Add implementation "android.arch.persistence.room:rxjava2:1.1.0" to you build.gradle.
https://developer.android.com/training/data-storage/room/accessing-data#query-rxjava
#Dao
public interface MyDao {
#Query("SELECT * from user where id = :id LIMIT 1")
public Flowable<User> loadUserById(int id);
}