Android Arsenal – Enlace de datos

馃К Kit de enlace de datos de Android para la notificaci贸n de cambios de datos desde niveles de modelo a niveles de interfaz de usuario. Esta biblioteca proporciona clases base para DataBinding (BindingActivity, BindingFragment, BindingViewModel) y admite modos de notificaci贸n de cambio de datos LiveData y no observables.

Caso de uso

Puede consultar los buenos casos de uso de esta biblioteca en los repositorios a continuaci贸n.

  • Pokedex馃棥锔 Pokedex Android con Hilt, Motion, Coroutines, Flow, Jetpack (Room, ViewModel, LiveData) basado en la arquitectura MVVM.
  • DisneyMotions馃 Una aplicaci贸n de Disney que utiliza movimientos de transformaci贸n basados 鈥嬧媏n la arquitectura MVVM (ViewModel, Coroutines, LiveData, Room, Repository, Koin).
  • H茅roes de Marvel鉂わ笍 Una aplicaci贸n de muestra de los h茅roes de Marvel basada en la arquitectura MVVM (ViewModel, Coroutines, LiveData, Room, Repository, Koin).
  • TheMovies2馃幀 Un proyecto de demostraci贸n que utiliza The Movie DB basado en la arquitectura Kotlin MVVM y el dise帽o de materiales y animaciones.

Descargar

Gradle

Agrega los siguientes c贸digos al tuyo ra铆z build.gradle archivo (no el archivo build.gradle del m贸dulo).

allprojects {
    repositories {
        mavenCentral()
    }
}

Y agregue un c贸digo de dependencia a su archivo m贸dulo‘S build.gradle expediente.

dependencies {
    implementation "com.github.skydoves:bindables:1.0.2"
}

INSTANTE

Hay disponibles instant谩neas de la versi贸n de desarrollo actual de Bindables, que trazan las 煤ltimas versiones.

repositories {
   maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
}

Establecer enlace de datos

Si ya usa DataBinding en su proyecto, puede omitir este paso. Agregue a continuaci贸n el suyo build.gradle y aseg煤rate de usar DataBinding en su proyecto.

plugins {
    ...
    id 'kotlin-kapt'
}

android {
  ...
  buildFeatures {
      dataBinding true
  }
}

Inicializar

Deber铆amos unirnos BR clase que genera el proceso DataBinding en tiempo de compilaci贸n en BindingManager. Se recomienda la encuadernaci贸n Application clase.

BindingManager.bind(BR::class)

BindingActivity

BindingActivity es una clase base para actividades que quieren asociar el dise帽o del contenido DataBindingUtil. Provee un binding extensi贸n de propiedad ViewDataBinding da informaci贸n abstracta. los binding la propiedad se inicializar谩 de forma diferida, pero garantiza que se inicializar谩 antes de ser llamada super.onCreate en Actividades. Por lo tanto, no es necesario aumentar los dise帽os, configurar ContentView e inicializar manualmente una propiedad de enlace.

class MainActivity : BindingActivity<ActivityMainBinding>(R.layout.activity_main) {

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

   binding.vm = viewModel // we can access a `binding` propety.

  // Base classes provide `binding` scope that has a receiver of the binding property.
  // So we don't need to use `with (binding) ...` block anymore.
   binding {
      lifecycleOwner = this@MainActivity
      adapter = PokemonAdapter()
      vm = viewModel
    }
  }
}

BindingFragment

El concepto de BindingFragment no es muy diferente del BindingActivity. Asegura la binding propiedad para inicializar onCreateView.

class HomeFragment : BindingFragment<FragmentHomeBinding>(R.layout.fragment_home) {

  private val viewModel: MainViewModel by viewModels()

  override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
  ): View {
    super.onCreateView(inflater, container, savedInstanceState) // we should call `super.onCreateView`.
    return binding {
      adapter = PosterAdapter()
      vm = viewModel
    }.root
  }
}

BindingViewModel

BindingViewModel proporciona una forma en la que la interfaz de usuario puede estar informada de los cambios de las capas del modelo.

bindingProperty

bindingProperty notifica que un espec铆fico ha cambiado y se puede observar en las capas de la interfaz de usuario. El captador para los cambios de propiedad debe estar marcado con @get:Bindable.

class MainViewModel : BindingViewModel() {

  @get:Bindable
  var isLoading: Boolean by bindingProperty(false)
    private set // we can prevent access to the setter from outsides.

  @get:Bindable
  var toastMessage: String? by bindingProperty(null) // two-way binding.

  fun fetchFromNetwork() {
    isLoading = true

    // ... //
  }
}

En nuestro dise帽o XML, los cambios en el valor de la propiedad se notificar谩n autom谩ticamente al DataBinding cada vez que cambiemos el valor.

<ProgressBar
    android:id="@+id/progress"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:gone="@{!vm.loading}"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

notificarPropertyChanged

podemos personalizar los establecedores de propiedades generales para notificar cambios de datos en los niveles de interfaz de usuario mediante @get:Bindable anotaci贸n e notifyPropertyChanged() en BindingViewModel.

@get:Bindable
var message: String? = null
  set(value) {
    field = value
    // .. do something.. //
    notifyPropertyChanged(::message) // notify data changes to UI layers. (DataBinding)
  }

