Now in Android is an open supply Android utility that features trendy Android Improvement finest practices. The challenge is maintained by the Google Android crew.
I counsel persevering with our tour with model constructed with Koin . dependency injection framework. It is a good time to refresh strategies, from normal part constructions to extra superior instances.
For this text, Now I counsel utilizing Koin Annotations as a substitute of Koin DSL to configure all of the parts of the applying. That is attention-grabbing to see how a lot it may possibly enhance the writing expertise.
Put together yourselves, we have now lots to see collectively 👍
⚠️ The model used under has not been made public. @KoinWorker coming quickly in subsequent launch
Beforehand partially 3, we noticed learn how to arrange and use Koin annotations with the Koin dependency injection framework. It is very easy as a result of the Koin annotation processor can detect a number of situations and create your dependency injection configuration actually quick. Now it is time to dive into extra parts of the NowInAndroid challenge.
You should have references for all content material to browse the code. Additionally, all the things is out there on-line on the Github repo: https://github.com/InsertKoinIO/nowinandroid/
Following the article half 2, we’ll now go to study the widespread core parts that can be utilized by the next options. However this time, the configuration can be achieved with annotations.
As a reminder, the Nia app is developed utilizing Jetpack Compose and makes use of repository parts & use instances:
- Warehouse to entry knowledge (community, database, and many others.)
- Usecase handles enterprise logic
The module is gathering all of the widespread parts which might beDataKoinModule.kt
module:
@Module(contains = [DaosKoinModule::class, DataStoreKoinModule::class, NetworkKoinModule::class, DispatchersKoinModule::class, DataUtilModule::class])
@ComponentScan("com.google.samples.apps.nowinandroid.core.knowledge.repository")
class DataKoinModule
This module is doing a number of issues:
- scan all repository lessons outlined in
@ComponentScan
- embody modules which might be declaring subclass parts
Every repository class is just tagged with @Single
Annotate like this:
@Single
class OfflineFirstAuthorsRepository(
personal val authorDao: AuthorDao,
personal val community: NiaNetworkDataSource,
)
You could find all of the repository lessons in supply code package deal.
For the database storage class, we have to declare our Room database occasion through a operate utilizing the Room API generator as follows:
@Module
class DatabaseKoinModule {
@Single
enjoyable database(context: Context) =
Room.databaseBuilder(context, NiaDatabase::class.java, "nia-database")
.construct()
}
The context
the parameter right here is the Android Context model from Koin.
Within the second module we are able to reuse NiaDatabase
instance under in DAO:
@Module(contains = [DatabaseKoinModule::class])
class DaosKoinModule {
@Single
enjoyable authorDao(niaDatabase: NiaDatabase) = niaDatabase.authorDao()
@Single
enjoyable topicDao(niaDatabase: NiaDatabase) = niaDatabase.topicDao()
@Single
enjoyable newsResourcesDao(niaDatabase: NiaDatabase) = niaDatabase.newsResourceDao()
}
That is it! Our database layer is able to be included.
This class defines Knowledge Sources that are parts that summary away calls to totally different knowledge sources. For instance, distant net service, native knowledge storage, and many others. Due to this fact, the consumer interface would not must know the place the information is coming from. It simply calls the interface outlined right here.
We’re defining some sort of usages with NiaNetworkDatasource
:
interface NiaNetworkDataSource {
droop enjoyable getTopics(ids: Record? = null): Record
droop enjoyable getAuthors(ids: Record? = null): Record
droop enjoyable getNewsResources(ids: Record? = null): Record
droop enjoyable getTopicChangeList(after: Int? = null): Record
droop enjoyable getAuthorChangeList(after: Int? = null): Record
droop enjoyable getNewsResourceChangeList(after: Int? = null): Record
}
First, we have to declare a default Coroutine dispatcher instantly in a module:
@Module
class DispatchersKoinModule{
@Single
enjoyable dispatcher() = Dispatchers.IO
}
IN a take a look at setting, you solely must redefine one
CoroutineDispatcher
kind to specify your wanted one. Simply add a brand new definition and it’ll overwrite the prevailing one.
The community module declaring NiaNetworkDatasource
and arranged into 2 flavors:
- demo — with native knowledge
- prod — for on-line knowledge
The NetworkKoinModule
together with the right implementation of the style:
@Module(contains = [FlavoredNetworkKoinModule::class])
class NetworkKoinModule {
@Single
enjoyable json() = Json { ignoreUnknownKeys = true }
}
The demo taste makes use of the Knowledge Warehouse API and the Protobuff API is used to retailer knowledge regionally for rendering as an offline most well-liked structure.
@Module(contains = [DispatchersKoinModule::class])
@ComponentScan("com.google.samples.apps.nowinandroid.core.community.pretend")
class FlavoredNetworkKoinModule{
@Single
enjoyable assetManager(context: Context) = FakeAssetManager(context.belongings::open)
}
Right here is the demo datasource implementation declared as a singleton:
@Single
class FakeNiaNetworkDataSource(
personal val ioDispatcher: CoroutineDispatcher,
personal val networkJson: Json,
personal val belongings: FakeAssetManager = JvmUnitTestFakeAssetManager,
) : NiaNetworkDataSource
The web model is said with the next module:
@Module(contains = [DispatchersKoinModule::class])
@ComponentScan("com.google.samples.apps.nowinandroid.core.community.retrofit")
class FlavoredNetworkKoinModule
This module will scan Retrofit implementations:
@Single
class RetrofitNiaNetwork(
networkJson: Json
) : NiaNetworkDataSource
A last part is in regards to the persistent knowledge storage API, which is used to declare native knowledge storage. Test Knowledge Warehouse Persistence Module that’s to declare the required parts for NiaPreferencesDatasource
.
Earlier than working our options, we have now some use case parts utilizing DataKoinModule. These use case parts are reusable enterprise logic parts. They’re outlined from DomainKoinModule
:
@Module(contains = [DataKoinModule::class])
@ComponentScan
class DomainKoinModule
You might notice that we don’t specify which packages to scan. Which means the module will scan within the present package deal and subpackages for annotated parts:
Every usecase aspect is said with @Manufacturing facility
notice. This tells Koin to create a brand new occasion every time we’d like it.
@Manufacturing facility
class GetFollowableTopicsStreamUseCase(
personal val topicsRepository: TopicsRepository,
personal val userDataRepository: UserDataRepository
)
Why not a single instance? As a result of these usecase parts can be used with a
ViewModel
, which follows the Android lifecycle. Making them a unit, we run the danger of getting references to aViewModel
canceled by the applying.
Lastly, we’re prepared to make use of all of those in our Options module. Each will then embody DomainKoinModule
or DataKoinModule
To learn from the favored components:
@Module(contains = [DomainKoinModule::class,StringDecoderKoinModule::class])
@ComponentScan("com.google.samples.apps.nowinandroid.characteristic.writer")
class AuthorKoinModule
By correctly scanning the package deal in our module, we will declare our ViewModel situations as follows:
@KoinViewModel
class AuthorViewModel(
savedStateHandle: SavedStateHandle,
stringDecoder: StringDecoder,
personal val userDataRepository: UserDataRepository,
authorsRepository: AuthorsRepository,
getSaveableNewsResourcesStream: GetSaveableNewsResourcesStreamUseCase
) : ViewModel()
Lastly, we have to declare SyncWorker parts to organize offline content material asynchronously. This features a module:
@Module
@ComponentScan
class SyncWorkerKoinModule
The next definitions can be scanned by the module.
@Single
class WorkManagerSyncStatusMonitor(
context: Context
) : SyncStatusMonitor
And SyncWorker
declared aspect with @KoinWorker
notice. This can produce the equal of employee { }
DSL:
@KoinWorker
class SyncWorker (
personal val appContext: Context,
workerParams: WorkerParameters,
personal val niaPreferences: NiaPreferencesDataSource,
personal val topicRepository: TopicsRepository,
personal val newsRepository: NewsRepository,
personal val authorsRepository: AuthorsRepository,
personal val ioDispatcher: CoroutineDispatcher,
) : CoroutineWorker(appContext, workerParams), Synchronizer
SyncWorker
can be declared with the Workmanager Koin manufacturing unit. This needs to be enabled from the beginning like this:
John Wick: Chapter 4 (FREE) FULLMOVIE The Super Mario Bros Movie avatar 2 Where To Watch Creed 3 Free At Home Knock at the Cabin (2023) FullMovie Where To Watch Ant-Man 3 and the Wasp: Quantumania Cocaine Bear 2023 (FullMovie) Scream 6 Full Movie
Supply hyperlink