Bindables
This library provides base classes for DataBinding (BindingActivity, BindingFragment, BindingViewModel),
and support ways in which notifying data changes without observable fields and LiveData.
UseCase
You can reference the good use cases of this library in the below repositories.
- Pokedex -
π‘οΈ Android Pokedex using Hilt, Motion, Coroutines, Flow, Jetpack (Room, ViewModel, LiveData) based on MVVM architecture. - DisneyMotions -
π¦ A Disney app using transformation motions based on MVVM (ViewModel, Coroutines, LiveData, Room, Repository, Koin) architecture. - MarvelHeroes -
β€οΈ A sample Marvel heroes application based on MVVM (ViewModel, Coroutines, LiveData, Room, Repository, Koin) architecture. - TheMovies2 -
π¬ A demo project using The Movie DB based on Kotlin MVVM architecture and material design & animations.
Download
Gradle
Add below codes to your root build.gradle
file (not your module build.gradle file).
allprojects {
repositories {
mavenCentral()
}
}
And add a dependency code to your module's build.gradle
file.
dependencies {
implementation "com.github.skydoves:bindables:1.0.8"
}
SNAPSHOT
Snapshots of the current development version of Bindables are available, which track the latest versions.
repositories {
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
}
Setup DataBinding
If you already use DataBinding
in your project, you can skip this step. Add below on your build.gradle
and make sure to use DataBinding
in your project.
plugins {
...
id 'kotlin-kapt'
}
android {
...
buildFeatures {
dataBinding true
}
}
BindingActivity
BindingActivity
is a base class for Activities that wish to bind content layout with DataBindingUtil
. It provides a binding
property that extends ViewDataBinding
from abstract information. The binding
property will be initialized lazily but ensures to be initialized before being called super.onCreate
in Activities. So we don't need to inflate layouts, setContentView, and initialize a binding property manually.
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
}
}
}
Extending BindingActivity
If you want to extend BindingActivity
for designing your own base class, you can extend like the below.
abstract class BaseBindingActivity<T : ViewDataBinding> constructor(
@LayoutRes val contentLayoutId: Int
) : BindingActivity(contentLayoutId) {
// .. //
}
BindingFragment
The concept of the BindingFragment
is not much different from the BindingActivity
. It ensures the binding
property to be initialized in 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
}
}
Extending BindingFragment
If you want to extend BindingFragment
for designing your own base class, you can extend like the below.
abstract class BaseBindingFragment<T : ViewDataBinding> constructor(
@LayoutRes val contentLayoutId: Int
) : BindingFragment(contentLayoutId) {
// .. //
}
BindingViewModel
BindingViewModel
provides a way in which UI can be notified of changes by the Model layers.
bindingProperty
bindingProperty
notifies a specific has changed and it can be observed in UI layers. The getter for the property that changes should be marked with @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
// ... //
}
}
In our XML layout, the changes of properties value will be notified to DataBinding automatically whenever we change the value.
"><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" />