Retrofit with Dagger 2 - android - android

I am using from bellow sample:
New Android Injector with Dagger 2
How can I define my SQLite Connection and retrofit and etc... in this class AppModule

Here is an example how you can do it. Hope this would help.
#Module
class AppModule(val app: Context) {
#Provides
#Singleton
fun provideContext(): Context = app
#Provides
#Singleton
fun provideDatabase(context: Context): Database = Room.databaseBuilder(context, Database::class.java, "my_db").build()
#Provides
#Singleton
fun provideUserDao(database: Database): UserDao = database.userDao()
#Provides
#Singleton
fun providePostDao(database: Database): PostDao = database.postDao()
#Provides
#Singleton
fun provideCommentsDao(database: Database): CommentDao = database.commentDao()
#Provides
#Singleton
fun provideHttpLogging(): HttpLoggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
#Provides
#Singleton
fun provideOkHttpClient(loggingInterceptor: HttpLoggingInterceptor): OkHttpClient =
OkHttpClient.Builder().addInterceptor(loggingInterceptor).build()
#Provides
#Singleton
fun provideJackson(): JacksonConverterFactory = JacksonConverterFactory.create()
#Provides
#Singleton
fun provideRetrofit(okHttpClient: OkHttpClient, jackson: JacksonConverterFactory): Retrofit = Retrofit.Builder()
.client(okHttpClient)
.baseUrl(baseUrl)
.addConverterFactory(jackson)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
#Provides
#Singleton
fun provideApiInterface(retrofit: Retrofit): ApiInterface = retrofit.create(
ApiInterface::class.java
)
}

Related

#Provides methods can only be present within a #Module or #ProducerModule

