Kotlin 是谷歌官方最新支持的一级语言,新版的 Android Studio3.0 Beta 版已经原声支持 Kotlin。昨天的新闻说 J 神也加入了谷歌的 Kotlin 组,觉得 Kotlin 会成为大势啊!
LiveData 是一个数据持有者类,它持有一个值并允许观察该值。它还可以与 Lifecycle 绑定,与观察者的生命周期同步。简单的说就是,把数据放到 LiveData 里面,然后给 LiveData 设置监听器,当数据改变的时候,会自动调用监听器。与 Lifecycle 绑定,当 Activity 被回收之后不会被触发监听。配合单例模式,可以很轻松的实现在一处修改数据,多处 activity,fragment 收到通知。
DataBinding 可以让你的的 UI 代码变得相当干净利落。它可以把页面逻辑从你的代码中提取出来。让你的代码更加专注处理其他事情。
我们把 DataBinding 的 ViewModel 设置成 LiveData,在 LiveData 的监听器中调用 DataBinding 的刷新。这项在任何地方修改 ViewModel,UI 就会自动更新。
接下来,举个例子。我们在上面的输入框输入文本。下面的文本框会实时反映输入的内容。
首先是配置环境, 我使用的是 AndroidStudio3.0 Beta1 Project 的 gradle 如下:
- // 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-beta1'
- 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
- }
Module 的 gradle 如下:
- 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:compiler:3.0.0-beta1'
- 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.constraint: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
- }
比较重要的是 dataBinding {enabled = true} 开启 databing。
下面开始撸代码。 首先是 ViewModel 类,也是一个 LiveData 类。
- 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>()
- }
这个类里面只有 2 个字段,分别对应界面上的输入框的内容,和文本框的显示内容。 然后是布局文件 acticity_main.xml
- 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"
- xmlns:tools="http://schemas.android.com/tools">
- type="com.greendami.gdm.SearchViewModel" />
- name="model"
- type="SearchViewModel" />
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context="com.greendami.gdm.MainActivity">
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:id="@+id/input"
- android:inputType="textNoSuggestions"
- android:imeOptions="actionSearch"
- tools:text="google"/>
- 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" />
首先最顶层的布局是 layout,然后下面第一个是 data 域,是声明数据的地方。后面就是正常的布局。我们首先声明了一个 SearchViewMode 类型的对象 model。然后再 TextView 中进行绑定 android:text="@{model.show_string.value}"。这里的 **.value** 是 LiveData 的取值的方式。
然后是 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 = "等待输入"
- 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()
- })
- }
- }
说明一下 **var binding = DataBindingUtil.setContentView(this, R.layout.activity_main)** 把布局加载进来,这里要注意的是 ActivityMainBinding 这个类可能一开始没有生成,可以尝试 rebuild 一下,或者重启 IDE。 获取到 binding 对象之后,就可以给对象绑定 ViewModel 了,也就是代码中的 searchViewModel。
我们使用 binding 对象. 控件 ID 来拿到控件对象。比如:
- 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) {
- }
- })
在监听器中修改 LiveData 的值。 因为我们设置了 LiveData 的观察者
- binding.model?.show_string?.observe( this@MainActivity, Observer{
- Log.e("TAG",binding.model?.show_string?.value)
- Log.e("TAG",binding.hasPendingBindings().toString())
- binding.invalidateAll()
- })
当数据修改后这里就会被调用。这里的第一个参数 this,是 LifecycleActivity,所以这个监听器绑定了 MainActvity 的生命周期。这里使用了 binding.invalidateAll(),而没有使用 binding.executePendingBindings() 是因为这里改变 LiveData 的 value 后,binding.hasPendingBindings() 返回 false, 也就是说,databinding 没有感知到数据的改变,所以不会刷新界面。
来源: https://juejin.im/post/5a33153ef265da432c23e253