0

I am in the process to rewrite my app code from using Java to Kotlin with MVVM. My app uses the Sugar ORM instead of Room DB at the moment, however, I still would like to use some of the potentials of MVVM.

My goal is to instantiate the DAO and Repository in one place for instance in the application and create only one instance of it for the whole app the correct way.

DAO - Kotlin

class FirstDao {
...
}

class SecondDao {
...
}

Repository - Kotlin

class InternalRepository(private val firstDao: FirstDao,
                         private val secondDao: SecondDao
) {
...
}

View Model - Kotlin

class FirstViewModel(private val repository: InternalRepository) :
    ViewModel() {
...
}

View Model Factory - Kotlin

class FirstViewModelFactory(
    private  val repository: InternalRepository
): ViewModelProvider.Factory{

    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(FirstViewModel::class.java)) {
            @Suppress("UNCHECKED_CAST")
            return FirstViewModel(repository) as T
        }
        throw IllegalArgumentException("Unknown ViewModel class")
    }

}

Activity - Java

FirstDao firstDao = new FirstDao();
SecondDao secondDao = new SecondDao();

InternalRepository repository = new InternalRepository(firstDao, secondDao);

FirstViewModelFactory factory = new FirstViewModelFactory(repository);
viewModel = new ViewModelProvider(this, factory).get(FirstViewModel.class);

Application - Java

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        SugarContext.init(this);
    ...
    }
...
}

The code itself works correctly, however, when I have more DAO I have to instantiate every single one in the activity including the repository and there is a risk that the DAO and repository will be instantiated multiple times.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
DevPeter
  • 83
  • 2
  • 8

1 Answers1

1

The most naive and perhaps not so optimal solution (when you ask for "the correct way") would be to use simple Singleton pattern. Another approach would be to use Service Locator or Dependency Injection design pattern, which we will focus on.

In your example you are actually already using Dependency Injection (DI),

you are simply passing your DAO classes through the constructor of your Repository class instead of for example creating those DAO instances in the Repository class itself

but the missing piece is something what would help you with:

  • first Injecting and Resolving those dependencies in a better automatized way and
  • second provide you with mechanics, which would keep your classes instantiated once (per application/activity/viewmodel/... scope).

You can find further explanation about what and what for is Dependency Injection design pattern for example in this exhaustive thread.

One of the common approaches would be to use some kind of Dependency Injection library, which would help you with Injecting and Resolving dependencies of for example your already mentioned Repository classes.

In Android development one of the library being commonly used is called Dagger. Here you can find handy explanation and tutorial directly from Android. The Dagger with help of @Inject annotations and other principles described in the documentation above will generate the DI code for you in the compile time. Then in your code you only really care about getting and using an instance of a (Repository) class what is being constructed for you with the help of the Dagger. The learning curve might be little bit steep, but in my personal opinion, this is the way for middle to big projects.

There are also other heavily used libraries/frameworks which can help you with the task such as Koin which promises easier and better APIs, but I personally cannot talk much about it, because I haven't used it yet in some serious project.

David Kneys
  • 275
  • 2
  • 7
  • Thank you for your inspiration. I find a great example of exactly what I am looking for. Reso Coder using dependency injection Kodein here: [Reso Coder Dependency Injection with Kodein & MVVM Architecture – Android Kotlin Tutorial](https://resocoder.com/2018/09/28/dependency-injection-with-kodein-mvvm-architecture-android-kotlin-tutorial/) He also uses interfaces and then implements them. Is it better to create an interface first and then implement the interface? – DevPeter Feb 03 '23 at 10:03
  • It is not that simple to say "yes it is better to program against interfaces" or "no it isn't'". If I would want to generalize, I would say "yes, it is a great practice to program against interface", but it depends when, why, what is the benefit. Programming is not about the one single best path. Every approach has pros and cons. With putting interfaces everywhere just for the reason of "it is a good practice", you can easily overengineer your app. Interfacing is great for improving code readability, usage or testing. I can only suggest you to learn by practice and from others with real code. – David Kneys Feb 03 '23 at 12:07
  • Thank you for your comment. Looks to me that Dagger is a good choice for me. Kodein looks simple, however, it is for Kotlin-only files and my Activity is in Java at the moment. – DevPeter Feb 03 '23 at 15:11