我声明了一个ApplicationComponent,它有几个方法。当我试图在任何片段或活动中访问应用程序组件的方法时,我可以使用应用程序类的build component,但是当我将此ApplicationComponent作为依赖项放入其他组件时,现在当我试图访问该方法时
它说“没有@Provides注释的方法就不能提供”。
以前,当我在Java中像这样使用时,我能够访问
其他任何组件类中的ApplicationComponent类的方法,但在kotlin中,我无法访问。请帮我解决这个问题。!!
这是我试过的密码。
硅酸盐组分
package com.satincreditcare.satin.android.dagger.component
import android.arch.lifecycle.ViewModelProvider
import com.satincreditcare.satin.android.dagger.module.RepositoryModule
import com.satincreditcare.satin.android.dagger.module.RetrofitServiceModule
import com.satincreditcare.satin.android.dagger.qualifier.LMSApplicationQualifier
import com.satincreditcare.satin.android.dagger.qualifier.LMSAuthQualifier
import com.satincreditcare.satin.android.dagger.scope.LmsAndroidApplicationScope
import com.satincreditcare.satin.android.network.rest_controller.RestInterface
import dagger.Component
/**
* Created by Abhishek Jha on 1/28/2019.
*/
@LmsAndroidApplicationScope
@Component(modules = [(RetrofitServiceModule::class), (RepositoryModule::class)])
open interface LmsApplicationComponent {
@LMSApplicationQualifier
fun getRestInterface():RestInterface
@LMSApplicationQualifier
fun provideViewModelFactory(): ViewModelProvider.Factory
@LMSAuthQualifier
fun getAuthRestInterface():RestInterface
@LMSAuthQualifier
fun provideAuthViewModelFactory(): ViewModelProvider.Factory
}
在这里,我包含了两个模块,即reformationservicemodule和RepositoryModule。
改造服务模块.kt
package com.satincreditcare.satin.android.dagger.module
import android.content.Context
import com.fatboyindustrial.gsonjodatime.DateTimeConverter
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.satincreditcare.satin.android.constants.REST_API
import com.satincreditcare.satin.android.network.rest_controller.RestInterface
import com.satincreditcare.satin.android.dagger.qualifier.LMSApplicationQualifier
import com.satincreditcare.satin.android.dagger.qualifier.LMSAuthQualifier
import com.satincreditcare.satin.android.dagger.scope.LmsAndroidApplicationScope
import dagger.Module
import dagger.Provides
import okhttp3.OkHttpClient
import org.joda.time.DateTime
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
/**
* Created by Abhishek Jha on 1/29/2019.
*/
@Module(includes = [(NetworkModule::class)])
open class RetrofitServiceModule {
@Provides
@LmsAndroidApplicationScope
@LMSApplicationQualifier
fun restInterface(@LMSApplicationQualifier retrofit: Retrofit): RestInterface{
return retrofit.create(RestInterface::class.java)
}
@Provides
@LmsAndroidApplicationScope
@LMSApplicationQualifier
fun retrofit(gson: Gson, @LMSApplicationQualifier okHttpClient: OkHttpClient,
@LMSApplicationQualifier baseUrl: String): Retrofit{
return Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(okHttpClient)
.baseUrl(baseUrl)
.build()
}
@Provides
@LmsAndroidApplicationScope
@LMSApplicationQualifier
fun baseUrl(context: Context): String{
return REST_API.getInstance(context).API
}
@Provides
@LmsAndroidApplicationScope
fun gson(): Gson{
val gsonBuilder: GsonBuilder = GsonBuilder()
gsonBuilder.registerTypeAdapter(DateTime::class.java, DateTimeConverter())
return gsonBuilder.create()
}
@Provides
@LmsAndroidApplicationScope
@LMSAuthQualifier
fun restInterfaceAuth(@LMSAuthQualifier retrofit: Retrofit): RestInterface{
return retrofit.create(RestInterface::class.java)
}
@Provides
@LmsAndroidApplicationScope
@LMSAuthQualifier
fun retrofitAuth(gson: Gson, @LMSAuthQualifier okHttpClient: OkHttpClient,
@LMSAuthQualifier baseUrl: String): Retrofit{
return Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(okHttpClient)
.baseUrl(baseUrl)
.build()
}
@Provides
@LmsAndroidApplicationScope
@LMSAuthQualifier
fun baseUrlAuth(context: Context): String{
return REST_API.getInstance(context).OAUTH_URL
}
}
reformationservicemodule包含NetworkModule作为其依赖项
所以,
网络模块.kt
package com.satincreditcare.satin.android.dagger.module
import android.content.Context
import android.os.Build
import android.util.Base64
import com.satincreditcare.satin.android.R
import com.satincreditcare.satin.android.constants.AppConstants
import com.satincreditcare.satin.android.constants.REST_API
import com.satincreditcare.satin.android.events.AllEvents
import com.satincreditcare.satin.android.events.Event
import com.satincreditcare.satin.android.network.exception.InvalidRefreshTokenException
import com.satincreditcare.satin.android.network.exception.InvalidTokenException
import com.satincreditcare.satin.android.network.exception.NoConnectivityException
import com.satincreditcare.satin.android.dagger.qualifier.LMSApplicationQualifier
import com.satincreditcare.satin.android.dagger.qualifier.LMSAuthQualifier
import com.satincreditcare.satin.android.dagger.scope.LmsAndroidApplicationScope
import com.satincreditcare.satin.android.utils.AppUtility
import com.satincreditcare.satin.android.utils.DataHolder
import com.satincreditcare.satin.android.utils.NetworkUtils
import dagger.Module
import dagger.Provides
import okhttp3.*
import okhttp3.logging.HttpLoggingInterceptor
import org.greenrobot.eventbus.EventBus
import timber.log.Timber
import java.io.File
import java.io.IOException
import java.io.InputStream
import java.nio.charset.Charset
import java.security.KeyStore
import java.security.cert.Certificate
import java.security.cert.CertificateFactory
import java.util.*
import java.util.concurrent.TimeUnit
import javax.net.ssl.*
/**
* Created by Abhishek Jha on 1/29/2019.
*/
@Module(includes = [(ContextModule::class)])
open class NetworkModule {
companion object {
val DEFAULT_READ_TIMEOUT: Long = 180
val DEFAULT_CONNECT_TIMEOUT: Long = 180
val maxRequestsPerHost: Int = 5
}
@Provides
@LmsAndroidApplicationScope
@LMSApplicationQualifier
fun okHttpClient(interceptorLogging: HttpLoggingInterceptor, cache: Cache,
sslSocketFactory: SSLSocketFactory, trustManager: X509TrustManager,
@LMSApplicationQualifier interceptor: Interceptor,
authenticator: Authenticator): OkHttpClient {
var okHttpClient: OkHttpClient = OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory, trustManager)
.readTimeout(DEFAULT_READ_TIMEOUT, TimeUnit.SECONDS)
.connectTimeout(DEFAULT_CONNECT_TIMEOUT, TimeUnit.SECONDS)
.addInterceptor(interceptorLogging)
.addInterceptor(interceptor)
.authenticator(authenticator)
.cache(cache)
.build()
if (AppConstants.SLOW_NETWORK_MODE) {
okHttpClient.dispatcher().maxRequestsPerHost = maxRequestsPerHost / 2
} else {
okHttpClient.dispatcher().maxRequestsPerHost = maxRequestsPerHost
}
return okHttpClient
}
@Provides
@LmsAndroidApplicationScope
@LMSAuthQualifier
fun okHttpClientAuth(interceptorLogging: HttpLoggingInterceptor, cache: Cache,
sslSocketFactory: SSLSocketFactory,
trustManager: X509TrustManager,
@LMSAuthQualifier interceptor: Interceptor): OkHttpClient {
var okHttpClient: OkHttpClient = OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory, trustManager)
.readTimeout(DEFAULT_READ_TIMEOUT, TimeUnit.SECONDS)
.connectTimeout(DEFAULT_CONNECT_TIMEOUT, TimeUnit.SECONDS)
.addInterceptor(interceptorLogging)
.addInterceptor(interceptor)
.cache(cache)
.build()
if (AppConstants.SLOW_NETWORK_MODE) {
okHttpClient.dispatcher().maxRequestsPerHost = maxRequestsPerHost / 2
} else {
okHttpClient.dispatcher().maxRequestsPerHost = maxRequestsPerHost
}
return okHttpClient
}
@Provides
@LmsAndroidApplicationScope
fun x509TrustManager(context: Context): X509TrustManager {
lateinit var trustManager: X509TrustManager
try {
//Load CAs
val cf: CertificateFactory = CertificateFactory.getInstance("X.509")
val cert: InputStream
if (REST_API.getInstance(context).API.equals(context.getString(R.string.PROD_URL),
ignoreCase = true)) {
cert = context.resources.openRawResource(R.raw.prod)
} else {
cert = context.resources.openRawResource(R.raw.dev_uat)
}
val ca: Certificate
try {
ca = cf.generateCertificate(cert)
} finally {
cert.close()
}
//Creating a keystore containing our trusted CAs
val keyStoreType: String = KeyStore.getDefaultType()
val keyStore: KeyStore = KeyStore.getInstance(keyStoreType)
keyStore.load(null, null)
keyStore.setCertificateEntry("ca", ca)
// creating a TrustManager that trusts the CAs in our KeyStore
val tmfAlgorithm: String = TrustManagerFactory.getDefaultAlgorithm()
val tmf: TrustManagerFactory = TrustManagerFactory.getInstance(tmfAlgorithm)
tmf.init(keyStore)
//X509Trust Manager
val trustManagers = tmf.trustManagers
if (trustManagers.size != 1 || trustManagers[0] !is X509TrustManager) {
throw IllegalStateException("Unexpected default trust managers:" + Arrays
.toString(trustManagers))
}
trustManager = trustManagers[0] as X509TrustManager
} catch (e: Exception) {
e.printStackTrace()
}
return trustManager
}
@Provides
@LmsAndroidApplicationScope
fun sslSocketFactory(trustManager: X509TrustManager): SSLSocketFactory {
lateinit var sslContext: SSLContext
lateinit var sslSocketFactory: SSLSocketFactory
try {
sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, arrayOf(trustManager), null)
sslSocketFactory = sslContext.socketFactory
} catch (e: Exception) {
e.printStackTrace()
}
return sslSocketFactory
}
@Provides
@LmsAndroidApplicationScope
fun httpLoggingInterceptor(): HttpLoggingInterceptor {
val interceptor: HttpLoggingInterceptor = HttpLoggingInterceptor(HttpLoggingInterceptor.Logger {
Timber.i(it)
})
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
return interceptor
}
@Provides
@LmsAndroidApplicationScope
@LMSAuthQualifier
fun interceptorAuth(context: Context): Interceptor {
val interceptor: Interceptor = Interceptor {
//Applying two interceptors work together
//Network Interceptor and OAuthTokenInterceptor
if (NetworkUtils.isNetworkAvailable(context)) {
//Here, we will check for the SecureHeaderInterceptor start
val deviceHeader: String = Build.MODEL + "$$" + AppUtility.getImei(context)
val headerValue: String = Credentials.basic(AppUtility.getOAuthClientId(context),
AppUtility.getOAuthClientSecret(context), Charset.forName(AppConstants.CHARSET_UTF8))
var rawRequest: Request = it.request()
rawRequest = rawRequest
.newBuilder()
.addHeader(AppConstants.HTTP_HEADER_AUTHORIZATION, headerValue)
.addHeader(AppConstants.HTTP_HEADER_DEVICE_AUTH, AppUtility
.encodeBase64(deviceHeader.trim(), Base64.NO_WRAP))
.build()
//Here, we will check for the OAuthTokenInterceptor end
try {
return@Interceptor it.proceed(rawRequest)
} catch (e: Exception) {
e.printStackTrace()
throw IOException(e)
}
} else {
throw NoConnectivityException()
}
}
return interceptor
}
@Provides
@LmsAndroidApplicationScope
@LMSApplicationQualifier
fun interceptor(context: Context): Interceptor {
return Interceptor { chain ->
//Applying two interceptors work together
//Network Interceptor and OAuthTokenInterceptor
if (NetworkUtils.isNetworkAvailable(context)) {
//Here, we will check for the OAuthTokenInterceptor start
var rawRequest = chain.request()
//getting token
if (DataHolder.getInstance() == null) {
throw InvalidTokenException()
}
val resOAuthToken = DataHolder.getInstance().oauthToken
?: throw InvalidTokenException()
if (!DataHolder.getInstance().isRefreshingToken) {
if (!DataHolder.getInstance().isRefreshTokenExpired) {
Timber.i("Sending request")
//locally checking life of access token
if (System.currentTimeMillis() < resOAuthToken.expiresOn) {
if (!AppConstants.IS_CUSTOM_IP) {
rawRequest = rawRequest.newBuilder()
.addHeader("Authorization", AppUtility
.createOAuthHeader(resOAuthToken.accessToken))
.build()
}
} else {
//Sending Signal to refresh access token from server
DataHolder.getInstance().isRefreshingToken = true
EventBus.getDefault().post(Event(AllEvents
.OAUTH_ACCESS_TOKEN_EXPIRED, false, resOAuthToken))
//dropping ongoing request(because access_token is expired)
throw InvalidTokenException()
}
} else {
//refresh token is expired (user should be logged out
throw InvalidRefreshTokenException(context)
}
} else {
//access token is getting refreshed so drop this request
Timber.i("access toke is already getting refreshed")
throw InvalidTokenException()
}
//Here, we will check for the OAuthTokenInterceptor end
//If everything goes well we can proceed to the below statement and satisfy
// the condition for the Network availability.
try {
return@Interceptor chain.proceed(rawRequest)//chain.request()
} catch (e: Exception) {
e.printStackTrace()
throw IOException(e)
}
} else {
throw NoConnectivityException()
}
//return chain.proceed(chain.request());
}
}
@Provides
@LmsAndroidApplicationScope
fun getAuthenticator(context: Context): Authenticator {
return Authenticator { route, response ->
val resOAuthToken = DataHolder.getInstance().oauthToken
//Checking if access token is getting refreshed.
if (!DataHolder.getInstance().isRefreshingToken) {
if (!DataHolder.getInstance().isRefreshTokenExpired) {
Timber.i("Now refreshing token")
//refreshing access_token from oauth server
DataHolder.getInstance().isRefreshingToken = true
EventBus.getDefault().post(Event(AllEvents
.OAUTH_ACCESS_TOKEN_EXPIRED, false, resOAuthToken))
} else {
//refresh token is expired (user should be logged out
throw InvalidRefreshTokenException(context)
}
} else {
Timber.i("already refreshing token")
//access token is getting refreshed so drop this request
//throw new InvalidTokenException();
}
//we are dropping every request
throw InvalidTokenException()
}
}
@Provides
@LmsAndroidApplicationScope
fun cache(cacheFile: File): Cache {
return Cache(cacheFile, 10 * 1000 * 1000)
}
@Provides
@LmsAndroidApplicationScope
fun file(context: Context): File{
return File(context.cacheDir, "okhttp_cache")
}
}
而NetworkModule需要依赖于
上下文模块.kt
package com.satincreditcare.satin.android.dagger.module
import android.content.Context
import com.satincreditcare.satin.android.dagger.scope.LmsAndroidApplicationScope
import dagger.Module
import dagger.Provides
/**
* Created by Abhishek Jha on 1/30/2019.
*/
@Module
open class ContextModule(context: Context) {
private val mContext: Context = context
@Provides
@LmsAndroidApplicationScope
fun context(): Context{
return mContext
}
}
和RepositoryModule.kt
package com.satincreditcare.satin.android.dagger.module
import android.arch.lifecycle.ViewModelProvider
import android.content.Context
import com.satincreditcare.satin.android.mvvm.data.AppRepository
import com.satincreditcare.satin.android.mvvm.viewmodel.CustomViewModelFactory
import com.satincreditcare.satin.android.mvvm.viewmodel.CustomViewModelFactoryAuth
import com.satincreditcare.satin.android.network.rest_controller.RestInterface
import com.satincreditcare.satin.android.dagger.qualifier.LMSApplicationQualifier
import com.satincreditcare.satin.android.dagger.qualifier.LMSAuthQualifier
import com.satincreditcare.satin.android.dagger.scope.LmsAndroidApplicationScope
import dagger.Module
import dagger.Provides
/**
* Created by Abhishek Jha on 1/30/2019.
*/
@Module(includes = [(RetrofitServiceModule::class), (ContextModule::class)])
open class RepositoryModule {
@Provides
@LmsAndroidApplicationScope
@LMSApplicationQualifier
fun appRepository(@LMSApplicationQualifier restInterface: RestInterface, context: Context): AppRepository{
return AppRepository(restInterface, context)
}
@Provides
@LmsAndroidApplicationScope
@LMSApplicationQualifier
fun provideViewModelFactory(@LMSApplicationQualifier appRepository: AppRepository): ViewModelProvider.Factory{
return CustomViewModelFactory(appRepository)
}
@Provides
@LmsAndroidApplicationScope
@LMSAuthQualifier
fun appRepositoryAuth(@LMSAuthQualifier restInterface: RestInterface, context: Context): AppRepository{
return AppRepository(restInterface, context)
}
@Provides
@LmsAndroidApplicationScope
@LMSAuthQualifier
fun provideViewModelFactoryAuth(@LMSAuthQualifier appRepository: AppRepository): ViewModelProvider.Factory{
return CustomViewModelFactoryAuth(appRepository)
}
}
因此,当我在应用程序类中获取ApplicationComponent时:
public class LmsAndroidApplication extends Application {
public static String TAG = BuildConfig.VERSION_NAME + AppConstants.EMPTY_SPACE;
public LmsApplicationComponent component;
public static LmsAndroidApplication get(Activity activity){
return (LmsAndroidApplication) activity.getApplication();
}
public LmsApplicationComponent component(){
return component;
}
@Override
public void onCreate() {
super.onCreate();
//Leak Canary should first be installed.
/*if(LeakCanary.isInAnalyzerProcess(this)){
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
return;
}
LeakCanary.install(this);*/
//Dagger Basic setup for Api and repository setup
if(BuildConfig.DEBUG){
Timber.plant(new Timber.DebugTree());
}
component = DaggerLmsApplicationComponent
.builder()
.contextModule(new ContextModule(this))
.build();
}
}
我在片段类中访问ApplicationComponent的方法如下:
@Inject
@LMSApplicationQualifier
lateinit var viewModelFactory: ViewModelProvider.Factory
var lmsApplicationComponent: LmsApplicationComponent = LmsAndroidApplication.get(activity).component()
viewModelFactory = lmsApplicationComponent.provideViewModelFactory()
我访问它没有任何问题,但当我试图通过Fragment的组件访问同一个对象时,它会给出一个丢失的绑定错误。请找到片段的组件代码pendpycomponent.kt
package com.satincreditcare.satin.android.dagger.component
import com.satincreditcare.satin.android.dagger.module.PendPsychoModule
import com.satincreditcare.satin.android.dagger.scope.PendPsychoScope
import com.satincreditcare.satin.android.pendPsychoMvvm.PendPsychoFragment
import dagger.Component
/**
* Created by Abhishek Jha on 1/30/2019.
*/
@PendPsychoScope
@Component(dependencies = [(LmsApplicationComponent::class)], modules = [(PendPsychoModule::class)])
interface PendPsychoComponent {
fun injectPendingPsycho(pendPsychoFragment: PendPsychoFragment)
}
如您所见,我已经用AppComponent的值添加了dependencies标记,但是我无法通过这种方式访问LmsApplicationComponent的方法,但是当我在Java中使用时,我能够访问它。请帮我解决这个问题。!!提前谢谢。