Android. Could not instantiate Worker - android

I want to pre-populate my Room database from the json file in the assets folder. I follow the Google Sunflower sample. I copied the SeedDatabaseWorker class:
import android.content.Context
import android.util.Log
import androidx.work.Worker
import androidx.work.WorkerParameters
import com.dmitrysimakov.gymlab.data.GymLabDb
import com.dmitrysimakov.gymlab.data.entity.Training
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonReader
import javax.inject.Inject
class SeedDatabaseWorker(val context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
private val TAG = SeedDatabaseWorker::class.java.simpleName
#Inject lateinit var database: GymLabDb
override fun doWork(): Worker.Result {
val plantType = object : TypeToken<List<Training>>() {}.type
var jsonReader: JsonReader? = null
return try {
val inputStream = context.assets.open("training.json")
jsonReader = JsonReader(inputStream.reader())
val plantList: List<Training> = Gson().fromJson(jsonReader, plantType)
database.trainingDao().insert(plantList)
Worker.Result.SUCCESS
} catch (ex: Exception) {
Log.e(TAG, "Error seeding database", ex)
Worker.Result.FAILURE
} finally {
jsonReader?.close()
}
}
}
I'm using Dagger 2, so instead of doing this: Sunflower AppDatabase, I do this:
import android.arch.persistence.db.SupportSQLiteDatabase
import android.arch.persistence.room.Room
import android.arch.persistence.room.RoomDatabase
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import com.dmitrysimakov.gymlab.GymLabApp
import com.dmitrysimakov.gymlab.data.GymLabDb
import com.dmitrysimakov.gymlab.workers.SeedDatabaseWorker
import dagger.Module
import dagger.Provides
import javax.inject.Singleton
#Module(includes = [ViewModelModule::class])
class AppModule {
#Singleton
#Provides
fun provideDb(app: GymLabApp): GymLabDb {
return Room
.databaseBuilder(app, GymLabDb::class.java, "gymlab.db")
.addCallback(object : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
val request = OneTimeWorkRequestBuilder<SeedDatabaseWorker>().build()
WorkManager.getInstance().enqueue(request)
}
})
.fallbackToDestructiveMigration()
.build()
}
#Singleton
#Provides
fun provideTrainingDao(db: GymLabDb) = db.trainingDao()
}
But I can't inject the database that has not yet been created. So, how can I access the dao?

The problem was that I couldn't inject my database into the Worker. I found the solution here: AndroidWorkerInjection

Your issue is that SeedDatabaseWorker is still based on Worker() which is deprecated now, so you need to use Worker(Context, WorkerParameters) this constructor.
Check my answer from another post, it'll help you understand WorkManager library.
Edit :
You can now check Worker from that Sunflower demo, it's updated.

Related

No type arguments expected for interface Callback

I'm a mid-Senior level Android developer who is working on some projects to upgrade my skills. While developing one of my projects. I came across the following error:
C:\Users\animesh.vashistha\StudioProjects\MovieListApp\app\src\main\java\com\example\movielistapp\MainViewModel.kt: (21, 43): No type arguments expected for interface Callback
My MainViewModel looks like this:
package com.example.movielistapp
import android.graphics.Movie
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.example.movielistapp.data.MainRepository
import com.example.movielistapp.model.Model
import retrofit2.Call
import retrofit2.Response
import javax.security.auth.callback.Callback
class MainViewModel constructor(private val repository: MainRepository) : ViewModel() {
val movieList = MutableLiveData<List<Model.Movie>>()
val errorMessage = MutableLiveData<String>()
fun getAllMovies() {
val response = repository.getAllMovies()
response.enqueue(object : Callback<List<Movie>>{
fun onResponse(call: Call<List<Model.Movie>>, response: Response<List<Model.Movie>>) {
movieList.postValue(response.body())
}
fun onFailure(call: Call<List<Model.Movie>>, t: Throwable) {
errorMessage.postValue(t.message)
}
})
}
}
I have imported import retrofit2.call as answered in other solutions to this question. Can someone please check and tell what wrong I'm doing?

Using Cookies with Retrofit and Hilt and recommended architecture

