Retrofit

qué es Retrofit

Código en GitHub

Crear un nuevo proyecto llamado DogsKotlin

AndroidManifest.xml

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

build.gradle

buildFeatures {
    viewBinding = true
}

Dependencias:

//Picasso
implementation("com.squareup.picasso:picasso:2.71828")
//RecyclerView
implementation("androidx.recyclerview:recyclerview:1.3.2")
//Retrofit
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
//Corrutinas
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1")

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    android:id="@+id/viewRoot"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.appcompat.widget.SearchView
        android:id="@+id/svDogs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:elevation="7dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintVertical_bias="0.0"
        app:queryHint="labrador, husky, no_existe"/>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rvDogs"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/svDogs"/>

</androidx.constraintlayout.widget.ConstraintLayout>

DogsResponse.kt

data class DogsResponse (
    @SerializedName("status") var status:String,
    @SerializedName("message") var images: List<String>)

APIService.kt

interface APIService {
    @GET
    suspend fun getDogsByBreeds(@Url url: String): Response<DogsResponse>
}

item_dog.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="320dp"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_margin="16dp"
    android:elevation="7dp"
    app:cardCornerRadius="8dp">

    <ImageView
        android:id="@+id/ivDog"
        android:scaleType="centerCrop"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</androidx.cardview.widget.CardView>

DogViewHolder.kt

class DogViewHolder(view: View) : RecyclerView.ViewHolder(view) {

    private val binding = ItemDogBinding.bind(view)

    fun bind(image: String) {
        Picasso.get().load(image).into(binding.ivDog)
    }
}

DogAdapter.kt

class DogAdapter (private val images: List<String>) : RecyclerView.Adapter<DogViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DogViewHolder {
        val layoutInflater = LayoutInflater.from(parent.context)
        return DogViewHolder(layoutInflater.inflate(R.layout.item_dog, parent, false))
    }

    override fun getItemCount(): Int {
        return images.size
    }

    override fun onBindViewHolder(holder: DogViewHolder, position: Int) {
        val item:String = images[position]
        holder.bind(item)
    }
}

MainActivity.kt

//androidx.appcompat.widget.SearchView
class MainActivity : AppCompatActivity(), SearchView.OnQueryTextListener {

    private lateinit var binding: ActivityMainBinding
    private lateinit var adapter: DogAdapter
    private val dogImages = mutableListOf<String>()

    companion object{
        const private val WEB= "https://dog.ceo/api/breed/"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.svDogs.setOnQueryTextListener(this)

        initRecyclerView()
    }

    private fun initRecyclerView() {

        adapter = DogAdapter(dogImages)
        // binding.rvDogs.setHasFixedSize(true)
        binding.rvDogs.layoutManager = LinearLayoutManager(this)
        binding.rvDogs.adapter = adapter
    }

    private fun getRetrofit(): Retrofit {
        return Retrofit.Builder()
            .baseUrl(WEB)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }

    private fun searchByName(query: String) {
        CoroutineScope(Dispatchers.IO).launch {
            val call: Response<DogsResponse> = getRetrofit().create(APIService::class.java).getDogsByBreeds("$query/images")

            val puppies:DogsResponse? = call.body()
            runOnUiThread {
                if (call.isSuccessful) {
                    val images:List<String> = puppies?.images ?: emptyList()
                    // show RecyclerView
                    dogImages.clear()
                    dogImages.addAll(images)
                    adapter.notifyDataSetChanged()
                } else {
                    showErrorDialog()
                }
                hideKeyboard()
            }
        }
    }

    override fun onQueryTextSubmit(query: String): Boolean {

        if (!query.isNullOrEmpty())
            searchByName(query.lowercase())

        return true
    }
    
    private fun showErrorDialog() {
        Toast.makeText(this, "Ha ocurrido un error", Toast.LENGTH_SHORT).show()
    }

    override fun onQueryTextChange(newText: String?): Boolean {
        return true
    }

    private fun hideKeyboard() {
        val imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
        imm.hideSoftInputFromWindow(binding.viewRoot.windowToken, 0)
    }
}

Comprobación:

  • Obtener fotos de una raza, por ejemplo labrador, husky, chihuahua
  • Obtener fotos de una raza que no existe

 

Mejoras:

– Usar el patrón Singleton con Retrofit

– Tratamiento de errores en Retrofit

– Mostrar todas las razas y, al pulsar en una, obtener las fotos de esa raza

https://dog.ceo/api/breeds/list/all

 

 

Deja una respuesta