Android Jetpack(一)ViewModel

        ViewModel是 Android Jetpack 所提供的架构组件,用于分离 UI 逻辑与 UI 数据。ViewModel是用来保存应用UI数据的类,他会在配置变更(即 Configuration Change)之后继续存在。ViewModel的生命周期会比创建它的Activity、Fragment的生命周期更长

                           

        从图中可以看出,在第一次调用Activity对象的onCreate()方法时创建了一个ViewModel。在Activity运行过程中可能会多次调用onCreate()方法(比如当设备屏幕旋转时),但是ViewModel一直存在,直到Activity结束并销毁。这意味着ViewModel不会因为它的创建者的一个配置变化而被销毁,Activity 的新实例将与现有的ViewModel重新连接。

 

1. ViewModel的优势

(1)Activity或Fragment进行销毁和重建的时候,ViewModel的数据不会被回收。对于一些简单的数据,Activity可以使用onSaveInstanceState()方法,并从onCreate的bundle中重新获取,但这一方法仅仅适合一些简单的UI状态,对于列表型这种庞大的数据类型并不适合。当然,这样的优势不仅可以有利于数据的保存,而且可以节约资源。Activity中通常会有有那种在其创建的时候获取数据,然后在其销毁的时候释放数据的方法。如果这些放在Activity中的话,在Activity进行重建的时候,会很浪费资源。但是如果方法在ViewModel中的话,Activity的重建将不会导致数据的重复获取。

(2)ViewModel可以有效的瓜分责任,便于解耦。Android开发时一个常见的坑,是将很多的变量、数据、逻辑一起放在Activity或Fragment中,这样的代码就比较混乱和难以维护。显然,这种开发模式违反了“单一职责”的原则。但如果我们使用ViewModel就可以解决这一问题。ViewModel可以保存Activity中所有的UI数据,而Activity仅负责如何在屏幕上显示该数据和接收用户互动,但是它不会处理这些互动。

        如果应用需要加载和存储数据,可以创建一个Repository存储区类。此外为了保证ViewModel不会因为处理过多逻辑而变得臃肿,可以创建一个Presenter类,来处理UI数据。具体架构如下:

               

2. ViewModel的使用

        首先来看一下官方所推荐的技术开发架构,如图所示:

       

        由图中可以看出,UI,也就是Activity或Fragment,它的职责仅仅是视图的管理(大部分是刷新工作),相当于是一个ViewController的角色。ViewModel类相当于数据集散地,UI要这个数据了,ViewModel就去帮它在仓库找好,无论是数据库还是网络都行。ViewModel拿到数据之后就通知UI,通常情况下这个通知由LiveData来完成。最后通过LiveData去找DataBinding,完成数据的刷新。

        ViewModel的使用可以用作技术架构的层次结构(如:MVVM架构的ViewModel层)去设计,也可以单独使用

        单独使用ViewModel,可以独立出UI数据的存储和管理逻辑。如下图所示:

        不使用ViewModel:

        

        使用ViewModel:

        

        单独使用ViewModel,主要是来发挥其生命周期长,数据不易回收的特性。使用方法如下:

(1)引入lifecycle扩展库(不引入的话,就无法使用ViewModelProviders来构建ViewModel对象)

dependencies {
    ...
    implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
}

(2)创建一个自定义的ViewModel,它继承自ViewModel,用来存储和管理UI数据 

public class MyViewModel extends ViewModel {
    public int number = 0;
}

(3)创建一个自定义ViewModel的实例,并通过它来进行数据的存取

public class MainActivity extends AppCompatActivity {
    MyViewModel myViewModel;
    TextView textView;
    Button button1, button2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
        textView = findViewById(R.id.textView);
        button1 = findViewById(R.id.button1);
        button2 = findViewById(R.id.button2);

        textView.setText(String.valueOf(myViewModel.number));

        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                myViewModel.number++;
                textView.setText(String.valueOf(myViewModel.number));
            }
        });

        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                myViewModel.number += 2;
                textView.setText(String.valueOf(myViewModel.number));
            }
        });
    }
}

        该例子中创建ViewModel实例是通过ViewModelProviders这个类,并且从始至终都没有使用ViewModel的构造方法。需要注意的是,ViewModel默认构造函数是无参的,而通过ViewModelProviders的方法构建ViewModel实例时也只提供一个无参的实现。如果我们希望创建一个带参的ViewModel并实例化,应该通过ViewModelProvider.Factory来构建实例。

        当然,这种情况并不多。ViewModel更多情况下是与其他的Jetpack组件一起使用。例如:

         

        初次之外,ViewModel 还可以与 LiveData 、Data Binding 组合使用来进行响应式UI设计。即:当底层数据被更新时,UI也会相应的自动更新。

        ViewModel + LiveData + Data Binding = 响应式UI

         

注意:

  • 不要将Context传入ViewModel

        由于ViewModel比Activity或Fragment的生命周期都要长,当Activity/Fragment被销毁(例如旋转了屏幕),但是如果ViewModel仍持有Activity/Fragment的引用,就会造成内存泄漏

        此外,如果需要比ViewModel生命周期更长的Application类,则可以使用AndroidViewModel的子类。通过这个子类,可以直接使用Application的引用。

  • ViewModel不应取代OnSaveInstanceState的使用

        两者是相辅相成的。当进程被关闭时,ViewModel将会被销毁,但是OnSaveInstanceState将不受影响;ViewModel可以存储大量数据,OnSaveInstanceState智能存储有限个数据。

ViewModel和OnSaveInstanceState对比 

ViewModel

OnSaveInstanceState

能度过配置变更

能度过配置变更和进程关闭

存储大量数据

存储少量数据

 

必须序列化


 

发布了51 篇原创文章 · 获赞 53 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_34519487/article/details/104086149