Kotlin is officially a first-level language supported by Google. The new Beta version of Android Studio3.0 has original Kotlin support. Yesterday’s news said god J has joined Google’s Kotlin group. I think Kotlin is going to be a big deal.
LiveData is a data holder class that holds a value and allows observation of that value. It can also be bound to Lifecycle, synchronizing with the Lifecycle of the observer. Simply put, put the data into LiveData, and then set up a listener for LiveData. When the data changes, the listener will be called automatically. Lifecycle binding will not trigger listening when an Activity is recycled. With the singleton mode, it is easy to modify data in one place and receive notifications for multiple activities and fragments.
DataBinding can make your UI code pretty clean. It takes the page logic out of your code. Make your code more focused on other things.
We set DataBinding’s ViewModel to LiveData and invoke DataBinding’s refresh in LiveData’s listener. This modifies the ViewModel anywhere, and the UI updates automatically.
Now, here’s an example. We enter text in the input box above. The text box below reflects the input in real time.
AndroidStudio3.0 Beta1 Project gradle is as follows:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '1.1.3-2'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com. Android. Tools. Build: gradle: 3.0.0 - walk'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
ext.arch_version = "1.0.0 - alpha7"
allprojects {
repositories {
google()
jcenter()
mavenCentral()
maven { url 'https://maven.google.com' }
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}Copy the code
Module gradle is as follows:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 26
buildToolsVersion "26.0.1"
defaultConfig {
applicationId "com.greendami.gdm"
minSdkVersion 15
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
dataBinding {
enabled = true
}
}
dependencies {
kapt 'com. Android. Databinding: the compiler: 3.0.0 - walk'
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
implementation 'com. Android. Support: appcompat - v7:26.0.1'
implementation 'com. Android. Support. The constraint, the constraint - layout: 1.0.2'
testImplementation 'junit: junit: 4.12'
androidTestImplementation 'com. Android. Support. Test: runner: 0.5'
androidTestImplementation 'com. Android. Support. Test. Espresso: espresso - core: 2.2.2'
compile "android.arch.persistence.room:runtime:$arch_version"
compile "android.arch.lifecycle:runtime:$arch_version"
compile "android.arch.lifecycle:extensions:$arch_version"
annotationProcessor "android.arch.persistence.room:compiler:$arch_version"
annotationProcessor "android.arch.lifecycle:compiler:$arch_version"
}
kapt {
generateStubs = true
}Copy the code
The important thing is dataBinding {enabled = true} to enable databing.
So let’s start coding. The first is the ViewModel class, which is also a LiveData class.
package com.greendami.gdm
import android.arch.lifecycle.MutableLiveData
import android.arch.lifecycle.ViewModel
/**
* Created by GreendaMi on 2017/8/10.
*/
class SearchViewModel : ViewModel() {
val show_string = MutableLiveData<String>()
val input_string = MutableLiveData<String>()
}Copy the code
There are only two fields in this class, corresponding to the content of the input box on the interface, and the display content of the text box. Next is the layout file acticity_main.xml
<?xml version="1.0" encoding="utf-8"? >
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="com.greendami.gdm.SearchViewModel" />
<variable
name="model"
type="SearchViewModel" />
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.greendami.gdm.MainActivity">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/input"
android:inputType="textNoSuggestions"
android:imeOptions="actionSearch"
tools:text="google"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{model.show_string.value}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
</layout>Copy the code
The top layer of the layout is the layout, and then the first one below is the data field, which is where the data is declared. The back is the normal layout. We start by declaring an object model of type SearchViewMode. Android :text=”@{model.show_string.value}” The dot value here is how LiveData is evaluated.
And then the MainActivity. Kt
package com.greendami.gdm import android.arch.lifecycle.LifecycleActivity import android.arch.lifecycle.Observer import android.databinding.DataBindingUtil import android.os.Bundle import android.text.Editable import android.text.TextWatcher import android.util.Log import com.greendami.gdm.databinding.ActivityMainBinding class MainActivity : LifecycleActivity() { var searchViewModel: SearchViewModel = SearchViewModel() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) var binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main) searchViewModel.show_string.value = "Waiting for input" binding. Model = searchViewModel binding.input.addTextChangedListener(object : TextWatcher { override fun afterTextChanged(p0: Editable?) { binding.model? .show_string? .value = p0.toString() } override fun beforeTextChanged(p0: CharSequence? , p1: Int, p2: Int, p3: Int) { } override fun onTextChanged(p0: CharSequence? , p1: Int, p2: Int, p3: Int) { } }) binding.model? .show_string? .observe( this@MainActivity, Observer{ Log.e("TAG",binding.model? .show_string? .value) Log.e("TAG",binding.hasPendingBindings().toString()) binding.invalidateAll() }) } }Copy the code
Explain the var binding = DataBindingUtil. The setContentView (this, R.l ayout. Activity_main) the load in layout, Note here that the ActivityMainBinding class may not be generated at first. Try rebuilding or restart the IDE. Once you get the Binding object, you can bind the ViewModel to the object, which is the searchViewModel in the code.
We use a Binding object. Control ID to get the control object. Such as:
binding.input.addTextChangedListener(object : TextWatcher { override fun afterTextChanged(p0: Editable?) { binding.model? .show_string? .value = p0.toString() } override fun beforeTextChanged(p0: CharSequence? , p1: Int, p2: Int, p3: Int) { } override fun onTextChanged(p0: CharSequence? , p1: Int, p2: Int, p3: Int) { } })Copy the code
Modify the value of LiveData in the listener. Because we set the LiveData observer
binding.model? .show_string? .observe( this@MainActivity, Observer{ Log.e("TAG",binding.model? .show_string? .value) Log.e("TAG",binding.hasPendingBindings().toString())
binding.invalidateAll()
})Copy the code
This is called when the data is modified. The first parameter here, this, is LifecycleActivity, so this listener is tied to the lifecycle of the MainActvity. Here using the binding. InvalidateAll (), and not to use the binding. ExecutePendingBindings () because it changes LiveData value, Binding. HasPendingBindings () returns false, that is to say, the databinding did not perceive the change of the data, so will not refresh interface.