ViewModel的理解

ViewModel

Activity的生命周期

先说一下

在这里插入图片描述

作用
OnCreate()是Activity被创建,布局文件加载与事件的绑定
OnStart()Activity由不可见变为可见,还不能进行交互,数据初始化
OnResume()用户可以与Activity进行交互
OnPause()Activity停止,从前端返回后台,停止数据和动画存储,只有第一个活动的OnPause()执行完后,第二个活动的OnResume()才会执行…这个方法在系统准备去启动或者恢复另一个活动的时候调用
OnStop()活动完全不可见,但可以进行一些轻量级的回收工作,但是如果你打开的新的界面是透明界面,第一个活动还是可以看见,所以第一个活动的OnStop()是不会进行
OnDestroy()活动彻底结束
OnRestart()活动重新启动

一般情况,A/B 均不是透明页面:
A 跳转 B 页面会经历的生命周期:A.onPause() -> B.onCreate() -> B.onStart() -> B.onResume() -> A.onStop。
从 B 页面返回 A 页面经历的生命周期:B.onPause() -> A.onRestart() -> A.onStart() -> A.onResume() -> B.onStop()。
B是透明页面的情况:
如果 B 是透明的,A 跳转到 B:A.onPause() -> B.onCreate() -> B.onStart() -> B.onResume()。
从 B 返回 A:B.onPause() -> A.onResume() -> B.onPause()。

事件的绑定的代码就是这块

 setContentView(R.layout.activity_main);
起始终止
完整生存期OnCreate()OnDestory()
可见生存期OnCreate()OnStop()
前台生存期OnCreate()OnResume()

(1):当你进行屏幕旋转的时候,Activity的生命周期是这样的

在这里插入图片描述

进行屏幕旋转的时候会让你的Activity重新启动一遍,数据不会保留,我自己仿写的知乎就出现了这个问题,一旦进行旋转,就自己退出app了

而如果你使用了ViewModel的话,它的生命周期就是这样的

在这里插入图片描述

左边的Activity的生命周期变了这么多,但是用了ViewModel后就是右边的效果了

所以就可以明白ViewModel的作用了

1.ViewModel的作用

(1)进行手机的旋转的时候,数据不会丢失.

(2)由第1个功能就可以推出第二个功能了,它可以帮助Activity分担一部分的工作,可以用它来存放与界面有关的数据

2.ViewModel的基本用法

《第一行代码第三版》书中,用ViewModel之前先在app/build.gradle文件中添加依赖

implementation"androidx.lifecycle:lifecycle-extensions:2.2.0"

但是我用的时候发现好像不写这个依赖也可以

要实现的是一个计数器功能,每次按一下按钮,计数器的界面的数字就会+1,我要做的就是当它向左摇动的时候仍然可以记录下原来的数据

先给你看不用ViewModel的效果

进行旋转后

原本的5没了



使用ViewModel

我是给MainActivity创建一个对应的ViewModel

先创建一个类来继承ViewModel

Class ViewModel extends ViewModel{
    int count = 0;
}

MainActivity中添加布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/text_0"/>
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/button_0"/>
</LinearLayout>

然后MainActivity中写

public class MainActivity extends AppCompatActivity {
    ViewModel viewmodel;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button = findViewById(R.id.button);
        TextView textView = findViewById(R.id.text);
        textView.setText(String.valueOf(viewmodel.count));
		viewmodel = new ViewModelProvider(this).get(ViewModel.class);
         button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                viewmodel.score++;
                textView.setText(String.valueOf(viewmodel.score));
            }
             
        });
    
    }
}

这时候我们看一下效果

成功实现效果


这时候我们来分析一下思路,我们是先创建了一个新的类来继承ViewModel,把相应的值都先附上,

之后在MainActivity中开始给在这个类中的对象初始化了

ViewModel viewmodel;
viewmodel = new ViewModelProvider(this).get(ViewModel.class);

先调用ViewModelProvider()get()方法来获取ViewModel的实例

之所以这么写,是因为

ViewModel有独立的生命周期,并且生命周期要长于Activity,如果我们在onCreate()方法中创建ViewModel的实例,那么每次onCreate()方法创建时,ViewModel都会创建一个新的实例,这样当手机屏幕旋转的时候,就无法保留数据了

后面的代码都超级好理解

向ViewModel传递参数:

我们打开我们刚才写的小demo

按按钮,把textview给它加到4

这时候我们把应用从后台关掉,再打开demo

发现textview变成0了,当从后台把demo关掉的时候,它的生命周期就已经结束了,重新打开的时候会进行新的生命周期

有什么办法可以让我们关掉后台的demo后,它依然有原先的数据呢

这时候就得说一下向ViewModel传递参数


  1. 将原本ViewModel类中的无参构造改成有参构造

    public class MainViewModel extends ViewModel {
            int count = 0;
            public MainViewModel(int count) {
                    this.count = count;
            }
    }
    

2.创建一个工厂类,实现ViewModelProvider.Factory接口:

public class MainViewModelFactory implements ViewModelProvider.Factory {
    public MainViewModelFactory(int counter) {
        this.counter = counter;
    }
    public int counter = 0;
    @NonNull
    @Override
    public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
        return (T) new MainViewModel(counter);
    }
}

这里我们重写了create方法,并且工厂类的构造方法中也有ViewModel类中有参构造的参数,主要是因为我们需要借助工厂类来构造ViewModel的具体实例,工厂类会自动在合适的时机创建ViewModel的实例。

之后在MainActivity中修改

public class MainActivity extends AppCompatActivity {
    MainViewModel viewmodel;
    SharedPreferences mPreferences;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
        int savedCounter = mPreferences.getInt("saved_data",0);
        Button button = findViewById(R.id.button);
        TextView textView = findViewById(R.id.text);
        viewmodel = new ViewModelProvider(this,new MainViewModelFactory(savedCounter)).get(MainViewModel.class);
        textView.setText(String.valueOf(viewmodel.count));
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                viewmodel.count++;
                textView.setText(String.valueOf(viewmodel.count));
            }
        });
    }
    @Override
    protected void onPause() {
        super.onPause();
        SharedPreferences.Editor editor = mPreferences.edit();
        editor.putInt("saved_data",viewmodel.count);
        editor.apply();
    }
}

按按钮把它加到7

把后台关掉之后再打开

还是原来的数据


其实这个只有2个地方需要注意

  1. @Override
    protected void onPause() {
        super.onPause();
        SharedPreferences.Editor editor = mPreferences.edit();
        editor.putInt("saved_data",viewmodel.count);
        editor.apply();
    }
    

    这块的时候,当退出该demo时,用SharedPreferences来存储数据,将Viewmodel.count存放在saved_data

    重新启动时

         mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
      		 int savedCounter = mPreferences.getInt("saved_data",0);
    

    把该数据从saved_data中拿出来

      viewmodel = new ViewModelProvider(this,new MainViewModelFactory(savedCounter)).get(MainViewModel.class);
    

    这块和刚才那块比要多一个

    new MainViewModelFactory(savedCounter)
    

    不能忘记

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值