ViewModel_DataBinding_SavedStateHandle(kotlin)

本文为jetpack学习案例,来自于
https://www.bilibili.com/video/BV1w4411t7UQ/?p=13

涉及内容:
ViewModel
LiveData
Databinding
android studio 自带图标库
SavedStateHandle

篮球计分器:使用ViewModel+DataBinding来进行ui操作,使用SavedStateHandle保存数据

ViewModel_DataBinding_SavedStateHandle(kotlin)_第1张图片

一、配置

本文环境为:

android studio 3.6.2 
gradle version 5.6.4
kotlin version 1.3.71
windows 10 pro

app build.gradle中开启databinding

   dataBinding { // 开启 DataBinding

            enabled true

        }

导入viewModel依赖

 implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
 implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'

二、代码编写

1.界面

新手注意

1.一定要转换布局,否则没办法进行绑定

ViewModel_DataBinding_SavedStateHandle(kotlin)_第2张图片

2.注意绑定点击事件的方式

android:onClick="@{()->data.addScore2B(1)}"

3.绑定数值方式

android:text="@{data.getTeanAScore().toString()}"

具体布局文件如下


<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="data"
            type="com.example.scorer.MyViewModel" />
    data>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.5" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.15" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline6"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.05" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline7"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.35" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline9"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.5" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline10"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.65" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline11"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.8" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline12"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.9" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/textview1"
        android:textSize="@dimen/TeamTextSize"
        app:layout_constraintBottom_toTopOf="@+id/guideline5"
        app:layout_constraintEnd_toStartOf="@+id/guideline4"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/guideline6" />

    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/textview2"
        android:textSize="@dimen/TeamTextSize"
        app:layout_constraintBottom_toTopOf="@+id/guideline5"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="@+id/guideline4"
        app:layout_constraintTop_toTopOf="@+id/guideline6" />

    <TextView
        android:id="@+id/scoreA"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{data.getTeanAScore().toString()}"
        android:textColor="@color/colorTeamA"
        android:textSize="@dimen/scoreTextSize"
        app:layout_constraintBottom_toTopOf="@+id/guideline7"
        app:layout_constraintEnd_toStartOf="@+id/guideline4"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/guideline5" />

    <TextView
        android:id="@+id/scoreB"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{data.getTeanBScore().toString()}"
        android:textSize="@dimen/scoreTextSize"
        android:textColor="@color/colorAccent"
        app:layout_constraintBottom_toTopOf="@+id/guideline7"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="@+id/guideline4"
        app:layout_constraintTop_toTopOf="@+id/guideline5" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/button1"
        android:textSize="@dimen/buttonSize"
        android:background="@color/colorTeamA"
        android:onClick="@{()->data.addScore2A(1)}"
        app:layout_constraintBottom_toTopOf="@+id/guideline9"
        app:layout_constraintEnd_toStartOf="@+id/guideline4"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/guideline7" />

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/button1"
        android:textSize="@dimen/buttonSize"
        android:background="@color/colorAccent"
        android:onClick="@{()->data.addScore2B(1)}"
        app:layout_constraintBottom_toTopOf="@+id/guideline9"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="@+id/guideline4"
        app:layout_constraintTop_toTopOf="@+id/guideline7" />

    <Button
        android:id="@+id/button4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/button2"
        android:textSize="@dimen/buttonSize"
        android:background="@color/colorTeamA"
        android:onClick="@{()->data.addScore2A(2)}"
        app:layout_constraintBottom_toTopOf="@+id/guideline10"
        app:layout_constraintEnd_toStartOf="@+id/guideline4"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/guideline9"
        />

    <Button
        android:id="@+id/button5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/button2"
        android:textSize="@dimen/buttonSize"
        android:background="@color/colorAccent"
        android:onClick="@{()->data.addScore2B(2)}"
        app:layout_constraintBottom_toTopOf="@+id/guideline10"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="@+id/guideline4"
        app:layout_constraintTop_toTopOf="@+id/guideline9" />

    <Button
        android:id="@+id/button6"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/button3"
        android:textSize="@dimen/buttonSize"
        android:background="@color/colorTeamA"
        android:onClick="@{()->data.addScore2A(3)}"
        app:layout_constraintBottom_toTopOf="@+id/guideline11"
        app:layout_constraintEnd_toStartOf="@+id/guideline4"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/guideline10" />

    <Button
        android:id="@+id/button7"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/button3"
        android:textSize="@dimen/buttonSize"
        android:background="@color/colorAccent"
        android:onClick="@{()->data.addScore2B(3)}"
        app:layout_constraintBottom_toTopOf="@+id/guideline11"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="@+id/guideline4"
        app:layout_constraintTop_toTopOf="@+id/guideline10" />

    <ImageButton
        android:id="@+id/imageButton_undo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toTopOf="@+id/guideline12"
        app:layout_constraintEnd_toStartOf="@+id/guideline4"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/guideline11"
        android:contentDescription="@string/undo"
        android:onClick="@{()->data.undo()}"
        app:srcCompat="@drawable/ic_undo_black_24dp" />

    <ImageButton
        android:id="@+id/imageButton_refresh"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toTopOf="@+id/guideline12"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="@+id/guideline4"
        app:layout_constraintTop_toTopOf="@+id/guideline11"
        android:contentDescription="@string/refresh"
        android:onClick="@{()->data.reset()}"
        app:srcCompat="@drawable/ic_loop_black_24dp" />


