计分器(ViewModel、Databinding实现数据的保存和控件操作)

Android中的ViewModel是一个可以用来存储UI相关的数据的类。ViewModel的生命周期会比创建它的Activity、Fragment的生命周期长。

 

 

可以看到重建的时候,ViewModel中的数据是不会被清理的

 

 

  Activity进行重建的时候,ViewModel的数据不会被回收调用。这时候我们就可以不用通过onSaveInstanceState()方法来进行数据的存储了。而且用onSaveInstanceState()方法为了使Activity能够尽快的重建还只能存储少量的数据进行恢复。
  Activity中通常会有有那种在其创建的时候获取数据,然后在其销毁的时候释放数据的方法。如果这些放在Activity中的话,在Activity进行重建的时候,会很浪费资源。但是如果方法在ViewModel中的话,Activity的重建将不会导致数据的重复获取。


  DataBinding 是谷歌官方发布的一个框架,顾名思义即为数据绑定,用于降低布局和逻辑的耦合性,使代码逻辑更加清晰。其实就是将 Presenter 层替换成了 ViewModel 层。DataBinding 能够省去我们一直以来的 findViewById() 步骤,大量减少 Activity 内的代码,数据能够单向或双向绑定到 layout 文件中,有助于防止内存泄漏,而且能自动进行空检测以避免空指针异常。另外的好处就是由于降低了控件与代码的相关联性,所以在对页面布局进行删减或修改时,基本不需要对程序进行大的修改,非常便于程序的维护和升级。


计分器实现功能:一个篮球计分器,对两队伍的得分进行统计,要保证屏幕旋转以及返回主菜单时可以保存数据,具备撤销功能(及返回上一步)
布局如下:
    

 

 这里引入ViewModel,整个Activity对应一个ViewModel对象。里面包含所有要保存和操作的界面值

 

package com.example.score;

import android.util.Log;

import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

public class MyViewModel  extends ViewModel {
    String TAG="output";
    private MutableLiveData<Integer> ATeamScore;
    private MutableLiveData<Integer> BTeamScore;
    private int aBack,bBack;      //作为存储上一步操作的比分值,用于撤销函数实现
    public MutableLiveData<Integer> getATeamScore() { //作为dadabinding中TextView(TeamA)的绑定
        if(ATeamScore==null)
        {
            ATeamScore=new MutableLiveData<>();
            ATeamScore.setValue(0);
        }

        return ATeamScore;
    }

    public MutableLiveData<Integer> getBTeamScore() { //作为dadabinding中TextView(TeamB)的绑定
        if(BTeamScore==null)
        {
            BTeamScore=new MutableLiveData<>();
            BTeamScore.setValue(0);
        }
        return BTeamScore;
    }

    public  void aTeamAdd(int p)
    {
        aBack=ATeamScore.getValue();
        bBack=BTeamScore.getValue();
        ATeamScore.setValue(ATeamScore.getValue()+p);   //aTeam的加分控件函数,会绑定到按键的xml文件中的Onclick对应函数上
    }
    public  void bTeamAdd(int p)
    {
        aBack=ATeamScore.getValue();
        bBack=BTeamScore.getValue();
        BTeamScore.setValue(BTeamScore.getValue()+p);  //bTeam的加分控件函数,会绑定到按键的xml文件中的Onclick对应函数上
    }
    public void reset()              //复位函数,将比分全清零
    {
        aBack=ATeamScore.getValue();
        bBack=BTeamScore.getValue();
        ATeamScore.setValue(0);
        BTeamScore.setValue(0);
        Log.d(TAG, "reset: ");//测试函数是否调用
    }

    public void withdraw()      //撤销函数,返回上一步的比分值
    {
       
        Log.d(TAG, "withdraw: ");//测试函数是否调用
        ATeamScore.setValue(aBack);
        BTeamScore.setValue(bBack);
    }
}

 

 

 

 databing的使用

