You don't have access to this class

Keep learning! Join and start boosting your career

Aprovecha el precio especial y haz tu profesión a prueba de IA

Antes: $249

Currency
$209
Suscríbete

Termina en:

0 Días
10 Hrs
12 Min
37 Seg

Creación del loader y resultados de la implementación

8/32
Resources

How to create a Loader in the Home Fragment using XML?

Creating a Loader in an Android application is an essential task to improve the user experience by displaying a visual indication of loading. In this guide, we will see step by step how to set up a Loader in the Home Fragment of an Android application using XML.

What is a Loader and how is it configured?

A Loader is a UI component that indicates to the user that data is loading. To create one, follow these steps:

  1. Go to the XML file of the Fragment: Go to the XML file of the fragment in which you want to add the Loader. This file is usually found in the res/layout folder of your project.

  2. Create a new Widget: In your XML fragment, add a ProgressBar. This will be the Loader that will be displayed in the application.

    <ProgressBar android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/home_loader" android:visibility="invisible" />
    • Adjust the properties: Set the width and height to wrap_content to fit the content.
    • Set the initial visibility to invisible: This ensures that the Loader is not shown when the view loads, but is controlled by the presenter.
  3. Positioning: Make sure the Loader is centered in the view using constraints:

    app:layout_constraintStart_toStartOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"

How to show and hide the Loader from the Home Fragment?

