Search code examples
androidkotlinkoin

No Bean Definition Found exception


2022-06-20 18:59:22.201 20149-20149/com.xx.xxxx E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.xx.xxxx, PID: 20149
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:681)
 Caused by: java.lang.reflect.InvocationTargetException
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:681) 
 Caused by: org.koin.core.error.NoBeanDefFoundException: |- No definition found for class:'com.xx.xxxx.di.PreferencesManager'. Check your definitions!
    at org.koin.core.scope.Scope.throwDefinitionNotFound(Scope.kt:304)
    at org.koin.core.scope.Scope.resolveValue(Scope.kt:274)
    at org.koin.core.scope.Scope.resolveInstance(Scope.kt:241)
    at org.koin.core.scope.Scope.get(Scope.kt:204)
    at com.xx.xxxx.SplashActivity$special$$inlined$inject$default$1.invoke(ComponentCallbackExt.kt:61)
    at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
    at com.xx.xxxx.SplashActivity.getMyPref(SplashActivity.kt:16)
    at com.xx.xxxx.SplashActivity.callNextScreen(SplashActivity.kt:28)
    at com.xx.xxxx.SplashActivity.onCreate$lambda-0(SplashActivity.kt:24)
    at com.xx.xxxx.SplashActivity.$r8$lambda$ZKKoKfwsv3qwgbmTc6lA0Ow_bOM(SplashActivity.kt)
    at com.xx.xxxx.SplashActivity$$ExternalSyntheticLambda0.run(D8$$SyntheticClass)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:179)
    at android.app.ActivityThread.main(ActivityThread.java:5730)

I am facing some issue on Koin DI.

import android.app.Application
import org.koin.android.ext.koin.androidContext
import org.koin.core.context.loadKoinModules
import org.koin.core.context.startKoin

//import org.koin.core.context.GlobalContext.startKoin
//import org.koin.android.ext.android.startKoin
class BaseApplication : Application() {

companion object {
    lateinit var ins: BaseApplication
}

override fun onCreate() {
    super.onCreate()
    ins = this
    startKoin {
        androidContext(this@BaseApplication)
     //            modules(listOf(appModule, repoModule, viewModelModule))
        val modules = listOf(
            appModule
        )
        loadKoinModules(modules)
    }
    }
    }

My AppModuleClassBelow

  val appModule = module {
 
     single { provideAppPreference(androidApplication()) }

  }
  private fun provideAppPreference(application: Application): PreferencesManager {
  val myPref = application.applicationContext.getSharedPreferences(
    "Patient",
    Context.MODE_PRIVATE
  )
   return PreferencesManager(myPref)
 }

My PreferenceManagerClass is below

class PreferencesManager(private val myPref: SharedPreferences) {


companion object {
    var KEY_AUTH_TOKEN = "auth_token"
    var KEY_FCM_TOKEN = "fcm_token"
    var KEY_USER_MODEL = "user_model"
}

fun isLogin(): Boolean {
    return getUserModel()?.firstname?.isNotEmpty() == true
}

fun getMobileNumber(): String {
    return getUserModel()?.phone ?: ""
}

fun getEmail(): String {
    return getUserModel()?.email ?: ""
}

fun getUserName(): String {
    return getUserModel()?.firstname ?: ""
}

fun getUserModel(): UserModel? {
    return Gson().fromJson(getStringValue(KEY_USER_MODEL), UserModel::class.java)
}

fun setUserModel(userModel: UserModel?) {
    val str = Gson().toJson(userModel, UserModel::class.java)
    setStringValue(KEY_USER_MODEL, str)
}

fun getNameForPayment(): String {
    val s = getUserName()
    return if (s.isEmpty()) {
        getStr(R.string.app_name)
    } else {
        s
    }
}

fun getEmailForPayment(): String {
    val s = getEmail()
    return if (s.isEmpty()) {
        "[email protected]"
    } else {
        s
    }
}

fun getMobileForPayment(): String {
    val s = getMobileNumber()
    return if (s.isEmpty() || s.length < 10) {
        "9876543210"
    } else {
        s
    }
}

fun resetCartList() {
    val currentUserId = getStringValue("UserId")
    myPref.edit().putString("cart_list$currentUserId", "").commit()
}

fun generateFCMToken() {
    //   myPref.saveFCM("Test fcmToken");
    /*FirebaseMessaging.getInstance().token
        .addOnCompleteListener { task: Task<String?> ->
            if (!task.isSuccessful) {
                setStringValue(PREF_KEY_FCM_TOKEN,"Fetching FCM registration token failed " + task.exception)
                Log.w(ContentValues.TAG,"Fetching FCM registration token failed",task.exception)
                return@addOnCompleteListener
            }

            // Get new FCM registration token
            val fcmToken = task.result
            if (fcmToken != null) {
                if (fcmToken.isNotEmpty()) {
                    setStringValue(PREF_KEY_FCM_TOKEN,fcmToken)
                } else {
                    setStringValue(PREF_KEY_FCM_TOKEN,"GetInstanceId Failed")
                }
            }
        }*/
}

fun getLastReservationId(): String {
    return getStringValue("reservationId")
}

fun setLastReservationId(token: String?) {
    setStringValue("reservationId", token)
}

fun getLastStationId(): String {
    return getStringValue("StationId")
}

fun setLastStationId(token: String?) {
    setStringValue("StationId", token)
}

fun getAccessToken(): String {
    return getStringValue(KEY_AUTH_TOKEN)
}

fun setAccessToken(token: String?) {
    setStringValue(KEY_AUTH_TOKEN, token)
}

fun setStringValue(keyName: String?, value: String?) {
    myPref.edit().putString(keyName, value).apply()
}

fun getStringValue(keyName: String?): String {
    return AppValidator.toStr(myPref.getString(keyName, ""))
}

fun setBooleanValue(keyName: String?, value: Boolean) {
    myPref.edit().putBoolean(keyName, value).apply()
}

fun getBooleanValue(keyName: String?): Boolean {
    return myPref.getBoolean(keyName, false)
}

fun setIntValue(keyName: String?, value: Int) {
    myPref.edit().putInt(keyName, value).apply()
}

fun getIntValue(keyName: String?): Int {
    return myPref.getInt(keyName, 0)
}

fun remove(key: String?) {
    myPref.edit().remove(key).apply()
}

fun clear(): Boolean {
    return myPref.edit().clear().commit()
}

fun resetAllPref() {
    clear()
}


}

