一篇搞定MVVM概念

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/c_he_n/article/details/89191545

MVVM是Google最新推出的架构,目的帮助设计鲁棒性高,易测试,易维护的app。涉及到LiveData,ViewModel和DataBinding。接下来分别介绍这些概念。
在介绍这些概念之前,先把这些添加依赖,配置如下是:

  • 添加依赖(按照注释,添加自己需要的依赖)

dependencies {
    def lifecycle_version = "2.0.0"

    // ViewModel and LiveData
    implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
    // alternatively - just ViewModel
    implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version" // For Kotlin use lifecycle-viewmodel-ktx
    // alternatively - just LiveData
    implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"
    // alternatively - Lifecycles only (no ViewModel or LiveData). Some UI
    //     AndroidX libraries use this lightweight import for Lifecycle
    implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"

    annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" // For Kotlin use kapt instead of annotationProcessor
    // alternately - if using Java8, use the following instead of lifecycle-compiler
    implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"

    // optional - ReactiveStreams support for LiveData
    implementation "androidx.lifecycle:lifecycle-reactivestreams:$lifecycle_version" // For Kotlin use lifecycle-reactivestreams-ktx

    // optional - Test helpers for LiveData
    testImplementation "androidx.arch.core:core-testing:$lifecycle_version"
}
  • 一定不能忘记在gradle.properties添加这个

android.useAndroidX=true
android.enableJetifier=true
  • 要想使用DataBinding库,需要build.gradle 中配置如下:

android {
    ...
    dataBinding {
        enabled = true
    }
}

1.LiveData

在给定的生命周期中,LiveData 是可被观察的数据持有类。(也就是说他是有生命周期的,会随着生命周期而消亡)。

这意味着观察者和生命周期拥有者是关联的,只有在LifecycleOwener在激活状态下,这个观察者才会通知包裹数据的修改。

LifecycleOwner的状态为STARTED或者RESUMED,表示出于激活状态。observer通过函数observeForever(Observer) 添加的都是处于激活状态并且会始终通知修改。对于这些observers,我们需要手动通过removeObserver(Observer)移除。

如果被添加到Lifecycle中的observer自动消亡了,那么对应的Lifecycle也变成DESTROYED状态。

对于activities 和 fragments特别有用,能够安全观察数据,不用担心泄露:当他们消亡时,自动解注册。

此外,LiveData有onActive() 和 onInactive()两个方法获,以便当激活Observers个数在0和1变化时通知。这允许LiveData在没有任何正在观察的观察者时释放任何重型资源。

这个类设计的目的保存ViewModel数据各个字段,但是也能用于你的应用中的不同模块饭共享数据,在解耦的方式下。

函数 用途
onActive() 当激活的观察者从0变成1时调用
onInactive() 当激活的观察者从1变成0时调用
postValue(T value) 在主线程中设置值
setValue(T value) 设置值

如何共享数据呢?

ViewModelProviders.of(activity).get(TestViewModel.class);只要activity共用即可。

  • MediatorLiveData

    考虑下面场景:我们有两个LiveData 实例,名字为 liveData1 和 liveData2,我们像把这个两个合并成一个对象:liveDataMerger。然而liveData1 和 liveData2 就变成MediatorLiveData liveDataMerger 数据源,每次其中的一个onChanged调用,我们在liveDataMerger设置一个新值。
LiveData liveData1 = ...;
LiveData liveData2 = ...;

MediatorLiveData liveDataMerger = new MediatorLiveData<>();
liveDataMerger.addSource(liveData1, value -> liveDataMerger.setValue(value));
liveDataMerger.addSource(liveData2, value -> liveDataMerger.setValue(value));
  • MutableLiveData

    可以认为是简化版的LiveData,只暴露postValue(T value)和setValue(T value)两个函数。

2.ViewModel

ViewModel是个为activity或者fragment准备和管理数据的类,它还处理Activity/Fragment与应用程序其余部分的通信(比如,叫做业务逻辑类)。

ViewModel始终和活动相关(fragment/activity),只要活动还在它就在。

换句话说,这意味着ViewModel是不会被销毁的,如果它的拥有着发生配置变化(例如,屏幕旋转),新的拥有者会重新连接现存的ViewModel.

ViewModel的目的是为了保存activity/fragment必要数据的。在ViewModel中,Activity 或者Fragment能够观察到数据的变化。ViewModels一般通过LiveData或者Android Data Binding 暴露数据的.

ViewModel职责时管理UI数据。它从不访问view层次结构或者把数据保存回activity和fragment。

值得注意的是:ViewModel 对象比view和lifecycleowner活得长,所以ViewModel绝不能引用View和LifecycleOwner相关的东西。这种设计另外一个目的:在不知道view和Lifecycle的情况下,写ViewModel,解耦和。