I wrote network module in project. I checked all similiar codes and qustions there are some people have same problem. But they all didn't solve this problem for me. I don't know what is problem here.
This is the error:
error: #Provides methods can only be present within a #Module or #ProducerModule
public static final com.technoface.iga.api.BoardingPassService postBoardingPassesRead(#org.jetbrains.annotations.NotNull()
NetworkModule.kt
#Module
#InstallIn(SingletonComponent::class)
object NetworkModule {
#Singleton
#Provides
fun provideBaseUrl() = BuildConfig.BASE_URL
#Provides
#Singleton
fun provideLoggingInterceptor(): HttpLoggingInterceptor {
return HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
}
#ServiceInterceptorOkHttpClient
#Singleton
#Provides
fun providesServiceInterceptor(clientPreferences: ClientPreferences): ServiceInterceptor =
ServiceInterceptor(clientPreferences)
#Provides
#Singleton
fun provideOkHttpClient(
logging: HttpLoggingInterceptor,
#ServiceInterceptorOkHttpClient
serviceInterceptor: ServiceInterceptor
): OkHttpClient {
return OkHttpClient.Builder()
.readTimeout(60, TimeUnit.SECONDS)
.connectTimeout(60, TimeUnit.SECONDS)
.addInterceptor(logging)
.addInterceptor(serviceInterceptor)
.build()
}
#Provides
#Singleton
fun provideNetworkResultCallAdapterFactory(): CallAdapter.Factory {
return NetworkResultCallAdapterFactory.create()
}
#Provides
#Singleton
fun provideRetrofit(client: OkHttpClient, callAdapterFactory: CallAdapter.Factory): Retrofit {
return Retrofit.Builder()
.baseUrl(BuildConfig.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(callAdapterFactory)
.client(client)
.build()
}
#Provides
#Singleton
fun postBoardingPassesRead(serviceBuilder: ServiceBuilder): BoardingPassService = serviceBuilder.buildService(BoardingPassService::class.java)
#Qualifier
#Retention(AnnotationRetention.BINARY)
annotation class BaseUrl
#Qualifier
#Retention(AnnotationRetention.BINARY)
annotation class ServiceInterceptorOkHttpClient
BoardingPassServiceRepo.kt
class BoardingPassServiceRepo #Inject constructor(
private val boardingPassService: BoardingPassService
) {
suspend fun postBoardingPassesRead(boardingPassInfoRequest: BoardingPassInfoRequest) = boardingPassService.postBoardingPassesRead(
encryptData(boardingPassInfoRequest)
)
}
AppModule.kt
#Module
#InstallIn(SingletonComponent::class)
object AppModule {
#Singleton
#Provides
fun provideClientPreferences(
#ApplicationContext context: Context
) = ClientPreferences(context)
}
class BoardingPassServiceRepo #Inject constructor(
private val boardingPassService: BoardingPassService
) {
suspend fun postBoardingPassesRead(boardingPassInfoRequest: BoardingPassInfoRequest) = boardingPassService.postBoardingPassesRead(
encryptData(boardingPassInfoRequest)
)
}
Update Gradle version.
Changed gradle version.
Clean, Rebuild, Invalidate cache
Deactivated Antivirus.

Dagger hilt Cannot be provided without an #Provides-annotated method

I am new with dagger using. So, I can't solve whats the problem with this. I just want to ask here to solve it.
This is the error:
C:\Users\msi\Documents\MyAndroidProjects\MovieProjects\app\build\generated\hilt\component_sources\debug\com\example\movieapp\App_HiltComponents.java:128:
error: [Dagger/MissingBinding]
com.example.movieapp.api.MovieAppService cannot be provided without an
#Provides-annotated method. public abstract static class SingletonC
implements App_GeneratedInjector,
^
com.example.movieapp.api.MovieAppService is injected at
com.example.movieapp.repository.MovieRepository(movieAppService)
com.example.movieapp.repository.MovieRepository is injected at
com.example.movieapp.viewmodel.MainViewModel(repository, �)
com.example.movieapp.viewmodel.MainViewModel is injected at
com.example.movieapp.viewmodel.MainViewModel_HiltModules.BindsModule.binds(arg0)
#dagger.hilt.android.internal.lifecycle.HiltViewModelMap java.util.Map<java.lang.String,javax.inject.Provider<androidx.lifecycle.ViewModel>>
is requested at
dagger.hilt.android.internal.lifecycle.HiltViewModelFactory.ViewModelFactoriesEntryPoint.getHiltViewModelMap()
[com.example.movieapp.App_HiltComponents.SingletonC ?
com.example.movieapp.App_HiltComponents.ActivityRetainedC ?
com.example.movieapp.App_HiltComponents.ViewModelC]
MainViewModel.kt
#HiltViewModel
class MainViewModel#Inject constructor(
private val repository: MovieRepository,
#ApplicationContext private val context: Context
) : ViewModel() {
val movieList = MutableLiveData<Resource<Movie>>()
fun getAllMovies(movieName: String) {
movieList.postValue(Resource.Loading())
viewModelScope.launch {
try {
if (hasInternetConnection(context)) {
val response = repository.getMovies(movieName, "ffe9063f")
movieList.postValue(Resource.Success(response.body()!!))
} else
movieList.postValue(Resource.Error("Internet yok"))
} catch (ex: Exception) {
when (ex) {
is IOException -> movieList.postValue(Resource.Error("Network Failure " + ex.localizedMessage))
else -> movieList.postValue(Resource.Error("Conversion Error"))
}
}
}
}
}
MovieRepository.kt
#Singleton
class MovieRepository #Inject constructor(private val movieAppService: MovieAppService) {
suspend fun getMovies(title: String, aKey: String): Response<Movie> = withContext(
Dispatchers.IO
) {
val movies = movieAppService.getMovies(title = title, aKey = aKey)
movies
}
}
ApiModule.kt
class ApiModule {
#Module
#InstallIn(SingletonComponent::class)
object ApiModule {
#Provides
#Singleton
fun provideLoggingInterceptor(): HttpLoggingInterceptor {
return HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
}
#Provides
#Singleton
fun provideOkHttpClient(logging: HttpLoggingInterceptor): OkHttpClient {
return OkHttpClient.Builder()
.addInterceptor(logging)
.connectTimeout(15, TimeUnit.SECONDS) // connect timeout
.readTimeout(15, TimeUnit.SECONDS)
.build()
}
#Provides
#Singleton
fun provideRetrofit(client: OkHttpClient): Retrofit {
return Retrofit.Builder()
.baseUrl(ENDPOINT)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build()
}
#Provides
#Singleton
fun provideMovieAppService(retrofit: Retrofit): MovieAppService {
return retrofit.create(MovieAppService::class.java)
}
}
}
MovieAppService.kt
interface MovieAppService {
companion object {
const val ENDPOINT = "http://www.omdbapi.com/"
}
#GET(".")
suspend fun getMovies(#Query("t") title: String,#Query("apikey") aKey: String): Response<Movie>
}
Do not wrap your singleton object module with a same named class. Change your module file like this or change your class name
#Module
#InstallIn(SingletonComponent::class)
object ApiModule {
#Provides
#Singleton
fun provideLoggingInterceptor(): HttpLoggingInterceptor {
return HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
}
#Provides
#Singleton
fun provideOkHttpClient(logging: HttpLoggingInterceptor): OkHttpClient {
return OkHttpClient.Builder()
.addInterceptor(logging)
.connectTimeout(15, TimeUnit.SECONDS) // connect timeout
.readTimeout(15, TimeUnit.SECONDS)
.build()
}
#Provides
#Singleton
fun provideRetrofit(client: OkHttpClient): Retrofit {
return Retrofit.Builder()
.baseUrl(ENDPOINT)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build()
}
#Provides
#Singleton
fun provideMovieAppService(retrofit: Retrofit): MovieAppService {
return retrofit.create(MovieAppService::class.java)
}
}

Screen rotation problem in viewmodel with dagger-hilt with injection

I have a problem with injection dagger into view model.The problem is that losing form inputs when rotating the screen.Is the problem in my injection or initialize my view model? Here is my viewmodel;
#HiltViewModel
class ProfilIslemViewModel #Inject constructor(application: Application,
private val kullaniciService: KullaniciService,
private val kullaniciDao:KullaniciDao
): AndroidViewModel(application), CoroutineScope {...}
And here is my fragment that use this view model;
#AndroidEntryPoint
class ProfilIslemFragment:Fragment(), ProfilIslemFragmentClickListener {
private val viewModel: ProfilIslemViewModel by viewModels();
...
}
Here is the module that injected class;
#Module
#InstallIn(SingletonComponent::class)
object KutuphanemAppModule {
#Singleton
#Provides
fun provideKutuphanemDatabase
(#ApplicationContext context:Context) = Room.databaseBuilder(
context,
KutuphanemDatabase::class.java,
KUTUPHANEM_DB_NAME
).build();
#Singleton
#Provides
fun provideRetrofit(client: OkHttpClient):Retrofit =
Retrofit.Builder()
.baseUrl(API_URL)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
#Singleton
#Provides
fun provideHttpClient(customSharedPreferences: CustomSharedPreferences):OkHttpClient{
return OkHttpClient.Builder().addInterceptor(object:Interceptor{
override fun intercept(chain: Interceptor.Chain): Response {
val request:Request = chain.request().newBuilder().addHeader("Authorization",
"Bearer "+customSharedPreferences.getStringFromSharedPreferences(APP_TOKEN_KEY).trim()).build();
return chain.proceed(request);
}
}).build();
}
#Singleton
#Provides
fun provideParametreDao(database: KutuphanemDatabase) = database.getParametreDao();
#Singleton
#Provides
fun provideParametreApi(retrofit: Retrofit):IParametreService = retrofit.create(IParametreService::class.java);
#Singleton
#Provides
fun provideKullaniciApi(retrofit: Retrofit):KullaniciService = retrofit.create(KullaniciService::class.java);
#Singleton
#Provides
fun provideKitapApi(retrofit: Retrofit):IKitapService = retrofit.create(IKitapService::class.java);
#Singleton
#Provides
fun provideKullaniciDao(database: KutuphanemDatabase) = database.getKullaniciDao();
}
When I rotate the screen the inputs are losing. How to solve this problem?
I found the error. It is not relevant my view model or injections. It caused by two way databinding. But even so I put this line into the contructor of viewmodel;
private val savedStateHandle: SavedStateHandle
I am controlling the state with this param.So my inputs are not losing.

