Kotlin e Retrofit 2: Tutorial com códigos de trabalho

Tempo de leitura: 4 minutes

Vou mostrar como usar Kotlin e Retrofit para ler dados de um servidor. Aqui, também forneço o exemplo de código real. Além de aprender as informações gerais sobre chamadas de rede, espero que você obtenha algumas dicas sobre os recursos do Kotlin que podem ser úteis.

O aplicativo de exemplo

O tutorial aqui irá guiá-lo para criar um aplicativo que permite que você insira uma palavra-chave, e mostrará quantas pesquisas ele tem no wiki, como mostra a imagem abaixo. Você pode obter o código na parte inferior da página. A explicação de como chegar lá nas seções a seguir.

O Endpoint API Server

Em vez de criar nosso próprio servidor, vamos usar uma API popular existente e prontamente disponível, para que pudéssemos nos concentrar em apenas criar o lado Android do código. Aqui, usamos a API fornecida pelo wiki que, dada uma string de pesquisa, retornará a contagem de pesquisa da ocorrência para a string de pesquisa fornecida.

ou seja, faremos uma pesquisa em https://en.wikipedia.org/w/api.php?action=query&format=json&list=search&srsearch=Nasa, ele retornará o resultado JSON abaixo, com totalhits como a contagem que desejamos.