Encuadernaci贸n bidireccional

Podemos implementar propiedades de enlace bidireccional usando bindingProperty. A continuaci贸n se muestra un ejemplo representativo de la asociaci贸n bidireccional utilizando TextView es EditText.

class MainViewModel : BindingViewModel() {
  // This is a two-way binding property because we don't set the setter as privately.
  @get:Bindable
  var editText: String? by bindingProperty(null)
}

Aqu铆 hay un dise帽o XML. El texto cambiar谩 cada vez que el viewModel.editText ha cambiado.

<androidx.appcompat.widget.AppCompatTextView
  android:id="@+id/textView"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:text="@{viewModel.editText}" />

<EditText
  android:id="@+id/editText"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content" />

En su negocio o fragmento, podemos configurar el archivo viewModel.editText siempre que el EditTextLa entrada de ha cambiado. Podemos implementarlo de otra manera usando inversebindingadapter.

binding.editText.addTextChangedListener {
  vm.editText = it.toString()
}

Funciones vinculantes

Podemos mejorar las funciones enlazables usando @Bindable anotaci贸n e notifyPropertyChanged() en BindingViewModel. Y el @Bindable el nombre del m茅todo anotado debe comenzar con get.

class MainViewModel : BindingViewModel() {
  @Bindable
  fun getFetchedString(): String {
    return usecase.getFetchedData()
  }

  fun fetchDataAndNotifyChaged() {
    usecase.fetchDataFromNetowrk()
    notifyPropertyChanged(::getFetchedString)
  }
}

Cada vez que llamamos notifyPropertyChanged(::getFetchedData), getFetchedString() se llamar谩 y la capa de interfaz de usuario recibir谩 los datos actualizados.

android:text="@{viewModel.fetchedData}"

Flujo vinculante

Podemos crear una propiedad vinculante a partir de Flow usando @get:Bindable es asBindingProperty. Las capas de la interfaz de usuario recibir谩n los datos reci茅n recopilados del archivo. Flow o StateFlow sobre el viewModelScope. Y la propiedad de Flow debe ser de solo lectura (val), porque su valor solo se puede cambiar observando los cambios en el archivo Flow.

class MainViewModel : BindingViewModel() {

  private val stateFlow = MutableStateFlow(listOf<Poster>())

  @get:Bindable
  val data: List<Poster> by stateFlow.asBindingProperty()

  @get:Bindable
  var isLoading: Boolean by bindingProperty(false)
    private set

  init {
    viewModelScope.launch {
      stateFlow.emit(getFetchedDataFromNetwork())

      // .. //
    }
  }
}

Enlace SavedStateHandle

Podemos crear una propiedad vinculante a partir de SavedStateHandle en BindingViewModel usando usando @get:Bindable es asBindingProperty(key: String). Las capas de la interfaz de usuario recibir谩n los datos reci茅n guardados del archivo SavedStateHandle y podemos establecer el valor en SavedStateHandle cuando simplemente establecemos un valor para la propiedad.

@HiltViewModel
class MainViewModel @Inject constructor(
  private val savedStateHandle: SavedStateHandle
) : BindingViewModel() {

  @get:Bindable
  var savedPage: Int? by savedStateHandle.asBindingProperty("PAGE")

  // .. //

BindingRecyclerViewAdapter

Podemos crear propiedades de asociaci贸n en RecyclerView.Adapter utilizando la BindingRecyclerViewAdapter. En el siguiente ejemplo, el isEmpty la propiedad es observable en el dise帽o XML. Y podemos notificar los cambios de valor a DataBinding usando notifyPropertyChanged.

class PosterAdapter : BindingRecyclerViewAdapter<PosterAdapter.PosterViewHolder>() {

  private val items = mutableListOf<Poster>()

  @get:Bindable
  val isEmpty: Boolean
    get() = items.isEmpty()

  fun addPosterList(list: List<Poster>) {
    items.clear()
    items.addAll(list)
    notifyDataSetChanged()
    notifyPropertyChanged(::isEmpty)
  }
}

En el siguiente ejemplo, podemos crear el archivo placeholder desaparecen cuando la lista de elementos del adaptador est谩 vac铆a o se est谩n cargando datos.

<androidx.appcompat.widget.AppCompatTextView
    android:id="@+id/placeholder"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@string/empty"
    app:gone="@{!adapter.empty || viewModel.loading}" />

Encuadernaci贸nModelo

Podemos usar propiedades de asociaci贸n en nuestras clases extendiendo el archivo BindingModel.

class PosterUseCase : BindingModel() {

  @get:Bindable
  var message: String? by bindingProperty(null)
    private set

  init {
    message = getMessageFromNetwork()
  }
}

驴Le result贸 煤til esta biblioteca? 鉂わ笍

Ap贸yalo uni茅ndote astr贸nomos para este repositorio. ES 隆s铆gueme para mis pr贸ximas creaciones! 馃ぉ

Copyright 2021 skydoves (Jaewoong Eum)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

.

About MiReal

Compruebe tambi茅n

Blog para desarrolladores de Android: 隆Jetpack Compose Beta anunciado!

Publicado por Anna-Chiara Bellini, Gerente de producto, Nick Butcher, Relaciones con desarrolladores Hoy lanzamos la …

Deja una respuesta

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