我宣布有哪几种方法之一ApplicationComponent。当我尝试在任何片段或活动的应用程序组件的访问方法,我可以通过建立应用级的compoent,但是当我把这个ApplicationComponent到一些其他的组件作为依赖,而现在当我尝试访问该方法时说“无@提供注解方法不能被提供。”。
以前,当我使用像这样在Java中,我能够访问任何其他组件类ApplicationComponent类的方法,但在科特林,我无法访问。请帮我解决这个问题。!
这里,是我已经尝试了代码。
LmsApplicationComponent.kt
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
}
在这里,我已经包含了两个模块,即RetrofitServiceModule和RepositoryModule。
RetrofitServiceModule.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
}
}
RetrofitServiceModule包括NetworkModule作为其依赖性,因此,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需要ContextModule.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()
我曾访问过它没有任何问题,但是当我试图通过片段的组件来访问这同一个对象,它给出了一个失踪绑定错误。请找到碎片的组成部分代码PendPsychoComponent.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)
}
正如你所看到的,我已经addded依赖标签与AppComponent的价值,但我无法访问LmsApplicationComponent的方法,这种方法,但我能够访问它时,我在Java中使用了。请帮我解决这个问题。!提前致谢。
你需要建立你的片段组成部分,并使用你的应用程序组件的依赖。此外,您不需要设置一个实例viewModelFactory
匕首会为你做到这一点。
事情是这样的:
DaggerPendPsychoComponent.builder()
.lmsApplicationComponent(LmsAndroidApplication.get(activity).component())
.pendPsychoModule(PendPsychoModule())
.build()
.inject(this)