I'm fairly new to Android and Java / Kotlin so I've been struggling to implement cookies in the recommended architecture. I looked in many places, read the documentation and watched many videos and everyone had such different ways to implement things that I was still confused. How does it all fit together?
I would have thought this was such a common use case that I can't believe the answer isn't all over the net, but I've had to work hard to put all the pieces together. Below is what worked for me from the Repository down. I haven't included the database side of things since that is well documented in many places and I found it easy enough to follow (if anyone needs me to include that, let me know). I switched to Kotlin part way through because I could only find some parts of the answer in Java. My example is to log in a user and get basic profile details.
Repository sends login details to server and saves response in database then pulls that info to save as LiveData
package com.example.myapplication
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.example.myapplication.*
import com.example.myapplication.asDomainModel
import com.example.myapplication.asDBEntity
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.IOException
import javax.inject.Inject
class LoginRepository #Inject constructor(
private val myDao: MyDao,
private val myNetwork: Network
) {
private val _profile: MutableLiveData<Profile> = MutableLiveData()
val profile: LiveData<Profile>
get() = _profile
suspend fun login(name: String, password: String) {
withContext(Dispatchers.IO) {
// log in to server and get profile data
val profileNWEntity = myNetwork.login("login", name, password)
// process response
when (profileNWEntity.status) {
"PROFLOGINOK" -> {
// save profile in database then retrieve
myDao.insertProfile(profileNWEntity.asDBEntity())
_profile.postValue(myDao.getProfile(profileNWEntity.user).asDomainModel())
}
else -> {
throw IOException (profileNWEntity.status)
}
}
}
}
}
Retrofit endpoint defines the login process
package com.example.myapplication
import com.example.myapplication.ProfileNWEntity
import retrofit2.http.Field
import retrofit2.http.FormUrlEncoded
import retrofit2.http.POST
interface Network {
#FormUrlEncoded
#POST("server_api")
suspend fun login(
#Field("action") action: String,
#Field("name") name: String,
#Field("pass") password: String
): ProfileNWEntity
}
Entity - used by Gson to parse the network response and by the repository to adapt for the database
package com.example.myapplication
import com.example.myapplication.AccountDBEntity
import com.example.myapplication.ProfileDBEntity
/**
* Base profile response from network query
*/
data class ProfileNWEntity(
val user: Int,
val name: String,
val status: String
)
// map the profile from network to database format
fun ProfileNWEntity.asDBEntity(): ProfileDBEntity {
return ProfileDBEntity(
id = user,
name = name
)
}
Retrofit class to enable inclusion of cookies (together with the interceptors included below, this comes from the work of tsuharesu and Nikhil Jha found at https://gist.github.com/nikhiljha/52d45ca69a8415c6990d2a63f61184ff)
package com.example.myapplication
import android.content.Context
import dagger.hilt.android.qualifiers.ApplicationContext
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import javax.inject.Inject
class RetrofitWithCookie #Inject constructor(
context: Context, // uses Hilt to inject the context to be passed to the interceptors
gson: Gson
) {
private val mContext = context
private val gson = gson
fun createRetrofit(): Retrofit {
val client: OkHttpClient
val builder = OkHttpClient.Builder()
builder.addInterceptor(AddCookiesInterceptor(mContext)) // VERY VERY IMPORTANT
builder.addInterceptor(ReceivedCookiesInterceptor(mContext)) // VERY VERY IMPORTANT
client = builder.build()
return Retrofit.Builder()
.baseUrl("myServer URL") // REQUIRED
.client(client) // VERY VERY IMPORTANT
.addConverterFactory(GsonConverterFactory.create(gson))
.build() // REQUIRED
}
}
Receiving Interceptor catches the inbound cookies and saves them in sharedpreferences
package com.example.myapplication
import android.content.Context
import androidx.preference.PreferenceManager
import okhttp3.Interceptor
import okhttp3.Response
import java.io.IOException
import java.util.*
// Original written by tsuharesu
// Adapted to create a "drop it in and watch it work" approach by Nikhil Jha.
// Just add your package statement and drop it in the folder with all your other classes.
class ReceivedCookiesInterceptor(context: Context?) : Interceptor {
private val context: Context?
#Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val originalResponse = chain.proceed(chain.request())
if (!originalResponse.headers("Set-Cookie").isEmpty()) {
val cookies = PreferenceManager.getDefaultSharedPreferences(context)
.getStringSet("PREF_COOKIES", HashSet()) as HashSet<String>?
for (header in originalResponse.headers("Set-Cookie")) {
cookies!!.add(header)
}
val memes = PreferenceManager.getDefaultSharedPreferences(context).edit()
memes.putStringSet("PREF_COOKIES", cookies).apply()
memes.commit()
}
return originalResponse
}
init {
this.context = context
} // AddCookiesInterceptor()
}
AddCookies interceptor adds the cookie back into future requests
package com.example.myapplication
import android.content.Context
import androidx.preference.PreferenceManager
import dagger.hilt.android.qualifiers.ActivityContext
import okhttp3.Interceptor
import okhttp3.Response
import timber.log.Timber
import java.io.IOException
import java.util.*
// Original written by tsuharesu
// Adapted to create a "drop it in and watch it work" approach by Nikhil Jha.
// Just add your package statement and drop it in the folder with all your other classes.
/**
* This interceptor put all the Cookies in Preferences in the Request.
* Your implementation on how to get the Preferences may ary, but this will work 99% of the time.
*/
class AddCookiesInterceptor(#ActivityContext context: Context?) : Interceptor {
// We're storing our stuff in a database made just for cookies called PREF_COOKIES.
// I reccomend you do this, and don't change this default value.
private val context: Context?
#Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val builder = chain.request().newBuilder()
val preferences = PreferenceManager.getDefaultSharedPreferences(context).getStringSet(
PREF_COOKIES, HashSet()
) as HashSet<String>?
// Use the following if you need everything in one line.
// Some APIs die if you do it differently.
/*String cookiestring = "";
for (String cookie : preferences) {
String[] parser = cookie.split(";");
cookiestring = cookiestring + parser[0] + "; ";
}
builder.addHeader("Cookie", cookiestring);
*/for (cookie in preferences!!) {
builder.addHeader("Cookie", cookie)
Timber.d("adding cookie %s", cookie)
}
return chain.proceed(builder.build())
}
companion object {
const val PREF_COOKIES = "PREF_COOKIES"
}
init {
this.context = context
}
}
Hilt Module to tie it all together
package com.example.myapplication
import android.content.Context
import com.example.myapplication.Network
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import javax.inject.Singleton
#InstallIn(SingletonComponent::class)
#Module
class NetworkModule {
#Singleton
#Provides
fun provideNetwork(retrofit: Retrofit)
: Network = retrofit.create(Network::class.java)
#Singleton
#Provides
fun provideRetrofitWithCookie(
#ApplicationContext context: Context,
gson: Gson
): Retrofit = RetrofitWithCookie(context, gson).createRetrofit()
#Singleton
#Provides
fun provideGson(): Gson = GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ") // used for parsing other responses
.create()
}

