zoukankan      html  css  js  c++  java
  • ViewModel、LiveData、DataBinding

    ViewModel

    ViewModel的引入

    如果系统销毁或重新创建界面控制器,则存储在其中的任何临时性界面相关数据都会丢失。例如,应用的某个 Activity 中可能包含用户列表。因配置更改而重新创建 Activity 后,新 Activity 必须重新提取用户列表。对于简单的数据,Activity 可以使用 onSaveInstanceState() 方法从 onCreate() 中的捆绑包恢复其数据,但此方法仅适合可以序列化再反序列化的少量数据,而不适合数量可能较大的数据,如用户列表或位图。
    架构组件为界面控制器提供了 ViewModel 辅助程序类,该类负责为界面准备数据。在配置更改期间会自动保留 ViewModel 对象,以便它们存储的数据立即可供下一个 Activity 或 Fragment 实例使用。

    实现ViewModel

    package com.zyb.viewmodeltest;
    
    import androidx.lifecycle.ViewModel;
    
    public class MyViewModel extends ViewModel {
        public int num = 0;
    }
    
    

    从 Activity 访问该列表,如下所示:

    package com.zyb.viewmodeltest;
    import androidx.appcompat.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    import android.widget.TextView;
    
    import androidx.lifecycle.ViewModelProviders;
    public class MainActivity extends AppCompatActivity {
    
        MyViewModel myViewModel;
        Button button1,button2;
        TextView showScore;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
            button1 = findViewById(R.id.button);
            button2 = findViewById(R.id.button2);
            showScore = findViewById(R.id.textView);
    
            showScore.setText(myViewModel.num+"");
    
            button1.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    myViewModel.num++;
                    showScore.setText(myViewModel.num+"");
                }
            });
    
            button2.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    myViewModel.num += 2;
                    showScore.setText(myViewModel.num+"");
                }
            });
    
    
        }
    }
    

    ui:

    功能:点击+1,数字+1,点击+2,数字在原来基础上+2
    优点:不用我们保存之前加过数字的状态,因为在配置更改期间会自动保留 ViewModel 对象
    缺点: showScore.setText();出现过多,代码累赘,setOnClickListener出现过多代码不好看

    LiveData

    使用 LiveData 具有以下优势:

    确保界面符合数据状态
    LiveData 遵循观察者模式。当生命周期状态发生变化时,LiveData 会通知 Observer 对象。您可以整合代码以在这些 Observer 对象中更新界面。观察者可以在每次发生更改时更新界面,而不是在每次应用数据发生更改时更新界面。
    不会发生内存泄露
    观察者会绑定到 Lifecycle 对象,并在其关联的生命周期遭到销毁后进行自我清理。
    不会因 Activity 停止而导致崩溃
    如果观察者的生命周期处于非活跃状态(如返回栈中的 Activity),则它不会接收任何 LiveData 事件。
    不再需要手动处理生命周期
    界面组件只是观察相关数据,不会停止或恢复观察。LiveData 将自动管理所有这些操作,因为它在观察时可以感知相关的生命周期状态变化。
    数据始终保持最新状态
    如果生命周期变为非活跃状态,它会在再次变为活跃状态时接收最新的数据。例如,曾经在后台的 Activity 会在返回前台后立即接收最新的数据。
    适当的配置更改
    如果由于配置更改(如设备旋转)而重新创建了 Activity 或 Fragment,它会立即接收最新的可用数据。
    共享资源
    您可以使用单一实例模式扩展 LiveData 对象以封装系统服务,以便在应用中共享它们。LiveData 对象连接到系统服务一次,然后需要相应资源的任何观察者只需观察 LiveData 对象。有关详情,请参阅扩展 LiveData。
    实现LiveData

    package com.zyb.livedatatest;
    
    import androidx.lifecycle.MutableLiveData;
    import androidx.lifecycle.ViewModel;
    
    public class MyViewModel extends ViewModel {
        private MutableLiveData<Integer> num;
    
        public MutableLiveData<Integer> getNum() {
            if(num == null){
                num = new MutableLiveData<>();
                num.setValue(0);
            }
            return num;
        }
    
        public MutableLiveData<Integer> addNum(int n){
            num.setValue(num.getValue()+n);
            return num;
        }
    }
    
    

    从 Activity 访问该列表,如下所示:

    package com.zyb.livedatatest;
    
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.lifecycle.Observer;
    import androidx.lifecycle.ViewModel;
    import androidx.lifecycle.ViewModelProviders;
    
    import android.os.Bundle;
    import android.view.View;
    import android.widget.ImageButton;
    import android.widget.TextView;
    
    public class MainActivity extends AppCompatActivity {
    
        ImageButton redButton,blueButton;
        TextView score;
        MyViewModel myViewModel;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            redButton = findViewById(R.id.imageButton);
            blueButton = findViewById(R.id.imageButton3);
            score = findViewById(R.id.textView);
    
           myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
           //观察数据是否改变,改变就重写
           myViewModel.getNum().observe(this, new Observer<Integer>() {
               @Override
               public void onChanged(Integer integer) {
                   score.setText(integer+"");
               }
           });
           redButton.setOnClickListener(new View.OnClickListener() {
               @Override
               public void onClick(View v) {
                   myViewModel.addNum(1);
               }
           });
           blueButton.setOnClickListener(new View.OnClickListener() {
               @Override
               public void onClick(View v) {
                   myViewModel.addNum(-1);
               }
           });
        }
    }
    
    

    ui:

    功能:左边+1,右边-1
    优点:将setText()减少到一句
    缺点:setOnClickListener出现过多代码不好看

    DataBinding

    在buid.gradle开启数据绑定:

    之后重新构建项目sync
    进入activity_main.xml中点击

    之后会多两个标签

    package com.zyb.databindingtest;
    
    import androidx.lifecycle.MutableLiveData;
    import androidx.lifecycle.ViewModel;
    
    public class MyViewModel extends ViewModel {
        MutableLiveData<Integer> cnt;
    
        public MutableLiveData<Integer> getCnt() {
            if(cnt == null){
                cnt = new MutableLiveData<>();
                cnt.setValue(0);
            }
            return cnt;
        }
    
        public void add(int n){
            cnt.setValue(cnt.getValue()+n);
        }
    }
    
    

    MainActivity.java

    package com.zyb.databindingtest;
    
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.databinding.DataBindingUtil;
    import androidx.lifecycle.ViewModel;
    import androidx.lifecycle.ViewModelProvider;
    import androidx.lifecycle.ViewModelProviders;
    
    import android.os.Bundle;
    
    import com.zyb.databindingtest.databinding.ActivityMainBinding;
    
    public class MainActivity extends AppCompatActivity {
    
        //绑定1:将界面对象绑定到控制器的ActivityMainBinding对象中(可以调用bind.xml标签名)
        ActivityMainBinding bind;//注意这个类的名字和你Java文件的名字相同,不是固定的
        MyViewModel myViewModel;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            bind = DataBindingUtil.setContentView(this,R.layout.activity_main);
            myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
            //绑定2:将屏幕数据和控件的xml绑定
            bind.setData1(myViewModel);//setData1是因为在xml那个数据的name自己设定的data1,所以这setData1也是不固定的
            //这句很重要,相当于之前设置的观察者语句
            bind.setLifecycleOwner(this);
    
        }
    }
    
    

    ui:

    功能:显示点击按钮次数
    优点:控制器代码减少,分工更明确
    activity_main.xml变化:这个写法有点像javaweb的模板引擎thymeleaf



    最后的
    thymeleaf相关图:

    相关变化图:
    最原始的,通过findViewById将单个组件的引用和控制器来连接起来,数据显示和变化都在控制器中

    加入ViewModel之后将页面数据(UIData)单独提出来封装

    加入LiveData,将之前提出来的UIData换为LiveData类型的,因为它满足观察者类型,可以减少setText的书写,降低代码耦合性

    加入DataBinding将数据操作绑定到相关界面的xml文件中,减少控制器的代码量,分工更明确了
    ui

    参考链接

    [android开发者官网](https://developer.android.google.cn/jetpack) [视频](https://www.bilibili.com/video/av50954019?p=11)
    不一样的烟火
  • 相关阅读:
    USASO Greedy Gift Givers
    Mat 类型用法
    OpenCV错误:Unhandled exception at 0x0133bc63 ....0xC0000005: Access violation reading location 0x00000004.
    C++ seekp 函数文件流跳转功能产生数据覆盖问题解决
    C++中文件名称必须是C风格的char*格式
    char*, char[] ,CString, string的转换
    Visual Stdio 2008 最大内存分配块大小问题: 使用new 分配连续723M内存 出错 std::bad_alloc at memory location 0x0013e0b8
    string类型转化为char*错误: error C2440: '=' : cannot convert from 'const char *' to 'char *'
    Mat 和 IplImage、CvMat格式的互相转换
    指针数组和数组指针
  • 原文地址:https://www.cnblogs.com/cstdio1/p/12346617.html
Copyright © 2011-2022 走看看