Cannot be provided without an #Inject constructor or an #Provides-annotated method in dagger kotlin

I am converting one my project into kotlin source code.
While building the dagger I am encountered with this problem
cannot be provided without an #Inject constructor or an #Provides-annotated method.
I have 2 modules as below
#Module
class AppClient {
#Provides
#Singleton
fun provideHttpCache(application: Application): Cache {
val cacheSize = 10 * 1024 * 1024
return Cache(application.cacheDir, cacheSize.toLong())
}
#Provides
#Singleton
fun provideGson(): Gson {
val gsonBuilder = GsonBuilder()
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
// gsonBuilder.excludeFieldsWithoutExposeAnnotation();
return gsonBuilder.create()
}
#Provides
#Singleton
fun provideOkhttpClient(cache: Cache): OkHttpClient {
val interceptor = HttpLoggingInterceptor()
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
val client = OkHttpClient.Builder()
client.cache(cache)
client.addInterceptor(interceptor)
return client.build()
}
#Provides
#Singleton
fun provideRetrofit(gson: Gson, okHttpClient: OkHttpClient): Retrofit {
return Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(gson))
.baseUrl(NetworkConstant.BASE_URL)
.client(okHttpClient)
.build()
}
#Provides
#Singleton
fun provideApiCall(retrofit: Retrofit): NetworkCall {
return retrofit.create(NetworkCall::class.java)
}
#Provides
#Singleton
fun provideSharedPreference(application: Application): SharedPreferences {
return application.applicationContext.getSharedPreferences(
application.getString(R.string.shared_pref_name),
MODE_PRIVATE
)
}
#Provides
#Singleton
fun provideSharedPreferenceEditor(sharedPreferences: SharedPreferences): SharedPreferences.Editor {
return sharedPreferences.edit()
}
#Provides
#Singleton
fun provideAppPresenter(
sharedPreferences: SharedPreferences, editor: SharedPreferences.Editor,
apiCall: NetworkCall): AppPresenter {
return AppPresenter(sharedPreferences, editor, apiCall)
}
}
And the second module
#Module
class AppModule(val application: MyApplication) {
#Provides
#Singleton
internal fun provideApplication(): MyApplication {
return application
}
}
Application class
class MyApplication : Application() {
lateinit var mApiComponent: AppComponent
override fun onCreate() {
super.onCreate()
mApiComponent = DaggerAppComponent.builder()
.appModule(AppModule(this))
.appClient(AppClient())
.build()
}
fun getAppComponent(): AppComponent {
return mApiComponent
}
}
And the component interface
#Singleton
#Component(modules = [AppModule::class, AppClient::class])
interface AppComponent {
fun inject(activity: LoginActivity)
}
Can someone help out as to what's wrong here?
It seems I was passing the wrong application class. So silly of me