Dagger issues after upgrading from Android Studio 3.0.1 to 4.0.1 and Dagger 2.9 -> 2.25.3

I’ve been working on upgrading our Android project from Android Studio 3.0.1 to 4.0.1, and as part of that, I have upgraded the following:
Build Tools Version 26.0.2 -> 30.0.2
Compile SDK Version 25 -> 28
Kotlin version 1.2.71 -> 1.4.10
Gradle version 3.1.0 -> 4.0.1
Android Support v7 -> androidx 1.0.0
Dagger 2.9 -> 2.28.3
Retrofit 2.2.0 -> 2.9.0
Okhttp 3.7.0 -> 4.9.0
I am now running into an issue where I am getting an error saying the following:
#dagger.Component(dependencies = {org.bbb.ccc.app.application.AppComponent.class}, modules = {org.bbb.ccc.app.ddd.yyy.zzz.class})
^
#Singleton org.bbb.ccc.app.application.AppComponent/Users/xxx/aaa_android/app/build/tmp/kapt3/stubs/eee/org/xxx/ddd/app/application/AppComponent.java:8: error: [Dagger/MissingBinding] java.util.Map<java.lang.Class<? extends error.NonExistentClass>,javax.inject.Provider<org.bbb.ccc.app.dagger.fragment.FragmentComponentBuilder<?,?>>> cannot be provided without an #Provides-annotated method.
So far, as part of this migration, I have moved several classes from being a Singleton to their own scope, as discussed in Singleton component cannot depend on scoped components
I have also tried to follow the information here: http://frogermcs.github.io/activities-multibinding-in-dagger-2/ as well as a few other things, and I have not yet been able to get the build to compile with AS4. This project compiled in 3.0.1 before upgrading.
Onto code now:
App.kt:

package org.bbb.ccc.app.application
import android.app.Activity
import android.app.Application
import android.content.Context
import android.content.Intent
import android.os.StrictMode
import android.util.Log
import com.crashlytics.android.Crashlytics
import io.fabric.sdk.android.Fabric
import io.realm.Realm
import io.realm.RealmConfiguration
import org.bbb.ccc.app.dagger.activity.ActivityComponentBuilder
import org.bbb.ccc.app.dagger.activity.HasActivitySubcomponentBuilders
import org.bbb.ccc.app.data.migration.KäsefüßeRealmMigration
import org.bbb.ccc.app.data.repository.RealmDatabase
import org.bbb.ccc.app.utils.logouttimer.LogoutTimerService
import javax.inject.Inject
/**
* Application Class (Debug Version)
* #desc - Instantiate a Base class for all Android Activities and Services. Also creates global
* objects for Realm, Dagger, Analytics, Memory Management, etc.
*/
open class App : Application(), HasActivitySubcomponentBuilders {
companion object {
var context: Context? = null
}
#Inject
lateinit var activityComponentBuilders: MutableMap<Class<out Activity?>?, #JvmSuppressWildcards ActivityComponentBuilder<*, *>?>
lateinit var appComponent: AppComponent
override fun onCreate() {
super.onCreate()
context = this
// Set Crashlytics for Firebase
Fabric.with(this, Crashlytics())
createRealm("KäsefüßeDebug.Realm", 4L)
appComponent = createAppComponent()
appComponent.inject(this)
try{
Intent(this, LogoutTimerService::class.java).also { intent ->
startService(intent)
}
} catch (e: IllegalStateException){
Log.d("Käsefüße", e.toString())
}
StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.build())
StrictMode.setVmPolicy(StrictMode.VmPolicy.Builder()
.detectAll()
.penaltyLog()
.build())
}
override fun onTerminate() {
LogoutTimerService.sharedInstance.cancelTimer()
Intent(this, LogoutTimerService::class.java).also { intent ->
stopService(intent)
}
super.onTerminate()
}
protected open fun createAppComponent() : AppComponent {
return DaggerAppComponent.builder()
.appModule(AppModule(this))
.apiModule(ApiModule())
.dbModule(DbModule())
.build()
}
protected open fun createRealm(realmName: String, realmVersion: Long) {
Realm.init(this)
RealmDatabase.realmConfiguration = RealmConfiguration.Builder()
.name(realmName)
.schemaVersion(realmVersion)
.migration(KäsefüßeRealmMigration())
.build()
}
override fun getBuilder(activityClass: Class<out Activity?>?): ActivityComponentBuilder<*, *>? {
return activityComponentBuilders[activityClass]
}
}
AppComponent.kt:
package org.bbb.ccc.app.application
import android.content.Context
import dagger.Component
import org.bbb.ccc.app.vol.ComplimenteuseService
import org.bbb.ccc.app.dagger.activity.ActivityBindingModule
import org.bbb.ccc.app.data.preference.PreferenceFactory
import org.bbb.ccc.app.Fromage.FromageService
import org.bbb.ccc.app.nourriture.Ananas.AnanasActivity
import org.bbb.ccc.app.nourriture.pommeDuTerre.PommeDuTerreActivity
import javax.inject.Singleton
#Singleton
#Component(modules = [AppModule::class, ActivityBindingModule::class])
interface AppComponent {
fun inject(app: App)
fun inject(FromageService: FromageService)
fun inject(complimenteuseService: ComplimenteuseService)
fun context() : Context
fun preferenceFactory() : PreferenceFactory
fun inject(ananasActivity: AnanasActivity)
fun inject(pommeDuTerreActivity: PommeDuTerreActivity)
}
AppModule.kt:
package org.bbb.ccc.app.application
import android.content.Context
import android.content.SharedPreferences
import com.google.gson.Gson
import dagger.Module
import dagger.Provides
import io.reactivex.Scheduler
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import org.bbb.ccc.app.bluetooth.BTUtils
import org.bbb.ccc.app.data.preference.PreferenceFactory
import org.bbb.ccc.app.domain.model.Profile
import org.bbb.ccc.app.domain.network.KäsefüßeAPI
import org.bbb.ccc.app.domain.repository.ComplimenteuseRepository
import org.bbb.ccc.app.domain.repository.TrainRepository
import org.bbb.ccc.app.domain.repository.UserRepository
import org.bbb.ccc.app.login.interactor.ProfileInteractor
import org.bbb.ccc.app.login.interactor.ProfileManager
import org.bbb.ccc.app.presentation.interactor.SchedulerProvider
import org.bbb.ccc.app.utils.android.DeviceNameGenerator
import org.bbb.ccc.app.utils.android.HasConnection
import org.bbb.ccc.app.utils.connectionstate.ConnectionBroadCastReceiverRegistry
import org.bbb.ccc.app.utils.connectionstate.ConnectionNotifier
import org.bbb.ccc.app.utils.connectionstate.OkHttpPingService
import org.bbb.ccc.app.utils.extensions.hasInternetConnection
import javax.inject.Singleton
/**
* App Module - Dagger.
*/
#Module(includes = [ApiModule::class, DbModule::class])
class AppModule(private val application: App) {
#Provides
#Singleton
fun app(): App = application
#Provides
#Singleton
fun sharedPreferences(): SharedPreferences =
application.getSharedPreferences("PREFS", Context.MODE_PRIVATE)
#Provides
#Singleton
fun applicationContext() : Context = application
#Provides
#Singleton
fun schedulerProvider() : SchedulerProvider {
return object : SchedulerProvider {
override fun ui(): Scheduler = AndroidSchedulers.mainThread()
override fun computation(): Scheduler = Schedulers.computation()
override fun trampoline(): Scheduler = Schedulers.trampoline()
override fun newThread(): Scheduler = Schedulers.newThread()
override fun io(): Scheduler = Schedulers.io()
}
}
#Provides
#Singleton
fun preferencesManager(sharedPreferences: SharedPreferences, gson: Gson) : PreferenceFactory =
PreferenceFactory(sharedPreferences, gson)
#Provides
#Singleton
fun profileInteractor(preferenceFactory: PreferenceFactory, trainRepository: TrainRepository,
userRepository: UserRepository, schedulerProvider: SchedulerProvider)
: ProfileManager {
val preference = preferenceFactory.create<Profile>(PreferenceFactory.PreferenceKey.PROFILE)
return ProfileInteractor(preference, trainRepository, userRepository, schedulerProvider)
}
#Provides
#Singleton
fun hasConnection() : HasConnection {
return object : HasConnection {
override fun available(): Boolean = application.hasInternetConnection()
}
}
#Provides
#Singleton
fun connectionNotifier(context: Context, hasConnection: HasConnection, schedulerProvider: SchedulerProvider)
: ConnectionNotifier =
ConnectionNotifier(OkHttpPingService(), ConnectionBroadCastReceiverRegistry(context), hasConnection, schedulerProvider)
#Provides
#Singleton
fun ComplimenteuseInteractor(ComplimenteuseRepository: ComplimenteuseRepository,
KäsefüßeAPI: KäsefüßeAPI,
hasConnection: HasConnection,
preferenceFactory: PreferenceFactory,
schedulerProvider: SchedulerProvider): ComplimenteuseManager {
val preference = preferenceFactory.create<Profile>(PreferenceFactory.PreferenceKey.PROFILE)
val deviceNameGenerator = object : DeviceNameGenerator {
override fun name(): String = BTUtils.deviceName
}
return ComplimenteuseInteractor(ComplimenteuseRepository, KäsefüßeAPI, hasConnection, preference, deviceNameGenerator, schedulerProvider)
}
}
ActivityBindingModule:
package org.bbb.ccc.app.dagger.activity
import dagger.Binds
import dagger.Module
import dagger.multibindings.IntoMap
import org.bbb.ccc.app.vol.AeroplanActivity
import org.bbb.ccc.app.vol.AeroplanComponent
import org.bbb.ccc.app.login.LoginActivity
import org.bbb.ccc.app.login.LoginComponent
import org.bbb.ccc.app.nourriture.viande.BoeufActivity
import org.bbb.ccc.app.nourriture.viande.BoeufComponent
import org.bbb.ccc.app.nourriture.fruit.PommeComponent
import org.bbb.ccc.app.nourriture.fruit.CarambolaActivity
import org.bbb.ccc.app.nourriture.fruit.RaisinActivity
import org.bbb.ccc.app.nourriture.fruit.RaisinComponent
import org.bbb.ccc.app.KäsefüßeKäse.KäseActivity
import org.bbb.ccc.app.KäsefüßeKäse.KäseComponent
/**
* Created by Bob Jones on 4/26/17.
*/
#Module(
subcomponents = [LoginComponent::class, AeroplanComponent::class, KäseComponent::class, PommeComponent::class, BoeufComponent::class, RaisinComponent::class]
)
abstract class ActivityBindingModule {
#Binds
#IntoMap
#ActivityKey(LoginActivity::class)
abstract fun loginComponentBuilder(impl: LoginComponent.Builder) : ActivityComponentBuilder<*, *>
#Binds
#IntoMap
#ActivityKey(AeroplanActivity::class)
abstract fun AeroplanComponentBuilder(impl: AeroplanComponent.Builder) : ActivityComponentBuilder<*, *>
#Binds
#IntoMap
#ActivityKey(KäseActivity::class)
abstract fun KäseActivityComponentBuilder(impl: KäseComponent.Builder) : ActivityComponentBuilder<*, *>
#Binds
#IntoMap
#ActivityKey(CarambolaActivity::class)
abstract fun carambolaComponentBuilder(impl: PommeComponent.Builder) : ActivityComponentBuilder<*, *>
#Binds
#IntoMap
#ActivityKey(BoeufActivity::class)
abstract fun boeufActivity(impl: BoeufComponent.Builder) : ActivityComponentBuilder<*, *>
#Binds
#IntoMap
#ActivityKey(RaisinActivity::class)
abstract fun RaisinComponentBuilder(impl: RaisinComponent.Builder) : ActivityComponentBuilder<*, *>
}
Thanks in advance for your assistance!
It says the FragmentComponentBuilder is missing code - I don't see where you create the FragmentComponentBuilder in your post so maybe start looking there and checking that all your fragments are being properly injected.

