Home > database >  How to instantiate DAO and Repository the correct way without Room DB?
How to instantiate DAO and Repository the correct way without Room DB?

Time:02-04

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.

CodePudding user response:

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.

  • Related