I am using this DI for store some information for my app. I have inject this in my Activity. like below.

   private val myPref: PreferencesManager by inject()

But when I try to access this, I am getting above mentioned error and app crashes.

Yours help really appreciated.

EDIT

I tried with not lazy type injection. facing the same Error.

 private val myPref: PreferencesManager = get ()

EDIT

When I debug after injection on Splashactivity I am getting following response, response is attached as image

image here

Lazy value not initialised yet error coming.

Did I make any mistake on this? after this line, app crashes with above error.

org.koin.core.error.NoBeanDefFoundException

EDIT

instead of single, if I used Scope component, like below,

val activityModule = module {
scope<SplashActivity> {
    scoped<PreferencesManager> {
        provideAppPreference(androidApplication())
    }
}

}

private fun provideAppPreference(application: Application): PreferencesManager {
 val myPref = application.applicationContext.getSharedPreferences(
    "default",
    Context.MODE_PRIVATE
)
  return PreferencesManager(myPref)
}

and the injection as follows,

class SplashActivity : AppCompatActivity(),AndroidScopeComponent{

override val scope: Scope by activityScope()
private val myPref:PreferencesManager by inject<PreferencesManager>()

private lateinit var binding: ActivitySplashBinding

//    private val userViewModel:UsersViewModel by viewModel()
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivitySplashBinding.inflate(layoutInflater)
    setContentView(binding.root)
    changeStatusBarColor(getColorCompat(R.color.white), true)
 //        makeSendOtpReq()
    Handler(Looper.getMainLooper()).postDelayed({
        callNextScreen()
    }, 5000)

}
private fun callNextScreen() {
    if(!myPref.isLogin()){
        startActivity(Intent(this, AuthActivity::class.java))
    }else{
        startActivity(Intent(this, MainActivity::class.java))
    }

   /* startActivity(Intent(this, MainActivity::class.java))
    finish()
  */
   }
  }

this is working fine. it is not working on single only. I don't know why. Anybody know means, provide the feedback.

Helps will be appreciated.


Solution

  • I've got it to work first try, here's the code that I have used:

    // StackOverflow72688110App.kt
    package com.trifork.stackoverflow72688110
    
    import android.app.Application
    import android.content.Context
    import android.content.SharedPreferences
    import android.util.Log
    import org.koin.android.ext.koin.androidContext
    import org.koin.android.ext.koin.androidLogger
    import org.koin.core.context.loadKoinModules
    import org.koin.core.context.startKoin
    import org.koin.dsl.module
    
    val appModule = module {
        single {
            val sharedPreferences = sharedPreferences("Patient", get())
            PreferenceManager(sharedPreferences)
        }
    }
    
    
    class PreferenceManager(private val sharedPreferences: SharedPreferences) {
        fun printSomething() {
            Log.d("PreferenceManager", "Hi from injected PreferenceManager")
            Log.d("PreferenceManager", sharedPreferences.all.toString())
        }
    }
    
    class StackOverflow72688110App : Application() {
    
        override fun onCreate() {
            super.onCreate()
            val app = this
            startKoin {
                androidContext(app)
                androidLogger()
                loadKoinModules(appModule)
            }
        }
    }
    
    
    private fun sharedPreferences(prefsName: String, context: Context): SharedPreferences =
        context.getSharedPreferences(prefsName, Context.MODE_PRIVATE)
    
    // MainActivity.kt
    package com.trifork.stackoverflow72688110
    
    import androidx.appcompat.app.AppCompatActivity
    import android.os.Bundle
    import org.koin.android.ext.android.inject
    
    class MainActivity : AppCompatActivity() {
        private val preferenceManager by inject<PreferenceManager>()
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            preferenceManager.printSomething()
        }
    }
    

    The output that this code yields:

    logging output


    Now to why yours doesn't work?

    1. Make sure you've added android:name=".StackOverflow72688110App" to your <application> in the AndroidManifest.xml file. This ensures that your onCreate method will be called and hence the startKoin as well.
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools">
    
        <application
            android:name=".StackOverflow72688110App"
            ...>
    ...
        </application>
    
    </manifest>
    
    1. From your activity make sure your import for inject is import org.koin.android.ext.android.inject

    2. Make sure that the generic that you pass into the inject is the correct class of PreferenceManager. Note that exists a class in android.preference.PreferenceManager that is not the one you're interested in. So make sure you're importing the right package name for your PreferenceManager