error: #Component.Builder is missing setters for required modules or components in Dagger 2 instead of having setter method

I am new to dagger 2. I was making a CarComponent on kotlin, I was trying to call my DaggerCarComponent with horsePower value without calling petrolEngineModule. the following is my code :
import dagger.BindsInstance
import dagger.Component
import javax.inject.Singleton
#Component (
modules = [WheelModule::class, PetrolEngineModule::class]
)
interface CarComponent {
fun getCar(): Car
fun inject(mainActivity: MainActivity)
#Component.Builder
interface Builder {
#BindsInstance
fun horsePower(horsePower : Int) : Builder
fun build(): CarComponent
}
}
this is PetrolEngine.kt:
package com.example.daggerapp
import android.util.Log
import javax.inject.Inject
class PetrolEngine : Engine {
private var horsePower : Int
#Inject constructor(horsePower: Int){
this.horsePower = horsePower
}
override fun start() {
Log.d("Engine", "Broom..., horsePower: ${this.horsePower}")
}
}
this is PetrolEngineModule.kt:
package com.example.daggerapp
import dagger.Module
import dagger.Provides
import javax.inject.Inject
#Module
class PetrolEngineModule {
private var horsePower: Int
#Inject constructor(horsePower: Int) {
this.horsePower = horsePower
}
#Provides
fun provideHorsePower(): Int {
return horsePower
}
#Provides
fun provideEngine(engine: PetrolEngine): Engine
{
return engine
}
}
I added the DaggerComponent here as DaggerCarComponent :
package com.example.daggerapp
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import javax.inject.Inject
class MainActivity : AppCompatActivity() {
#Inject
lateinit var car:Car
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val daggerCar: CarComponent = DaggerCarComponent.builder().petrolEngineModule(PetrolEngineModule(140)).build()
daggerCar.inject(this)
Log.d("Car instance", "$car")
car.drive()
}
}
I was following this tutorial: https://www.youtube.com/watch?v=3tIvekCTSJg&list=PLrnPJCHvNZuA2ioi4soDZKz8euUQnJW65&index=8
In your Builder:
#BindsInstance
Builder horsePower(#Named("horse_power") int horsePower);
After this you will be able to pass horsePower from MainActivity without passing instance of PetrolEngineModule.And same way in ur PetrolEngine constructor:
#Inject
public PetrolEngine(#Named("horse_power") int horsePower) {
this.horsePower = horsePower;
}
And in your PetrolEngineModule u can remove everything and just leave #Provides for PetrolEngine.
Remove #Inject in the module class, cause that what #BindsInstance is doing when pass horsePower it in #Component.Builder
Just an optimization for future viewers. Just replace the existing code with this. Now Dagger will not create the --Provide-- class to provide the instance of PetrolEngine.
Please improve the code if you find anything wrong.
#Module
abstract class PetrolEngineModule {
#Binds
abstract fun bindEngine(engine: PetrolEngine): Engine
}

Unable to generate code created by Dagger in Kotlin Android App

Thanks for reading, After some issues with Annotations after converting a Java App to Kotlin I have added the modules components qualifiers and Scopes and it builds after rebuilding it.But I'm stuck here as I want to use the DaggerFragmentComponent (Fragment Component) but it doesn't import as in it hasn't created that after rebuilding.
I only have access to DaggerCollections which is not want I want to execute the dependency injection....
FragmentModule:
package com.example.daggerappkotlin.di.module
import com.example.daggerappkotlin.di.qualifier.FragContext
import com.example.daggerappkotlin.ui.HomeFragment
import dagger.Module
import dagger.Provides
#Module
class FragmentModule(internal var fragment: HomeFragment) {
#FragContext
#Provides
internal fun provideFragment(): HomeFragment {
return fragment
}
#FragContext
#Provides
internal fun provideConnection(): String {
return "Connected Ben Mohammad"
}
}
FragmentComponent:
package com.example.daggerappkotlin.di.component
import android.content.Context
import com.example.daggerappkotlin.di.module.FragmentModule
import com.example.daggerappkotlin.di.qualifier.ApplicationContext
import com.example.daggerappkotlin.di.scope.FragmentScope
import com.example.daggerappkotlin.ui.HomeFragment
import dagger.Component
#FragmentScope
#Component(dependencies = [ApplicationComponent::class], modules = [FragmentModule::class])
interface FragmentComponent {
#ApplicationContext
val context: Context
fun inject(frag: HomeFragment)
}
ApplicationModule:
package com.example.daggerappkotlin.di.module
import android.content.Context
import com.example.daggerappkotlin.MyApplication
import com.example.daggerappkotlin.di.qualifier.ApplicationContext
import com.example.daggerappkotlin.di.qualifier.DatabaseInfo
import com.example.daggerappkotlin.di.qualifier.NetworkInfo
import dagger.Module
import dagger.Provides
#Module
class ApplicationModule(val application: MyApplication) {
#ApplicationContext
#Provides
internal fun provideContext(): Context {
return application
}
#Provides
#DatabaseInfo
internal fun provideDatabaseName(): String {
return "dummy_db"
}
#Provides
#DatabaseInfo
internal fun provideDatabaseVersion(): Int? {
return 1
}
#Provides
#NetworkInfo
internal fun provideApiKey(): String {
return "SOME_API_KEY"
}
}
ApplicationComponent:
package com.example.daggerappkotlin.di.component
import android.content.Context
import com.example.daggerappkotlin.MyApplication
import com.example.daggerappkotlin.data.local.DatabaseService
import com.example.daggerappkotlin.data.remote.NetworkService
import com.example.daggerappkotlin.di.module.ApplicationModule
import com.example.daggerappkotlin.di.qualifier.ApplicationContext
import dagger.Component
import javax.inject.Singleton
#Singleton
#Component(modules = [ApplicationModule::class])
interface ApplicationComponent {
fun inject(application: MyApplication)
#ApplicationContext
val context: Context
val networkService: NetworkService
val databaseService: DatabaseService
}
I am trying to do the building in MainActivity, HomeFragment and the MyApplication....
GithubRepo

Categories

Resources