In Android sample codes/codelabs, Daos inside RoomDatabase are defined as
abstract fun genericDao(): GenericDao
and when you need to access the dao's methods, you call
database.genericDao().genericFun()
Why is it implemented like this, and not like
abstract val genericDao: GenericDao
database.genericDao.genericFun()
? Is it wrong to do it the second way?
Link to Codelab
Ok, i checked Decompiled bytecode and the only difference is that first implementation is named as
subscriptionStatusDao()
and the second one as
getSubscriptionStatusDao()
So basically, no difference at all.
Related
New to DI. Let's say there is an interface XYZ in a module ABC, which is being used by the main app project as a dependency. I want to inject that interface XYZ to the MainActivity in the main project. Please see below how I am trying.
ABC Module Contents
XYZ
interface XYZ {
fun init()
}
TestView class implementing interface
class TestView: XYZ {
override fun init(){
}
}
Main project contents
AppModule class
#Module
#InstallIn(SingletonComponent::class)
object AppModule {
#Provides
fun xyz(): XYZ = TestView()
}
MainActivity
#AndroidEntryPoint
class MainActivity : AppCompactActivity() {
#Inject lateinit var xyz : XYZ
override onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
xyz.init()
}
}
Please let me know if there is something wrong with this.
If I use the same interface for another class let's say TestView2 and use it in another activity in main project. Can I provide that view as well in the AppModule class? If yes How will I differentiate it from the first one as Both will be using the same interface?
Thanks in advance.
I'm not a senior dev, so take my words with a grain of salt ;)
Please let me know if there is something wrong with this.
Yes and no (see below)
It will work and some people prefer to provide an interface this way,
however it is better to use #Binds (it generates less code, which makes your app smaller and the build times are quicker)
you can find how to use it here
If I use the same interface for another class let's say TestView2 and use it in another activity in main project. Can I provide that view as well in the AppModule class? If yes How will I differentiate it from the first one as Both will be using the same interface?
If you create 2 provide methods which return the same type, dagger won't know which method to use to provide your dependency, that's why you can name your providers (using the #Named annotation), you can find more about it here
(also, just a comment: Using multiple activities in one application isn't really recommended anymore, and I'm personally against it)
I have been quite inquisitive on the reason why an abstract Dao method is used to access the methods in the the Dao interface in android room database
it is not just the Room, Retrofit and other libraries use this pattern too, it is called Programming to an Interface. Instead of just creating a concrete implementation you just specify the stuff you want to do and they provide you with an implementation that will behave as you requested.
For further study you can check this article: https://tuhrig.de/programming-to-an-interface/
This is the project I'm trying to understand. I'm trying to understand what goes after what in this project. What confuses me, is that getFeatures() call in ViewModel. It seems that it calls an abstract function in the interface which is implemented in the file DefaultMapsRepository. I don't understand how it works. I thought that call should be of function from DefaultMapsRepository class where getFeatures() is implemented. So, as I understand, getFeatures() call in ViewModel calls the not implemented method from the interface and then that interface somehow finds the implementation of it and that override fun getFeatures() code runs its body. Correct me if I'm wrong. But If I create another implementation of getFeatures() how would that interface choose which implementation to use? I heard somewhere that interface of repository makes code easier to test but it's hard to understand how if I don't know how this all code works. I sometimes like to test how code works in the console to make code look simpler but I can't replicate the same situation because I'm not able to run the code if I add something to fun main() constructor. I think such structure of a project is used a lot and I want to understand it very well.
A different way of explaining it that might help. Suppose you have this interface and class.
interface Pet {
fun sayName()
}
class Dog(val name: String): Pet {
override fun sayName() {
println(name)
}
}
If some function asks for a Pet, you can pass it an instance of anything that implements the Pet interface.
fun sayPetName(pet: Pet) {
pet.sayName()
}
From the function's point of view, it doesn't have to know what class was passed to it. It just knows that whatever was passed to it is an instance of a Pet, and must therefore have a non-abstract sayName() function.
Even though the function sayName() is abstract inside the definition of the interface, it would be impossible to create an instance of a class where there is an abstract function. There's no such thing as an abstract function in an instance of a class. You can define abstract classes that have abstract functions, but you cannot create instances of them.
You could pass a Dog instance to this function since it qualifies as a Pet. When the function calls pet.sayName(), it is up to the instance of Dog to respond. The function itself doesn't have to know anything about what class type was passed to it.
In the same way, if you have an instance of a Pet that was passed to your constructor, your class can use the sayName() function on it. If you pass the class a Dog instance, even though the class is storing it in a property that is marked Pet and the class doesn't know it has a Dog, if it calls sayName() on it, the Dog instance will use its implementation of sayName().
class SomeClass(val pet: Pet) {
fun sayThePetName() {
pet.sayName()
}
}
If a Dog were passed to the constructor of the above class, it does not get "downgraded" into a Pet interface that has an abstract function. It's still a Dog instance even if that specific type is not exposed to the class in this scope. The code inside the class doesn't know or care that it's a Dog. It just knows it has a reference to some actual class instance that has the functions defined by the Pet interface.
An interface is just a contract. If CoolInterface has a property someValue: Int and a method doThing(): Boolean, then anything that implements that interface is guaranteed to have that property and that method.
The MapsViewModel class takes a MapsRepository parameter, and MapsRepository is just an interface with one function:
suspend fun getFeatures(): Resource<FeaturesResponse>
You can pass in anything that implements that interface, which DefaultMapsRepository does:
class DefaultMapsRepository #Inject constructor(
...
) : MapsRepository {
Since it implements that interface, it needs to implement that getFeatures function, which it does:
// override is the keyword that shows you're not just declaring a new function,
// it's implementing something abstract in a superclass/interface (or overriding
// an open function)
override suspend fun getFeatures(): Resource<FeaturesResponse> {
// bla bla
}
So you can pass in anything at all as your repository, so long as it implements MapsRepository, meaning you need some implementation of that getFeatures function. It doesn't "decide" a version to use, it calls it on whatever you pass in. So you can test it with whatever mock class or object you like
val mockRepo = object : MapsRepository {
override suspend fun getFeatures(): Resource<FeaturesResponse> {
return Resource.Error("oh snap")
}
}
val viewModel = MapsViewModel(mockRepo, whateverTheOtherThingIs)
// calls getFeatures() on the repo
viewModel.getFeatures()
If none of that makes any sense, you should read up on what interfaces and polymorphism are!
Good day, I'm working through the coroutines with room codelab and I have some doubt as to when it's okay to simply call a databaseDao from a ViewModel and when you need to put it inside a suspend fun and launch it from a Coroutine with Dispatchers(IO).
In particular, in the code, which can be found here, inside SleepTrackerViewModel on line 37 they declare a val directly in the class like this:
private val nights = database.getAllNights()
Where the database is the dao and getAllNights is a query and it's called without any Coroutine or suspend fun. Shouldn't this be done from a coroutineScope within a suspend fun?
Thanks in advance!
As seen in the SleepDatabaseDao, getAllNights() is defined as:
fun getAllNights(): LiveData<List<SleepNight>>
Getting a LiveData does not need to be called on a background thread or from within a coroutine scope.
I have seen this implementation in Room database.
There is an abstract class AppDatabase -
#Database(entities = {Task.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract TaskDao taskDao();
}
But when you create an Object of this AppDatabase class, you do something like this -
AppDatabase appDatabase =
Room.databaseBuilder(context, AppDatabase.class, "something").build();
My questions are -
How can you pass an Abstract class directly like this without the Override methods defined ?
Like, normally we don't use and pass abstract classes like that, if you do something like this in IDE, it throws an error.
Which design pattern is this and how Room handles this type of things internally ?
1) The idea of using abstract classes is to have a sort of contract between the developer and room. We use abstract classes (or interfaces) because the implementation of those Dao methods will not be provided by us the developers but by Room itself.
2) It is a Builder design pattern, this design pattern is generally used when we have many options for how we'd like to create our final object and the pattern provides a more maintainable api for doing so. The example you provide is just a basic initialization of the database, but we can actually set many params whilst building the database class. For instance we can add the following option when building the database in order to tell it to delete everything and start again in case our database schema changes:
.fallbackToDestructiveMigration()
How Rooms handles thing internally is a bit of a hard question, but in general terms it is an abstraction layer of SQL apis provided by android itself, it will use your contracts (abstract classes or interfaces) for the Daos and the Database in order to create implementations for all of those abstract methods defined in those classes. Once you've setup everything and built your project the first time, Room will generate a bunch of _Impl classes that will implement those abstract methods. For instance, if you have a UserDao, it will generate a UserDao_Impl class that extends (or implements if you've used an interface) the original UserDao and it will provide those implementations. What it does internally will depend on the method, but it's basically using the SQLite api provided by Android.