Общий метод ответа веб-сервиса Android - PullRequest
0 голосов
/ 07 ноября 2018

Я получаю ответ от веб-сервисов. Где все ответы одинаковы, за исключением массива, как грузовики и кошки. Ниже приведены два примера для понимания. Я использую liveData и дооснащение ..

В интерфейсе AppWebServices я создал GsonBuilder и установил registerTypeAdapter(WebServiceResponse::class.java, Deserializer<WebServiceResponse<Company>>(Company::class.java))

Я хочу сделать эту компанию внутри WebServiceResponse <> динамической. Я попробовал T type для AppWebServices, но он не работает.

{
    "status": true,
    "statusMessage" : "Success",
    "data": {
        "trucks": [{
                "id": 1,
                "engine": "big",
                "wheels" : 12
                }, 
                { 
                "id": 2,
                "engine": "super big",
                "wheels" : 128
                }]
            }
  }

2-й образец

{
        "status": true,
        "statusMessage" : "Success",
        "data": {
            "cats": [{
                    "id": 1,
                    "title": "Cat 1"
                    }, 
                    { 
                    "id": 2,
                    "title": "Cat 2"
                    }]
                }
      }

После поиска на SO я нашел решение . Работает нормально.

CompaniesActivity.class

class CompaniesActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_companies)
        initializeUi()
    }

    private fun initializeUi() {
        val factory = InjectorUtils.provideCompanyViewModelFactory()
        val viewModel = ViewModelProviders.of(this, factory)
            .get(CompanyViewModel::class.java)
        viewModel.getCompanies().observe(this, Observer { companies ->
            setupRecyclerView(companies)
        })
    }

    private fun setupRecyclerView(companies: List<Company>) {
        recyclerView.layoutManager = LinearLayoutManager(this)
        recyclerView.adapter = CompanyAdapter(companies)
    }
}

InjectorUtils.class

object InjectorUtils {

    fun provideCompanyViewModelFactory() : CompanyViewModelFactory {
        val companyDao = Database.getInstance().companyDao
        val companyRepository = CompanyRepository.getInstance(companyDao)
        return CompanyViewModelFactory(companyRepository)
    }
}

CompanyViewModel.class

class CompanyViewModel(private val companyRepository: CompanyRepository) : ViewModel() {

    fun addCompany(company: Company) = companyRepository.addCompany(company)

    fun addcompanies(companies: List<Company>) = companyRepository.addCompanies(companies)

    fun getCompanies() = companyRepository.getCompanies()
}

CompanyRepository.class

class CompanyRepository private constructor(private val companyDao: CompanyDao) {

    companion object {
        @Volatile private var instance: CompanyRepository? = null
        fun getInstance(companyDao: CompanyDao) =
            instance ?: synchronized(this) {
                instance
                    ?: CompanyRepository(companyDao).also { instance = it }
            }
    }

    fun addCompany(company: Company) {
        companyDao.addCompany(company)
    }

    fun addCompanies(companies: List<Company>) {
        companyDao.addCompanies(companies)
    }

    private fun updatedCompanies(): LiveData<List<Company>> {
        return companyDao.getCompanies()
    }

    fun getCompanies(): LiveData<List<Company>> {
        val companies = companyDao.getCompanies().value
        if (companies == null || companies.isEmpty()) {
            val appWebServices = AppWebServices()
            GlobalScope.launch(Dispatchers.Main) {
                val response = appWebServices.getNearestCompanies(33.6658432, 73.0726399, 0, 100).await()
                if (response.status && response.result.isNotEmpty()) {
                    addCompanies(response.result)
                }
            }
        }
        return updatedCompanies()
    }

}

Deserializer.java

class Deserializer<T>(private val clazz: Type): JsonDeserializer<WebServiceResponse<T>> {

    @Throws(JsonParseException::class)
    override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): WebServiceResponse<T>? {
        val jsonObject = json as JsonObject
        var status = true ///jsonObject.get("status")
        var statusMessage = "hello"//jsonObject.get("statusMessage")

        val data = jsonObject.get("data") as JsonObject
        val companies = data.get("companies") as JsonArray

        val list = mutableListOf<T>();
        for (element in companies) {
            val ele = element as JsonElement
            list.add(context!!.deserialize(ele, clazz))
        }

        return WebServiceResponse<T>(list,status,statusMessage);
    }
}

AppWebServices.class Интерфейс для модернизации

interface AppWebServices {

    @GET(Keys.GET_NEARST_COMPANY_LIST)
    fun getNearestCompanies(
        @Query(Keys.CURRENT_LAT) latitude: Double,
        @Query(Keys.CURRENT_LON) longitude: Double,
        @Query(Keys.START_LIST_INDEX) startIndex: Int,
        @Query(Keys.END_LIST_INDEX) endIndex: Int
    ) : Deferred<WebServiceResponse<Company>>

    companion object {
        operator fun invoke(): AppWebServices {
            val okHttpClient = OkHttpClient.Builder().build()

            var gson = GsonBuilder().setLenient()
                .registerTypeAdapter(WebServiceResponse::class.java, Deserializer<WebServiceResponse<Company>>(Company::class.java))
                .create()
            return Retrofit.Builder()
                .client(okHttpClient)
                .baseUrl(BuildConfig.BASE_URL)
                .addCallAdapterFactory(CoroutineCallAdapterFactory())
                .addConverterFactory(GsonConverterFactory.create(gson))
                .build()
                .create(AppWebServices::class.java)
        }
    }
}

WebServiceResponse.class

data class WebServiceResponse<T> (
    @SerializedName(Keys.DATA)
    val result: List<T>,
    val status: Boolean,
    val statusMessage: String
)

CompanyDao.class

class CompanyDao {
    private val companyList = mutableListOf<Company>()
    private val companies = MutableLiveData<List<Company>>()

    init {
        companies.value = companyList
    }

    fun addCompany(company: Company) {
        companyList.add(company)
        companies.value = companyList
    }

    fun addCompanies(companies: List<Company>) {
        companyList.addAll(companies)
        this.companies.value = companyList
    }

    fun getCompanies() = companies as LiveData<List<Company>>
}

Я хочу, чтобы решение сообщало моей службе, какой ответ я хочу
val appWebServices = AppWebServices<Company>(), чтобы он мог установить его на

.registerTypeAdapter(WebServiceResponse::class.java, Deserializer<WebServiceResponse<T>>(T::class.java))

1 Ответ

0 голосов
/ 07 ноября 2018

Вы можете использовать inline reified для доступа к параметру универсального типа в теле функции.

Ваша текущая функция invoke содержит много кода, а встраивание скопирует все строки в место вызова. Было бы лучше разделить функцию на часть reified, чтобы захватить объект class и внутреннюю часть, которая создает прокси. Для доступа к методу internal из метода inline необходимо использовать аннотацию @PublishedApi.

companion object {
    inline operator fun <reified T> invoke() =
        createProxy(T::class.java)


    @PublishedApi
    internal fun <T> createProxy(clazz: Class<T>): AppWebServices {
        ...
    }
}

Теперь вы можете создать свой Сервис так, как вы хотели:

val appWebServices = AppWebServices<Company>()
...