oligazar
11/20/2017 - 2:48 AM

ServiceGenerator with SingletonHolder

class RetrofitManager private constructor(cacheDir: File): OkHttpClient() {

    private val baseUrl = "https://ict.com.mm/wp-json/"

    val retrofitClient: Retrofit

    init {
        val gson = GsonBuilder()
            .registerTypeAdapter(Product::class.java, ProductModelDeserializer())
            .registerTypeAdapter(Page::class.java, PageModelDeserializer())
            .registerTypeAdapter(ProductDetails::class.java, ProductDetailsModelDeserializer())
            .registerTypeAdapter(Category::class.java, CategoryModelDeserializer())
            .registerTypeAdapter(Post::class.java, PostItemModelDeserializer())
            .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
            .create()

        retrofitClient = Retrofit.Builder()
                .baseUrl(baseUrl)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create(gson))
                // using OkHttpManager
                .client(OkHttpManager.getInstance(cacheDir).client)
                .build()
    }

    companion object: SingletonHolder<File, RetrofitManager>(::RetrofitManager) {

        val userName = "ck_9b4335ab3952866c1111a59b4821fd71a55f3aa8"
        val password = "cs_6620a1b35779c8836810ee5f9ec6bbb9c02bbe5e"
        val homeCategoryId = 5699

        fun <S> createService(context: Context, serviceClass: Class<S>): S =
                getInstance(context.cacheDir).retrofitClient.create(serviceClass)
    }
}

class OkHttpManager private constructor(cacheDir: File) {

    val client: OkHttpClient

    init {
        val cacheSize = 10 * 1024 * 1024 // 10 MiB
        val cache = Cache(cacheDir, cacheSize.toLong())
        client = StethoUtils.getOkHttpClient(cache)
    }

    companion object: SingletonHolder<File, OkHttpManager>(::OkHttpManager)
}

open class SingletonHolder<in A, out T>(creator: (A) -> T) {
    // https://medium.com/@BladeCoder/kotlin-singletons-with-argument-194ef06edd9e

    private var creator: ((A) -> T)? = creator
    @Volatile private var instance: T? = null

    fun getInstance(arg: A): T {
        val i = instance
        if (i != null) {
            return i
        }

        return synchronized(this) {
            val i2 = instance
            if (i2 != null) {
                i2
            } else {
                val created = creator!!(arg)
                instance = created
                creator = null
                created
            }
        }
    }
}
class ServiceGenerator {

    fun <S> createService(serviceClass: Class<S>, cacheDir: File): S = createRetrofit(cacheDir).create(serviceClass)

    companion object : SingletonHolder<File, OkHttpClient>(::createOkHttp) {

        private val BASE_URL = "https://ict.com.mm/wp-json/"

        val gson = GsonBuilder()
//            .registerTypeAdapter(Product::class.java, ProductModelDeserializer())
                .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
                .create()

        fun createOkHttp(cacheDir: File): OkHttpClient {
            val cacheSize = 10 * 1024 * 1024 // 10 MiB
            val cache = Cache(cacheDir, cacheSize.toLong())
            return StethoUtils.getOkHttpClient(cache)
        }

        fun createRetrofit(cacheDir: File): Retrofit {
            return Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .addConverterFactory(GsonConverterFactory.create(gson))
                    .client(getInstance(cacheDir))
                    .build()
        }
    }
}