Once configured in the XML, the next step is to control the visibility of the Loader from the fragment.

  1. Access the Loader from the Fragment: In the Java or Kotlin file of your fragment, get the reference to the Loader using its ID.

    val homeLoader: ProgressBar = view.findViewById(R.id.home_loader)
  2. Methods to show and hide the Loader:

    • Show Loader:

      { fun showLoader() { homeLoader.visibility = View.VISIBLE}
    • Hide Loader:

      { homeLoader.visibility = View.GONE}fun hideLoader() { homeLoader.visibility = View.GONE}
  3. Delay implementation with Handler: To simulate a loading time and improve the UX, you can use a Handler to delay the appearance or disappearance of the Loader. For example, to simulate a delay of 3 seconds:

    val handler = Handler(Looper.getMainLooper())handler.postDelayed({ hideLoader() }, 3000)

What architecture is being applied and how does it impact?

In this context, the MVP (Model-View-Presenter) architecture is used. This architecture separates the application into three layers:

  • View: handles the user interface.
  • Presenter: Contains the business logic and dictates when to show the Loader.
  • Model: Manages the application data, usually interacting with databases or APIs.

Using MVP helps keep code clean and scalable. If you need to change the way data is handled, you can make modifications in the specific layer without affecting the others. This is a great example of the clarity and efficiency that a well-defined architecture brings to software development.

Future Perspectives and Alternative Architectures

In future classes, we will explore the MVVM (Model-View-View Model) architecture that offers other advantages for handling user interface and business logic. Stay enthusiastic, keep exploring and refining your knowledge in software architecture. This is where every detail counts and your understanding deepens as you apply these concepts to real projects. Go ahead and keep learning!

Contributions 17

Questions 1

Sort by:

Want to see more contributions, questions and answers from the community?

no sé por que al profesor no le dió error pero a mi me daba error por que no estaba instanciado favoriteTransferItems asi que decidí usar null-safety

package com.cristianvillamil.platziwallet.ui.home.view

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.cristianvillamil.platziwallet.R
import com.cristianvillamil.platziwallet.ui.home.FavoriteTransfer

class FavoriteTransferAdapter : RecyclerView.Adapter<FavoriteTransferViewHolder>() {

	private var favoriteTransferItems: List<FavoriteTransfer>? = null
	override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FavoriteTransferViewHolder =
		FavoriteTransferViewHolder(
			LayoutInflater.from(parent.context).inflate(
				R.layout.favorite_transfer_row,
				parent,
				false
			)
		)


	override fun getItemCount(): Int {
		return favoriteTransferItems?.size ?: 0
	}

	override fun onBindViewHolder(holder: FavoriteTransferViewHolder, position: Int) =
		holder.bind(favoriteTransferItems?.get(position)!!)

	fun setData(favoriteTransferItems: List<FavoriteTransfer>) {
		this.favoriteTransferItems = favoriteTransferItems
		notifyDataSetChanged()
	}


}

Para solucionar el error al momento de probar el proyecto

En el **FavoriteTransferAdapter.kt **

Modifiquen la Linea

private lateinit var favoriteTransferItems: List<FavoriteTransfer>

por:

private var favoriteTransferItems: List<FavoriteTransfer>  = arrayListOf()

Estará funcionando el proyecto

HAY VARIAS COSAS QUE NO FUNCIONAN CORRECTAMENTE.
Se supone que al llamar a la lista que tenemos en caché (dentro del HomeInteractor), tendrían que cambiar los nombres, las cantidades de dinero, aparecer fechas y fotos… Y no lo hace. Además debería aparecer una animación junto con la foto de perfil del usuario, que ni sale la foto ni sale la animación en cuanto lanzas la app… Hay muchos errores que no concuerdan con el código que tenemos en archivos y enlaces.
Lo que yo eniendo es que NO se han molestado ni en comprobar si el XML que muestra la fila de transferencias está correcto (que sí lo está) lo que me lleva a entender QUE NO HAN TENIDO GANAS DE HACER EL PASO INTERMEDIO PARA QUE LA VISTA GENERE CADA NUEVO ITEM DEL CACHÉ… Si este curso lo está viendo alguien que no sabe nada de Android, cierra el vídeo y Platzi y se va a otros cursos en otros lugares… Ocurre mucho en todos los cursos. Se saltan pasos SUPERIMPORTANTES para aquellos que están comenzando (y que son los que quieren aprender) y se explican cosas innecesarias que luego no importan.

Esta puede ser otra forma de crear un delay

Podemos usar los mismos constraints definidos en el recyclerview en nuestro Progress bar para que aparezca en la zona del recycleview, solo para darle un detallito mas en el diseño:

Notar que el proyecto como tal carece de algunos detalles para que pueda ejecutarse correctamente.
Algunos de ellos son:
.
FavoriteTransferAdapter
.
En este se requiere inicializar la lista de favoriteTransferItems en null. Lo hice de la siguiente manera:

class FavoriteTransferAdapter : RecyclerView.Adapter<FavoriteTransferViewHolder>() {

    private var favoriteTransferItems: List<FavoriteTransfer>? = null
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FavoriteTransferViewHolder =
            FavoriteTransferViewHolder(
                    LayoutInflater.from(parent.context).inflate(
                            R.layout.favorite_transfer_row,
                            parent,
                            false
                    )
            )


    override fun getItemCount(): Int{
        return favoriteTransferItems?.size ?: 0
    }

    override fun onBindViewHolder(holder: FavoriteTransferViewHolder, position: Int) {
        // holder.bind(favoriteTransferItems?.get(position)!!)
        favoriteTransferItems?.get(position)?.let { holder.bind(it) }
    }

    fun setData(favoriteTransferItems: List<FavoriteTransfer>) {
        this.favoriteTransferItems = favoriteTransferItems
        notifyDataSetChanged()
    }


}

.
.
FavoriteTransferViewHolder
.
En esta clase, no enlazaron las vistas con los datos que traemos de HomeInteractor … razón por la cual se muestran cards con la misma información; información que fué previamente asignada en el xml fragment_home.
Adicional a esto, agregué una función para dar formato a los valores double de amount de forma que se agrega una coma “,” para separar los miles. Acá el código
.

class FavoriteTransferViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {

    @SuppressLint("SetTextI18n")
    fun bind(item: FavoriteTransfer) {
        val photoImageView = view.findViewById<ImageView>(R.id.profilePhotoImageView)
        val name = view.findViewById<TextView>(R.id.nameTextView)
        val transferAmount = view.findViewById<TextView>(R.id.transferredAmountTextView)
        val transferTime = view.findViewById<TextView>(R.id.transferTimeTextView)

        Picasso.get().load(item.photoUrl).into(photoImageView)
        name.text = item.name
        transferAmount.text = "$${formatingAmountOnDisplay(item)}"
        transferTime.text = item.date
    }

    private fun formatingAmountOnDisplay(item: FavoriteTransfer): String {
        val amount = item.amount.toString()
        var firstSegment: String = ""
        var secondSegment: String = ""
        var formatedText : String = ""

        if ((amount.length - 2) > 3 && (amount.length - 2) >= 6 ) {

            for (i in 0..2) {
                firstSegment += amount[i].toString()
            }

            for (j in 3 until amount.length) {
                secondSegment += amount[j].toString()
            }

            formatedText = "${firstSegment},${secondSegment}"

        }else if ((amount.length - 2) > 3 && (amount.length - 2) >= 5) {
            for (i in 0..1) {
                firstSegment += amount[i].toString()
            }

            for (j in 2 until amount.length) {
                secondSegment += amount[j].toString()
            }

            formatedText = "${firstSegment},${secondSegment}"

        }else if ((amount.length - 2) > 3 && (amount.length - 2) >= 4) {
            for (i in 0..0) {
                firstSegment += amount[i].toString()
            }

            for (j in 1 until amount.length) {
                secondSegment += amount[j].toString()
            }

            formatedText = "${firstSegment},${secondSegment}"
        }else {
            formatedText = item.amount.toString()
        }

        return formatedText
    }
}

Si se atrasaron en el código pueden descargar el archivo desde la sección ‘Archivos y Enlaces’, al final de todos esos documentos bajando para abajo le dan a ‘descargar todo’ y se les bajara un archivo zip, lo extraen y lo abren de forma tradicional en Android Studio…
(Abren Android Studios y abajo de la opción ‘Start a new proyect’ abajo hacen click a la opción ‘Open an exist proyect’ y escogen el archivo descomprimido del zip)

Para los nuevos en este curso, al menos 2023

Para el error de

kotlin.UninitializedPropertyAccessException: lateinit property favoriteTransferItems has not been initialized

Deben de modificar el archivo: FavoriteTransferAdapter.kt

// Linea 11 del archivo 
// Solo quitar lateinit e inicializar con emptyList() como este ejemplo

private var favoriteTransferItems: List<FavoriteTransfer> = emptyList()

Ahora bien!!!

Ciertamente hay algunas partes del sistema que no funcionan muy bien, si has seguido la ruta de desarrollo android podrás solucionar cada error, como la foto de perfil que no carga o bien como me ha pasado, hay muchos cambios y algunas depreciaciones en el código pero EL CURSO ES DE ARQUITECTURA así que no debes de ponerle mucha importancia (a menos que quieras meterle mano al código).

Sin embargo la idea es que puedas entender que estamos haciendo.
Les deseo éxitos y que los comentarios negativos de este y los demás videos no los desanime, al final estamos aprendiendo y esto les servirá de experiencia en un ambiente laboral “REAL”.

FavoriteTransferAdapter.kt
private var favoriteTransferItems: List<FavoriteTransfer> = arrayListOf()

Excelente explicación, le estaba batallando para entenderle a esta arquitectura 😄, gracias Cristian

Hasta ahora muy bueno el curso y el profe de muy buena calidad.

Cristian tiene cara de que es hincha de millonarios

Para los que tienen el problema de inicialization siempre les va pasar por usar un late init y no inicializarlo y llamarlo, les recomiendo una buena practica es hacer esto

  override fun getItemCount(): Int =
        if (this::favoriteTransferItems.isInitialized) favoriteTransferItems.size
        else 0

En la clase “FavoriteTransferViewHolder” debemos agregar alguna lineas de codigo para que las se muestren los datos correctamente, de lo contrario saldra los mismos datos para todas las transferencias usar :

fun bind(item: FavoriteTransfer) {
       val photoImageView = view.findViewById<ImageView>(R.id.profilePhotoImageView)
       Picasso.get().load(item.photoUrl).into(photoImageView)
       val name = view.findViewById<TextView>(R.id.nameTextView)
       name.text=item.name
       val transferAmount = view.findViewById<TextView>(R.id.transferredAmountTextView)
       transferAmount.text=item.amount.toString()
       val transferTime = view.findViewById<TextView>(R.id.transferTimeTextView)
       transferTime.text=item.date
   }

Ademas de esto, la primera imagen no se muestra ya que no se puede tener acceso a URL de la imagen, en mi caso solo busque otra foto de Freddy Vega en internet y copie la url en la clase Home Interactor, y todo funciono correctamente :

        FavoriteTransfer(
                1,
                "Freddy Vega",
                800.000,
                "Hace 8h",
                "https://freddyvega.com/content/images/size/w2000/2020/08/freddy-vega-grande.jpg"
            )

Yo , los patrones de disenio lo estoy comprendiendo pero al ver tantos comando nuevos me pierdo ojala que me expliquen mejor la app en su forma basica y lueo sabre modificarla con MVP

Las clases e interfaces que acabamos de crear me salen de color rojo en las pestañas del IDE… No hay ningún error (sale el check verde arriba a la derecha). Alguna idea de por qué sale así??? Cuando corro la app, se carga en el emulador, pero al hacer el launch se me crashea y se cierra… Será también por lo mismo que las pestañas del IDE en rojo???
Alguien puede ayudarme con ello???

Cuando lanzo la app en mi móvil de prueba físico, al girarlo y ponerlo lateral no se ve la pantalla correctamente. Si se supone que hay constraints layouts para que se vea tanto vertical como horizontal en cualquier dispositvo, por qué no se ve bien y no hace scroll??? Alguna idea???