I am struggling to translate this retrofit class into Kotlin. It is basically a singleton that works as a client and I am not sure of my Kotlin implementation. UserAPI and ProfileAPI are just interfaces.
public class RetrofitService {
private static final String BASE_URL = "https://test.api.com/";
private ProfileAPI profileAPI;
private UserAPI userAPI;
private static RetrofitService INSTANCE;
/**
* Method that returns the instance
* @return
*/
public static RetrofitService getInstance() {
if (INSTANCE == null) {
INSTANCE = new RetrofitService();
}
return INSTANCE;
}
private RetrofitService() {
Retrofit mRetrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl(BASE_URL)
.build();
profileAPI = mRetrofit.create(ProfileAPI.class);
UserAPI = mRetrofit.create(UserAPI.class);
}
/**
* Method that returns the API
* @return
*/
public ProfileAPI getProfileApi() {
return profileAPI;
}
/**
* Method that returns the API
* @return
*/
public UserAPI getUserApi() {
return userAPI;
}
}
And this is my Kotlin implementation. As I understand this, the init block will be executed first when the class is instantiated.
class RetrofitService private constructor() {
/**
* Method that returns the API
* @return
*/
private val profileApi: ProfileAPI
private val userAPI: UserAPI
companion object {
private const val BASE_URL = "https://test.api.com/"
private var INSTANCE: RetrofitService? = null
/**
* Method that returns the instance
* @return
*/
fun getInstance(): RetrofitService? {
if (INSTANCE == null) {
INSTANCE = RetrofitService()
}
return INSTANCE
}
}
init {
val mRetrofit = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl(BASE_URL)
.build()
profileApi = mRetrofit.create(ProfileAPI::class.java)
UserAPI = mRetrofit.create(UserAPI::class.java)
}
}
But something tells me this is not the right way or it can be done better. Is there anything I can improve here?
UPDATE!!!
Based on comments and answer I have this implementation now
object RetrofitService {
private const val BASE_URL = "https://test.api.com"
private fun retrofitService(): Retrofit {
return Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl(BASE_URL)
.build()
}
val profileApi: ProfileAPI by lazy {
retrofitService().create(ProfileAPI::class.java)
}
val userApi: UserAPI by lazy {
retrofitService().create(UserAPI::class.java)
}
}
Then I would use it like this
RetrofitService.profileApi
Would that be alright?
Kotlin intentionally avoids the confusion people have with singletons in Java. And avoids the "wrong versions" of this pattern -- of which there are many. It instead provides the simpler and the safest form of singletons. Given the use of lazy() , if you have other members each would individually be lazy.
Using Singletons in Kotlin. By using the keyword object in your app, you're defining a singleton. A singleton is a design pattern in which a given class has only one single instance inside the entire app.
Deal with multiple threads(singleton thread safe) a Kotlin object actually relies on a Java static initialization block. t enables thread-safe lazy initialization without having to rely on a locking algorithm like the complex double-checked locking.
ConstructorsA class in Kotlin can have a primary constructor and one or more secondary constructors. The primary constructor is a part of the class header, and it goes after the class name and optional type parameters.
You could use something like:
object MyApi {
private const val BASE_URL = " https://www.MYAPI.com/"
private val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
private fun retrofit(): Retrofit {
return Retrofit.Builder()
.addConverterFactory(MoshiConverterFactory.create(moshi))
.addCallAdapterFactory(CoroutineCallAdapterFactory())
.client(clientBuilder.build())
.baseUrl(BASE_URL)
.build()
}
val retrofitService: MyApiService by lazy {
retrofit().create(MyApiService::class.java)
}
//If you want more service just add more val such as
val otherService: MyOtherService by lazy {
retrofit().create(MyOtherService::class.java
}
}
//To use it you just need to do:
MyApi.retrofitService
MyApi.otherService
object ClassName
is a singleton it'll only instance it once and reuse for next callby lazy
using this keyword, your retrofitService
will only be initialised the first time you call and then you'll reuse that same value, for more details look here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With