Dagger2 generating multiple instances of retrofit interceptor

Dagger 2 is generating multiple instances of retrofit interceptor despite marking it as singleton in dagger module. Now the problem is that AuthorizationInterceptor constructor gets called twice which I don't understand why and because of that the headers that I set after getting result from login API get sets to a different instance of Interceptor and while making call to some other API which requires authorizationToken the token is unset.
Here is my ApiModule
#Module
open class ApiModule {
#Provides
#Singleton
fun provideHttpLoggingInterceptor(): HttpLoggingInterceptor {
val loggingInterceptor = HttpLoggingInterceptor()
loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
return loggingInterceptor
}
#Provides
#Singleton
fun provideHeaderInterceptor(): Interceptor {
return AuthorizationInterceptor()
}
#Provides
#Singleton
fun provideHttpClient(interceptor: HttpLoggingInterceptor, headerInterceptor: Interceptor): OkHttpClient {
return OkHttpClient.Builder()
.addInterceptor(interceptor)
.addInterceptor(headerInterceptor)
.build()
}
#Provides
#Singleton
fun provideMoshi(): Moshi {
return Moshi.Builder()
.build()
}
#Provides
#Singleton
fun provideRetrofit(client: OkHttpClient, moshi: Moshi, apiConfig: ApiConfig): Retrofit {
return Retrofit.Builder()
.baseUrl(apiConfig.baseUrl)
.client(client)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
}
#Provides
#Singleton
fun provideFrappApi(retrofit: Retrofit): FrappApi {
return retrofit.create(FrappApi::class.java)
}
Here is my AuthorizationInterceptor class
#Singleton
class AuthorizationInterceptor #Inject constructor() : Interceptor {
override fun intercept(chain: Interceptor.Chain?): Response {
val request = chain?.request()
val requestBuilder = request?.newBuilder()
if (request?.header("No-Authorization") == null && authorization.isNotEmpty()) {
requestBuilder?.addHeader("Authorization", authorization)
}
return chain?.proceed(requestBuilder!!.build())!!
}
private var authorization: String = ""
fun setSessionToken(sessionToken: String) {
this.authorization = sessionToken
}
}
You dont need to make a provide method if you do a constructor injection.
Remove the provideHeaderInterceptor method, then update the provideHttpClient method like below,
#Provides
#Singleton
fun provideHttpClient(interceptor: HttpLoggingInterceptor,
headerInterceptor: AuthorizationInterceptor): OkHttpClient {
return OkHttpClient.Builder()
.addInterceptor(interceptor)
.addInterceptor(headerInterceptor)
.build()
}
Or if you dont like the solution above, you can remove the #Singleton and #Inject in your AuthorizationInterceptor class.

Categories

Resources