Tuesday, August 28, 2018

Dependency Injection with KOIN to Androidx Jetpack

August 28, 2018

Welcome to this post.

A few months ago google launch jetpack. This library includes some new component, like Work Manager. The problem is if you want to use dependency injection, then you can not do easily. If you heard about dependency injection then the first library coming in our mind is Dagger. But the problem is Dagger still not support androidx.

A few days ago I work with a new project, and I decide to use Work manger. But the problem arises because I am used Dagger. I search and waste a couple of hours but the solution is not in the satisfaction level. Then I decide to move to KOIN.

This is the first time I use KOIN. And the problem is gone. And I found KOIN is very handy. I don't have to write a lot of code. Just a simple line configuration. Declaring module is also very easy.
you will see that too in this post.

So let's start KOIN
First, add dependencies of KOIN


implementation 'org.koin:koin-android:0.9.3'
implementation "org.koin:koin-androidx-viewmodel:1.0.0-beta-3"

Note: Don't forget to add room, viewmodel, and livedata dependencies.

Let's Create a database.
I use room.

I skipping this part. you probably know how to create database using room. (This post is about some advanced topics).

Code snippet:
Create a table, such as WordTable
@Entity
class WordTable(
        @PrimaryKey(autoGenerate = true)
        var id: Int = 0,
        var word: String = "",
        var des: String = "",
        var bookmark: Boolean = false,
        var addByUser: Boolean = false,
        var uploaded:Boolean = false
)

Now Data Accessing object(Dao), exp: WordTableDao
@Dao
interface WordTableDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun add(table: WordTable): Long

    @Update
    fun update(table: WordTable): Int

    @Delete
    fun delete(pageTable: WordTable): Int


    @Query("Select * From WordTable")
    fun getAllList(): List<WordTable>
}

All set, create the database class.

@Database(entities = [WordTable::class], version = 1,
        exportSchema = false)
abstract class MyDatabase:RoomDatabase(){
    abstract val wordTableDao: WordTableDao
}

So our class database is ready, but still, we don't create the database. We will create the database in the KOIN module declaration time.

Now create a ViewModel class.
we need only Dao. it will provide by KOIN. We ViewModel Class as the parent class.
In the class just create a method called getData()  and load data from the database and return.

class MainVM(private val wordTableDao: WordTableDao):ViewModel(){

    fun getData() = wordTableDao.getRandomData()

}

Now time for module declaration. See the code first, then I discussing code.
we have two module. The first one is dbModule

val dbModule = module {

    single {
        Room.databaseBuilder(androidContext(), MyDatabase::class.java,
                "SS").build()
    }

    single { get<MyDatabase>().wordTableDao }

}

code -
1. keyword: module, it's just a function that creating a koin module
2. To create an instance you have to use single (from this new version, in the old version, use been keyword)
3. in a single, create the database
4. another single, call get function and type MyDatabase and access the Dao.

The second module is vmModule,
Same as this module but this time use viewmodel instead of single.

val vmModule = module {
    viewModel {
        MainVM(get() as WordTableDao)
    }
}

Note: if you don't use the androidx version of KOIN then you get an error, in this module declaration

we finished all declaration. Now we are ready for using KOIN. But before using KOIN, we have to start KOIN. To start KOIN declare an application class.
and write a simple line of code-

startKoin(this, listOf(module_list)

See code-

class MyApp:Application(){

    override fun onCreate() {
        super.onCreate()
        startKoin(this, listOf(dbModule, vmModule))
    }
}

All set. Now inject the ViewModel in the Main activity.
Now hard here, just declare a variable type MainVM and use by keyword (for lazy injection) and call viewModel() function.

    private val viewModel: MainVM by viewModel()

See code-

class MainActivity : AppCompatActivity() {

    private val viewModel: MainVM by viewModel()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setSupportActionBar(toolbar)


        viewModel.getData().observe(this, Observer {
            //observe data
        })
    }

}

Now the most desired one-
we are going to inject in the worker class. Create a worker class. But this time you are injecting KOIN not supported class. Don't worry. KOIN has already built an option to solve this problem. You have to implement KoinComponent.
After that same, declare a variable and lazy injection call inject() function
    val wordTableDao: WordTableDao by inject()

See the code-

class MyWorker : Worker(), KoinComponent {

    val wordTableDao: WordTableDao by inject()

    override fun doWork(): Result {

        val table = WordTable()

        wordTableDao.add(table)
        
        return Result.SUCCESS
    }


}

That's it. We are done. We finished our goal.

If you check all of those code in Gist also. Click here.

So by using KOIN, you can easily inject on the Androidx component. But for the dagger case, it's not so easy as this.

So, it's your choice, to use dagger or koin.

Thanks for reading.
Hope this articles help you a lot.

Happy coding

Read More