{
  "batchcomplete": "",
  "continue": {
    "sroffset": 10,
    "continue": "-||"
  },
  "query": {
    "searchinfo": {
      "totalhits": 38759,
      "suggestion": "gas",
      "suggestionsnippet": "gas"
    },
    "search": [
      {
        "ns": 0,

Observe também que, no URL fornecido, existem 4 parâmetros, ou seja, action, format, list e srsearch. Para os três primeiros, vamos apenas corrigir as entradas para consulta, json e pesquisa, enquanto o último é a string de pesquisa que o usuário fornecerá.

 

O Modelo de Dados

Como vimos os dados JSON lá em cima, na verdade estamos apenas interessados nos totalhits. Uma vez que está contido no escopo searchinfo e query JSON, para simplificar a transformação do nosso modelo de dados, vamos modelá-lo de acordo com o JSON, definindo-o como classe de dados Kotlin conforme abaixo

object Model {
    data class Result(val query: Query)
    data class Query(val searchinfo: SearchInfo)
    data class SearchInfo(val totalhits: Int)
}

Adicionar bibliotecas dependentes e permissão

Agora, para usar o Retrofit, você precisará adicionar a biblioteca ao seu gradle. Além disso, você também precisará da biblioteca Rxjava e da biblioteca do conversor gson, pois essa é a melhor maneira de buscar dados do servidor conhecido hoje e transformá-los automaticamente de JSON em seu modelo de dados.

Adicione o seguinte ao seu build.gradle

implementation "com.squareup.retrofit2:retrofit:2.9.0"
implementation "com.squareup.retrofit2:adapter-rxjava2:2.9.0"
implementation "com.squareup.retrofit2:converter-gson:2.9.0"
implementation "io.reactivex.rxjava2:rxandroid:2.1.1"

Além disso, não se esqueça de adicionar a permissão de Internet necessária em seu AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET" />

 

Os serviços do Retrofit 2

Com as bibliotecas incluídas, agora vamos à definição de serviços de interface do Retrofit 2. Definimos uma interface de serviço chamada WikiApiService. Como nos concentramos apenas em uma única chamada de API, com 4 parâmetros de consultas, eu os defino como a seguir, correspondendo ao serviço de API de endpoint mencionado acima.

interface WikiApiService {

    @GET("api.php")
    fun hitCountCheck(@Query("action") action: String,
                      @Query("format") format: String,
                      @Query("list") list: String,
                      @Query("srsearch") srsearch: String): 
                  Observable<Model.Result>

}

Observação: o resultado é retornado como Model.Result e como Observable, que é um objeto Rxjava que pode ser analógico como o gerador de resultado do buscador de endpoint.

Uma vez que sua interface é definida, você pode adicionar um método estático (em seu escopo de interface WikiApiService) que gera seu serviço de retrofit. O objeto companheiro Kotlin é usado para tornar a função de criação abaixo semelhante ao static method do padrão Java Factory.

companion object {
        fun create(): WikiApiService {

            val retrofit = Retrofit.Builder()
                  .addCallAdapterFactory(
                      RxJava2CallAdapterFactory.create())
                  .addConverterFactory(
                      GsonConverterFactory.create())
                  .baseUrl("https://en.wikipedia.org/w/")
                  .build()

            return retrofit.create(WikiApiService::class.java)
        }
}

Aqui, usamos a fábrica de adaptadores padrão que converte entre o tipo de retrofit Rx Observables para Call e também o objeto GsonConverter padrão.

O Endpoint base também é definido aqui https://en.wikipedia.org/w/.

 

Faça a busca

Depois de definir tudo isso, é hora da parte divertida: pegue os dados!

Os Objetos Globais

Mas antes disso, vamos definir duas variáveis globais

val wikiApiServe by lazy {
    WikiApiService.create()
}

var disposable: Disposable? = null
  1. O objeto WikiApiService singleton que é criado vagarosamente na primeira vez que é usado. Depois disso, será reutilizado sem criação. O recurso lazy Kotlin é muito útil sem a necessidade de você escrever uma função explicitamente para fazer a inicialização preguiçosa. Observe que o objeto é criado a partir da função create estática WikiApiService.
  2. O objeto disposable é basicamente um objeto de retorno do RxJava 2.0 que rastreia a atividade de busca. No caso de sua atividade ter sido destruída, poderíamos descartar este objeto, para que seu evento de busca parasse, caso não fosse concluído. Isso evitaria travamentos indesejados, no caso de sua atividade ser destruída antes do retorno do resultado de busca.

 

O código de busca real

Finalmente, depois de muita preparação, agora você pode buscar seus dados na wikipedia, fornecendo o keyworld srsearch. Eu escrevi uma função abaixo

private fun beginSearch(srsearch: String) {
  disposable = 
     wikiApiServe.hitCountCheck("query", "json", "search", srsearch)
      .subscribeOn(Schedulers.io())
      .observeOn(AndroidSchedulers.mainThread())
      .subscribe(
       { result -> showResult(result.query.searchinfo.totalhits) },
       { error -> showError(error.message) }
      )
}
  1. wikiApiServe é o serviço singleton, onde hitCountCheck retornará um Observable
  2. O Observable, uma vez que é como um gerador de resultado do buscador de endpoint, dizemos a ele para buscar os dados em segundo plano por subscribeOn(Schedulers.io())
  3. No entanto, gostamos que os dados buscados sejam exibidos na MainTread (UI), então definimos observeOn(AndroidSchedulers.mainThread())
  4. Em termos do que fazemos com o resultado, usamos subscribe para definir nossa ação no resultado, onde by result é o resultado dos dados buscados, onde poderíamos acessar os dados do totalhits de acordo. No caso de ocorrer um erro, ele retornará o erro em vez de ser tratado.

Este é até agora o melhor modelo que permite que uma rede seja feita em background e poste o resultado em mainThread.

 

Fechamento adequado

Por último e não menos importante, precisamos lembrar, uma vez que a busca está acontecendo em segundo plano de forma assíncrona, existe a possibilidade de sua atividade ser encerrada antes que a busca em segundo plano seja concluída. Portanto, é muito importante interromper a missão de busca sempre que sua atividade for encerrada.

Felizmente, usando Rxjava, o disposable que instanciamos se vincula ao tratamento de busca Rx. Poderíamos fazer com que ele encerrasse o processo chamando dispose conforme abaixo

override fun onPause() {
    super.onPause()
    disposable?.dispose()
}

Eu faço isso no onPause, mas pode-se lidar com isso no onDestroy ou onde quer que faça sentido para o seu código.

Espera que você aprenda algo, seja um pouco de Retrofit 2.0, Rxjava 2.0 ou algo sobre Kotlin.

Sim, você pode obter o código de

Visits: 2 Visits: 1199498