ViewModel如何使用呢,首先,新建一个ViewModel类,其次,在UserActivity中进行注册,最后,更新UI。VIewModel可以看作业务逻辑处理地方。

public class UserModel extends ViewModel {
     public final LiveData<User> userLiveData = new LiveData<>();

     public UserModel() {
         // trigger user load.
     }

     void doAction() {
         // depending on the action, do necessary business logic calls and update the
         // userLiveData.
     }
 }
 public class UserActivity extends Activity {

     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.user_activity_layout);
         final UserModel viewModel = ViewModelProviders.of(this).get(UserModel.class);
         viewModel.userLiveData.observer(this, new Observer() {
            @Override
             public void onChanged(@Nullable User data) {
                 // update ui.
             }
         });
         findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                  viewModel.doAction();
             }
         });
     }
 }
 
  • AndroidViewModel

    如果ViewModel需要context,就用AndroidViewModel;

3.DataBinding

使用DataBinding的布局文件和普通的布局文件略有不同,通过layout标签。布局文件的结构大致如下

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.firstName}"/>
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.lastName}"/>
   </LinearLayout>
</layout>

layout 是DataBinding格式,没啥好说的。
data标签,是引用数据的,是UI的数据来源。variable标签下name为变量名,在布局文件中使用的名字,而type则是真是数据的来源。
剩下的部分就是布局文件,通过@{}方式进行引用。

假定数据model如下:

public class User {
  public final String firstName;
  public final String lastName;
  public User(String firstName, String lastName) {
      this.firstName = firstName;
      this.lastName = lastName;
  }
}

Binding Adapters

Binding adapters 负责调用合适的框架进行设置值。一个属性设置的例子,像调用setText()方法,显示文本,另外监听事件设置的例子,像调用setOnClickListener()方法。

Data Binding Library 允许你指定方法来设置值,提供你自己的绑定逻辑,并通过使用适配器来指定返回的数据类型。

看到这,不是感觉不知所云,通俗的说,就是对方法或者属性进行绑定自定义逻辑,比如自定义一个属性,并给这个属性绑定自定义逻辑。

Binding Adapters 基本使用:

通过自定义属性并绑定自定义逻辑来说明如何使用的,总共分三步:

1.定义属性:
在values/attrs中配置如下:

<resources>
    <declare-styleable name="View">
        <attr name="onClickCommand" />
    </declare-styleable>
</resources>

其中name设置为View,那么所有的view都具有该属性,设置之后,所有的view都有一个属性:onClickCommand,textview,imageview,都具有该属性。

2.绑定事件逻辑
属性定义好之后,怎么将自定义的属性和事件绑定到一起,这就要用到 @BindingAdapter,我们将属性onClickCommand与单击事件进行绑定,通过下面代码进行绑定。

public class ViewAdapter {
    @BindingAdapter(value = {"onClickCommand"}, requireAll = false)
    public static void onClickCommand(View view, final BindingCommand<String> bindingCommand) {
        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (bindingCommand != null) {
                    bindingCommand.execute("haochen");
                }
                Toast.makeText(v.getContext(), "onclick", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

3.在布局文件中使用


<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:binding="http://schemas.android.com/apk/res-auto">

    <data>
        <variable
            name="viewmodel"
            type="com.iflytek.myapplication.TestViewModel" />
    </data>

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:id="@+id/text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/lottery_animlist"
            android:text="lsfdjlksfjdlksjflkdjlksfjdlkj"
            binding:onClickCommand="@{viewmodel.mStringBindingCommand}" />
    </LinearLayout>
</layout>

上面的TestViewModel 如下:

public class TestViewModel extends ViewModel {
    MutableLiveData<User> mStringMutableLiveData = new MutableLiveData<>();


    public LiveData<User> getData() {
        User mUser = new User("first", "second");
        mStringMutableLiveData.setValue(mUser);
        return mStringMutableLiveData;
    }

    public BindingCommand<String> mStringBindingCommand = new BindingCommand<>(new CommandAction<String>() {
        @Override
        public void call(String s) {
            Log.i("test", s);
        }
    });
}

需要注意的是:

需要在binding下viewmodel,否则事件的回调不执行,原因是因为bindingCommand 没有实例化导致的,添加类似代码即可。

mTestViewModel = ViewModelProviders.of(this).get(TestViewModel.class);
mActivityMainBinding.setViewmodel(mTestViewModel);

参考

Data Binding Library

LiveData

Android MVVM模式快速开发框架

猜你喜欢

转载自blog.csdn.net/c_he_n/article/details/89191545
今日推荐