Generalidades

Eliminación de mejores prácticas para la síntesis posterior de ViewDataBinding en Kotlin | Por MS SIDDIQUE | Marzo de 2022

Eliminacion de mejores practicas para la sintesis posterior de ViewDataBinding

Como la mayoría de nosotros ya sabemos, Kotlin Synthetics ha quedado obsoleto y lentamente todas las organizaciones están comenzando a usar ViewDataBinding, pero el principal problema con ViewDataBinding es una gran cantidad de código repetitivo como este.

class HomeFragment : DaggerFragment() {
private lateinit var viewModel: HomeFragmentViewModel
private var _binding: FragmentHomeBinding? = null
private val binding get() = _binding!!

Así que hoy en este artículo voy a discutir una de las mejores prácticas para deshacerse de este código repetitivo y hacerlo más limpio y eficiente.

Aspectos básicos de mi enfoque

  • Voy a crear dos clases base BaseBindingActivityBaseBindingActivity y BaseBindingFragmentestas clases servirán como clases base para actividades y fragmentos respectivamente
  • Inyección de dependencia para algunas cosas muy básicas como la inyección. Ver modelo de fábrica.
  • mostrar genéricos bar con o sin acción (Utilizar funciones de orden superior).
  • alternar visibilidad barra de progreso
  • crear ver modelo ejemplo

BaseBindingFragment.kt

open class BaseBindingFragment(
val bindingFactory: (LayoutInflater) -> VB
) : DaggerFragment() {

@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory

var listener: BaseEventListener? = null

val binding: VB by lazy { bindingFactory(layoutInflater) }

val viewModel: VM by lazy {
ViewModelProvider(
this,
viewModelFactory
)[getViewModelClass()]
}

override fun onAttach(context: Context) {
super.onAttach(context)
try {
listener = context as BaseEventListener
} catch (e: IllegalStateException) {
e.printStackTrace()
}
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return binding.root
}

private fun getViewModelClass(): Class {
val type = (
javaClass.genericSuperclass as ParameterizedType
).actualTypeArguments[1]
return type as Class
}

fun showProgressBar(
isVisible: Boolean,
message: String? = null
) = listener?.showProgressBar(isVisible, message)

fun showSnackBar(
message: String,
actionName: String? = null,
action: (() -> Unit)? = null
) = listener?.showSnackBar(message, actionName, action)
}

BaseBindingActivity.kt

abstract class BaseBindingActivity(
val bindingFactory: (LayoutInflater) -> VB
) : DaggerAppCompatActivity(), BaseEventListener {

@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory

val binding: VB by lazy { bindingFactory(layoutInflater) }

private lateinit var baseBinding: ActivityBaseBinding

val viewModel: VM by lazy {
ViewModelProvider(
this,
viewModelFactory
)[getViewModelClass()]
}

override fun setContentView(layoutResID: Int) {
baseBinding = DataBindingUtil.inflate(
layoutInflater, R.layout.activity_base, null, false
).apply {
layoutInflater.inflate(
layoutResID,
activityContainer,
true
)

baseLayoutContainer.requestLayout()
super.setContentView(root)
}
}

private fun getViewModelClass(): Class {
val type = (
javaClass.genericSuperclass as ParameterizedType
).actualTypeArguments[1]
return type as Class
}

override fun showProgressBar(
isVisible: Boolean,
message: String?
) {
baseBinding.progressBar.apply {
groupProgressBar.visibility = if (isVisible)View.VISIBLE else View.GONE
if
(!message.isNullOrEmpty()){ loadingText.text = message }
}
}

override fun showSnackBar(
message: String,
actionName: String?,
action: (() -> Unit)?
) = Snackbar.make(
baseBinding.baseLayoutContainer,
message,
Snackbar.LENGTH_LONG
).apply {
if (actionName != null) {
setAction(
actionName
) { if (action != null) action() }
}
}.show()
}

BaseEventListener.kt

interface BaseEventListener {
fun showProgressBar(isVisible: Boolean, message: String? = null)
fun showSnackBar(message: String, actionName: String? = null, action: (() -> Unit)? = null)
}

avtivity_base.xml (ActivityBaseBinding)

xml version="1.0" encoding="utf-8"?>
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">

android:id="@+id/base_layout_container"
android:layout_width="match_parent"
android:layout_height="match_parent">

android:id="@+id/activity_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />

android:id="@+id/progress_bar"
layout="@layout/progress_bar_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />


InicioFragmento.kt

Esto extiende BaseBindingFragment.kt

class HomeFragment : BaseBindingFragment<FragmentHomeBinding,HomeFragmentViewModel>(
FragmentHomeBinding::inflate
) {
}

MainActivity.kt

class MainActivity : BaseBindingActivity<ActivityMainBinding, HomeFragmentViewModel>(
ActivityMainBinding::inflate
) {
  • crear Contenedor activo(FrameLayout) en activity_base.xml actúa como un contenedor para sus vistas de actividad, sin importar quién extienda BaseBindingActivity
  • ProgressBar y SnackBar se manejan completamente en el nivel de actividad, es por eso que uso la interfaz BaseEvenHandler para pasar eventos a BaseBindingActivity y BaseBindingFragment
  • En BaseBindingActivity básicamente anulamos Establecer vista de contenido En lugar de agrupar la vista como un todo, la función coloca la vista dentro del contenedor (Contenedor activo)

Ahora solo necesita proporcionar viewBinding y viewModel una vez al crear cualquier actividad o fragmento y está listo para comenzar. ver enlace de datos y ver modelo directamente sin preocuparse de cómo se crean realmente, y puede mostrar libremente el snackBar en cualquiera de sus actividades de fragmentos como este

showSnackBar(result.msg)  // without action
or
showSnackBar(
getString(R.string.gps_warning),
"Retry"
) { turnOnGPS() } // with action

Simplemente puede alternar la visibilidad de ProgressBar de esta manera

showProgressBar(false)  // without message
or
showProgressBar(true, result.msg) // with message

Para obtener más detalles o código, puede navegar por este repositorio

https://github.com/MSSIDDIQUE/WeatherForecast

LEER  Extraer el perfil de color de una imagen en Android | por yggr | Septiembre de 2021

Publicaciones relacionadas

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Botón volver arriba