ViewModel实现了数据的保存,保证了在屏幕发送旋转或返回主菜单时丢失数据,可是控件与代码的联系之前一直通过函数findViewByID()函数实现绑定,databing可是简化这步操作:
首先需要在gradle,script->build.gradle(Module:app)中添加如下代码:
  defaultConfig {
        applicationId "com.example.score"
        minSdkVersion 19
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        android.defaultConfig.vectorDrawables.useSupportLibrary = true

//添加代码如下:
dataBinding{ enabled true }

 

然后切换到布局文件,将布局文件由design模式切换为Code模式,如下图所示:

 

 

 

 

 到Code文件中找到提示Convert to data binding layout:单击整即可

 

 

然后添加如下代码

   <data>
    <variable
        name="data"  //作为ViewModel的变量名,后续进行调用实现绑定
        type="com.example.score.MyViewModel" />
    </data>

 

design布局下这个控件进行信息绑定:右键单击控件->go to xml

例如:

 

 就会跳转到控件对应的代码段

对TextView(分数A)的绑定如下:

 <TextView
            android:id="@+id/textView3"
            android:layout_width="140dp"
            android:layout_height="107dp"
            android:text="@{String.valueOf(data.getATeamScore())}" //修改主要在这,将文字显示绑定到ViewModel中的
            android:textAlignment="center"
            android:textColor="#F30606"
            android:textSize="@dimen/ScoreTextSize"
            app:layout_constraintBottom_toTopOf="@+id/guideline3"
            app:layout_constraintEnd_toStartOf="@+id/guideline11"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@+id/guideline2"
            app:layout_constraintVertical_bias="0.682"
            tools:text="120" />

        <TextView

 

所有Code代码如下所示:按上面方式操作即可

<?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>
    <variable
        name="data"
        type="com.example.score.MyViewModel" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="386dp"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

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

        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/guideline2"
            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/guideline3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            app:layout_constraintGuide_percent="0.33" />

        <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.57326734" />

        <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.71049595" />

        <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.8535179" />

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

        <TextView
            android:id="@+id/textView"
            android:layout_width="83dp"
            android:layout_height="32dp"
            android:text="@string/textview1"
            android:textAlignment="center"
            android:textSize="24sp"
            app:layout_constraintBottom_toTopOf="@+id/guideline2"
            app:layout_constraintEnd_toStartOf="@+id/guideline8"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@+id/guideline" />

        <TextView
            android:id="@+id/textView2"
            android:layout_width="77dp"
            android:layout_height="35dp"
            android:text="@string/textview2"
            android:textAlignment="center"
            android:textSize="@dimen/TeamTextSize"
            app:layout_constraintBottom_toTopOf="@+id/guideline2"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="@+id/guideline8"
            app:layout_constraintTop_toTopOf="@+id/guideline" />

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

        <TextView
            android:id="@+id/textView3"
            android:layout_width="140dp"
            android:layout_height="107dp"
            android:text="@{String.valueOf(data.getATeamScore())}"
            android:textAlignment="center"
            android:textColor="#F30606"
            android:textSize="@dimen/ScoreTextSize"
            app:layout_constraintBottom_toTopOf="@+id/guideline3"
            app:layout_constraintEnd_toStartOf="@+id/guideline11"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@+id/guideline2"
            app:layout_constraintVertical_bias="0.682"
            tools:text="120" />

        <TextView
            android:id="@+id/textView4"
            android:layout_width="138dp"
            android:layout_height="100dp"
            android:text="@{String.valueOf(data.getBTeamScore())}"
            android:textAlignment="center"
            android:textColor="#0CD681"
            android:textSize="@dimen/ScoreTextSize"
            app:layout_constraintBottom_toTopOf="@+id/guideline3"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="@+id/guideline12"
            app:layout_constraintTop_toTopOf="@+id/guideline2"
            app:layout_constraintVertical_bias="0.666"
            tools:text="0" />

        <Button
            android:id="@+id/button2"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:background="#8BC34A"
            android:onClick="@{()->data.bTeamAdd(1)}"
            android:text="@string/button1"
            android:textColor="#FFFFFF"
            android:textSize="@dimen/ButtonTextSzie"
            app:layout_constraintBottom_toTopOf="@+id/guideline4"
            app:layout_constraintEnd_toStartOf="@+id/guideline10"
            app:layout_constraintStart_toStartOf="@+id/guideline12"
            app:layout_constraintTop_toTopOf="@+id/guideline3"
            app:layout_constraintVertical_bias="0.407" />

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

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

        <Button
            android:id="@+id/button3"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:background="#F44336"
            android:onClick="@{()->data.aTeamAdd(2)}"
            android:text="@string/button2"
            android:textColor="#FFFFFF"
            android:textSize="@dimen/ButtonTextSzie"
            app:layout_constraintBottom_toTopOf="@+id/guideline5"
            app:layout_constraintEnd_toStartOf="@+id/guideline11"
            app:layout_constraintStart_toStartOf="@+id/guideline9"
            app:layout_constraintTop_toTopOf="@+id/guideline4"
            app:layout_constraintVertical_bias="0.268" />

        <Button
            android:id="@+id/button4"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:background="#8BC34A"
            android:onClick="@{()->data.bTeamAdd(2)}"
            android:text="@string/button2"
            android:textColor="#FFFFFF"
            android:textSize="@dimen/ButtonTextSzie"
            app:layout_constraintBottom_toTopOf="@+id/guideline5"
            app:layout_constraintEnd_toStartOf="@+id/guideline10"
            app:layout_constraintStart_toStartOf="@+id/guideline12"
            app:layout_constraintTop_toTopOf="@+id/guideline4" />

        <Button
            android:id="@+id/button5"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:background="#F44336"
            android:onClick="@{()->data.aTeamAdd(3)}"
            android:text="@string/button3"
            android:textColor="#FFFFFF"
            android:textSize="@dimen/ButtonTextSzie"
            app:layout_constraintBottom_toTopOf="@+id/guideline6"
            app:layout_constraintEnd_toStartOf="@+id/guideline11"
            app:layout_constraintStart_toStartOf="@+id/guideline9"
            app:layout_constraintTop_toTopOf="@+id/guideline5" />

        <Button
            android:id="@+id/button6"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:background="#8BC34A"
            android:onClick="@{()->data.bTeamAdd(3)}"
            android:text="@string/button3"
            android:textColor="#FFFFFF"
            android:textSize="@dimen/ButtonTextSzie"
            app:layout_constraintBottom_toTopOf="@+id/guideline6"
            app:layout_constraintEnd_toStartOf="@+id/guideline10"
            app:layout_constraintStart_toStartOf="@+id/guideline12"
            app:layout_constraintTop_toTopOf="@+id/guideline5"
            app:layout_constraintVertical_bias="0.507" />

        <ImageButton
            android:id="@+id/imageButton2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:contentDescription="@string/ResetButtton"
            android:onClick="@{()->data.reset()}"
            app:layout_constraintBottom_toTopOf="@+id/guideline7"
            app:layout_constraintEnd_toStartOf="@+id/guideline10"
            app:layout_constraintStart_toStartOf="@+id/guideline12"
            app:layout_constraintTop_toTopOf="@+id/guideline6"
            app:srcCompat="@drawable/ic_baseline_loop_24" />

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

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

        <Button
            android:id="@+id/button"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:background="#F44336"
            android:text="@string/button1"
            android:textColor="#FFFFFF"
            android:textSize="@dimen/ButtonTextSzie"
            android:onClick="@{()->data.aTeamAdd(1)}"
            app:layout_constraintBottom_toTopOf="@+id/guideline4"
            app:layout_constraintEnd_toStartOf="@+id/guideline11"
            app:layout_constraintStart_toStartOf="@+id/guideline9"
            app:layout_constraintTop_toTopOf="@+id/guideline3" />

        <ImageButton
            android:id="@+id/imageButton3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:contentDescription="@string/UndoButton"
            android:onClick="@{()->data.withdraw()}"
            app:layout_constraintBottom_toTopOf="@+id/guideline7"
            app:layout_constraintEnd_toStartOf="@+id/guideline11"
            app:layout_constraintStart_toStartOf="@+id/guideline9"
            app:layout_constraintTop_toTopOf="@+id/guideline6"
            app:srcCompat="@drawable/ic_baseline_undo_24" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

 

主程序如下

package com.example.score;

import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.lifecycle.ViewModelProvider;

import android.os.Bundle;

import com.example.score.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {
    MyViewModel myViewModel;
    ActivityMainBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setContentView(R.layout.activity_main);
        binding=DataBindingUtil.setContentView(this,R.layout.activity_main);
        myViewModel=new ViewModelProvider(this).get(MyViewModel.class);
        binding.setData(myViewModel);
        binding.setLifecycleOwner(this);//这个一定不能少
    }
}

 

posted @ 2020-11-26 17:00  victorywr  阅读(612)  评论(0编辑  收藏  举报