在 Kotlin 中实现 Retrofit 单例模式

11

我在将这个 retrofit 类翻译成 Kotlin 的过程中遇到了困难。它基本上是一个作为客户端的单例,但我不确定我的 Kotlin 实现是否正确。UserAPI 和 ProfileAPI 只是接口。

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;
}

}

这是我的 Kotlin 实现。据我理解,当类被实例化时,init 代码块将首先被执行。

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)
}
}

但是有一些东西告诉我这不是正确的方式,或者它可以做得更好。有什么可以在这里改进的吗?

更新!!!

根据评论和答案,我现在有了这个实现

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)
}
}

然后我会像这样使用它

RetrofitService.profileApi

这样可以吗?


1
RetrofitService 可以是一个完整的对象。那么就没有必要有私有构造函数和初始化块了。 - Yevhen Danchenko
2个回答

15

你可以使用类似下面的内容:

object MyApi {

    private const val BASE_URL = " https://www.MYAPI.com/"

    private val moshi = Moshi.Builder()
        .add(KotlinJsonAdapterFactory())
        .build()

    private val retrofit = 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 是一个单例,它只会被实例化一次并在下一次调用时重复使用。
  • by lazy 使用此关键字,你的retrofitService仅在第一次调用时进行初始化,然后您将重复使用相同的值,更多细节请参见此处

谢谢@Biscuit。我已经采纳了你的建议并更新了我的问题。现在看起来更好了吗? - user6920323
是的,你的更新完全没问题,这也是我可以这样做的方式,我已经在我的答案中添加了它。 - Biscuit
每个服务都会有一个新的Retrofit实例吗?我们在每次初始化服务时都会调用retrofit()。 - Rinat Diushenov
确实,每个服务都将创建一个新的实例,因此对于我的示例,只会创建2个retrofit对象,您可以将函数“retrofit()”更改为“val retrofit:Retrofit by lazy”以解决此问题。 - Biscuit
在使用此对象之前,我应该如何传递我的API用户名和密码? - Kamil

4
//try to adapt this code sample to your code

object RetrofitConfig {
// use lazy to insure that only one instance of retrofit will be used - no duplication
private val retrofit : Retrofit by lazy {
    Retrofit.Builder()
        .addConverterFactory(GsonConverterFactory.create())
        .baseUrl("put_your_url_here")
        .build()
}

// here put your services interface if you have more
val movieService : MovieService by lazy {
    retrofit.create(MovieService::class.java)
}

val showService : ShowService by lazy {
    retrofit.create(ShowService::class.java)
}
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接