androidx.constraintlayout.widget.ConstraintLayout>
layout>

2.MainActivity

package com.example.scorer

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.SavedStateViewModelFactory
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProviders
import com.example.scorer.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    private lateinit var mViewModel: MyViewModel
    var binding: ActivityMainBinding ?= null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
//        setContentView(R.layout.activity_main)
        //绑定视图
        binding=DataBindingUtil.setContentView(this,R.layout.activity_main)
        mViewModel=ViewModelProvider(this).get(MyViewModel::class.java)
        //绑定数据
        binding!!.data=mViewModel
        //绑定生命周期
        binding!!.lifecycleOwner = this

    }

    companion object {
        const val SCOREA:String="scoreA"
        const val SCOREB:String="scoreB"
        const val LIST:String="List"
    }
}

3.MyViewModel

package com.example.scorer

import android.util.Log
import android.widget.Toast
import androidx.lifecycle.ViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
import kotlin.math.log

class MyViewModel(handle: SavedStateHandle) : ViewModel() {
    //声明变量:两队的分数,使用MutableLiveData
    private  var teamAScore:MutableLiveData<Int>?=null
    private  var teamBScore:MutableLiveData<Int>?=null
    //撤回信息数组
    private var list:MutableLiveData<ArrayList<Undo>>? = null
    private var mhandle=handle


    /**
     * 获取A队分数
     */
    fun getTeanAScore(): MutableLiveData<Int>{
        if (teamAScore==null){
            if (!(mhandle!!.contains(MainActivity.SCOREA))){
                mhandle!!.set(MainActivity.SCOREA,0)
            }
            teamAScore= mhandle!!.getLiveData(MainActivity.SCOREA)
            return teamAScore as MutableLiveData<Int>
        }else{
            return teamAScore as MutableLiveData<Int>
        }
//

    }

    /**
     * 获取撤销数组
     */
    fun getList(): MutableLiveData<ArrayList<Undo>>? {
        if (!(mhandle!!.contains(MainActivity.LIST))){
            var mlist= arrayListOf<Undo>()
            mhandle.set(MainActivity.LIST, mlist)
        }
        list=mhandle.getLiveData(MainActivity.LIST)
        return list
    }
    /**
     * 获取B队分数
     */
    fun getTeanBScore():MutableLiveData<Int>{
        if (teamBScore==null){
            if (!(mhandle!!.contains(MainActivity.SCOREB))){
                mhandle!!.set(MainActivity.SCOREB,0)
            }
            teamBScore= mhandle!!.getLiveData(MainActivity.SCOREB)
            return teamBScore as MutableLiveData<Int>
        }else{
            return teamBScore as MutableLiveData<Int>
        }
    }

    /**
     * A队加分
     */
    fun addScore2A(n:Int){
        if (list==null){
            getList()
        }
        list!!.value!!.add(Undo("A", teamAScore?.value!!))
        teamAScore?.value = teamAScore?.value?.plus(n)


    }

    /**
     * B队伍加分
     */
    fun addScore2B(n:Int){
        if (list==null){
            getList()
        }
        list!!.value!!.add(Undo("B", teamBScore?.value!!))
        teamBScore?.value = teamBScore?.value?.plus(n)


    }

    /**
     * 重置
     */
    fun reset(){
        list!!.value!!.add(Undo("A", teamAScore?.value!!))
        list!!.value!!.add(Undo("B", teamBScore?.value!!))
        teamAScore.also {
            it!!.value=0
        }

        teamBScore.also {
            it!!.value=0
        }

    }

    /**
     * 撤回
     */
    fun undo(){
      if (list!!.value!!.size>0){
          var undo=list!!.value!![list!!.value!!.size-1]

          when(undo.team){
              "A"->{
                  teamAScore?.value = undo.n
                  Log.i("score","A 加分:${teamAScore?.value!!}")
              }
              "B"->{
                  teamBScore?.value = undo.n
                  Log.i("score","B 加分:${teamBScore?.value!!}")
              }
          }
          list!!.value!!.removeAt(list!!.value!!.size-1)
      }
    }
}

4.Undo

package com.example.scorer

import android.os.Parcel
import android.os.Parcelable
import java.io.Serializable

/**
 * 保存撤回所用的信息
 */
data class Undo(val team:String,val n:Int):Serializable{

}

三、补充知识点

1.android studio自带图标库

ViewModel_DataBinding_SavedStateHandle(kotlin)_第3张图片
ViewModel_DataBinding_SavedStateHandle(kotlin)_第4张图片

项目
https://gitee.com/lee_gitee/Jetpack_DataBinding_kotlin

你可能感兴趣的:(jetpack)