Search code examples
androidkotlinmvvmandroid-contextkodein

Android Pass Context in object


I need to pass the Application Context to an object. This is to call a function to intercept in the okhttpClient, my connection service. I'am using an object class to build the connection to the server with retrofit and an external interface with my services.

object DfreeApiService  {

   private lateinit var interceptor: HttpLoggingInterceptor
   private lateinit var okHttpClient: OkHttpClient
   private lateinit var networkConnectivityInterceptor: NetworkConnectivityInterceptor

   val client: Retrofit
   get() {
       networkConnectivityInterceptor= NetworkConnectivityInterceptor() //cannot pass the context here
       interceptor = HttpLoggingInterceptor()
       interceptor.level = HttpLoggingInterceptor.Level.BODY
       okHttpClient= OkHttpClient.Builder()
          // .addInterceptor(networkConnectivityInterceptor)
           .addInterceptor(interceptor)
           .connectionSpecs(
               Arrays.asList(ConnectionSpec.MODERN_TLS, ConnectionSpec.CLEARTEXT)
           )
           .followRedirects(true)
           .followSslRedirects(true)
           .retryOnConnectionFailure(true)
           .connectTimeout(20, TimeUnit.SECONDS)
           .readTimeout(20, TimeUnit.SECONDS)
           .writeTimeout(20, TimeUnit.SECONDS)
           .cache(null)
           .build()

           val retrofit: Retrofit =Retrofit.Builder()
               .client(okHttpClient)
               .baseUrl("http://example:2000/")
               .addConverterFactory(GsonConverterFactory.create())
               .build()

       return retrofit

   }

}

And in the following code is my interface:

interface AuthenticationApi {

    @POST("ws/login")
    suspend fun login(@Body userInfo: UserInfo): Response<UserReponse>

    @POST("ws/register")
    suspend fun register(@Body userInfo: UserRegister): Response<UserReponse>

    @POST("ws/pw_recover")
    suspend fun pw_recover(@Body email: String): Response<BaseResponse>

    @POST("ws/login")
    suspend fun loginGoogle(@Body user: GoogleUser) : Response<UserReponse>


    companion object{
        operator fun invoke():AuthenticationApi{
            return DfreeApiService.client.create(AuthenticationApi::class.java)
        }
    }
  }

I'am using mvvm and kodein. Without the internet interceptor the app crashes when there is no internet. My interceptor:

    class NetworkConnectivityInterceptor(
    context: Context
    ) : Interceptor {

    private val applicationContext = context

    @RequiresApi(Build.VERSION_CODES.M)
    override fun intercept(chain: Interceptor.Chain): Response {
        if (!isInternetAvailable())
            throw NoInternetException("Make sure you have an active data connection")
        return chain.proceed(chain.request())
    }

    @RequiresApi(Build.VERSION_CODES.M)
    private fun isInternetAvailable(): Boolean {
        var result = false
        val connectivityManager =
            applicationContext.getSystemService(Application.CONNECTIVITY_SERVICE) as ConnectivityManager?
        connectivityManager?.let {
            it.getNetworkCapabilities(connectivityManager.activeNetwork)?.apply {
                result = when {
                    hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
                    hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
                    else -> false
                }

            }
        }
        return result
    }
}

Thanks for your attention


Solution

  • In the mainActivity:

    class ExampleApplication : Application(), KodeinAware {
    lateinit var context: Context
    override val kodein = Kodein.lazy {
        import(androidXModule(this@ExampleApplication))
        bind() from singleton { ExampleApiService }
        bind() from singleton { AuthenticationApi() }
        bind() from singleton { NetworkConnectivityInterceptor(instance()) }
        bind() from singleton { ExampleDataBase(instance()) }
        bind<UserRepository>() with singleton { UserRepository(instance(), instance()) }
        bind() from provider { AuthenticationLoginViewModelFactory(instance(),instance()) }
        bind() from provider { CreateAccountViewModelFactory(instance(),instance()) }
        bind() from provider { PasswordViewModelFactory(instance(),instance()) }
    }
    
    override fun onCreate() {
        super.onCreate()
        DfreeApiService.init(this)
    }
    

    }

    And in the object DfreeApiSercive:

    object DfreeApiService  {
    
    private lateinit var application: Application
    
    fun init(application: Application){
        this.application=application
    }
    
     private lateinit var interceptor: HttpLoggingInterceptor
    private lateinit var okHttpClient: OkHttpClient
    private lateinit var networkConnectivityInterceptor: NetworkConnectivityInterceptor
    
    
    val client: Retrofit
    get() {
        networkConnectivityInterceptor= NetworkConnectivityInterceptor(application.applicationContext)
        interceptor = HttpLoggingInterceptor()
        interceptor.level = HttpLoggingInterceptor.Level.BODY
        okHttpClient= OkHttpClient.Builder()
            .addInterceptor(networkConnectivityInterceptor)
            .addInterceptor(interceptor)
    ...
    }
    }
    

    And with this way you can import the context to an object.