精华内容
参与话题
问答
  • ViewModel 使用及原理解析

    万次阅读 2019-03-21 00:00:25
    ViewModel旨在以生命周期意识的方式存储和管理用户界面相关的数据,它可以用来管理Activity和Fragment中的数据.还可以拿来处理Fragment与Fragment之间的通信等等. 当Activity或者Fragment创建了关联的ViewModel,那么...

    *本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布

    本文是基于 androidx.lifecycle:lifecycle-extensions:2.0.0 的源码进行分析

    ViewModel旨在以生命周期意识的方式存储和管理用户界面相关的数据,它可以用来管理Activity和Fragment中的数据.还可以拿来处理Fragment与Fragment之间的通信等等.

    当Activity或者Fragment创建了关联的ViewModel,那么该Activity或Fragment只要处于活动状态,那么该ViewModel就不会被销毁,即使是该Activity屏幕旋转时重建了.所以也可以拿来做数据的暂存.

    ViewModel主要是拿来获取或者保留Activity/Fragment所需要的数据的,开发者可以在Activity/Fragment中观察ViewModel中的数据更改(这里需要配合LiveData食用).

    ps: ViewModel只是用来管理UI的数据的,千万不要让它持有View、Activity或者Fragment的引用(小心内存泄露)。

    本文以由浅入深的方式学习ViewModel

    一、ViewModel的使用

    1. 引入ViewModel

    //引入AndroidX吧,替换掉support包
    implementation 'androidx.appcompat:appcompat:1.0.2'
    
    def lifecycle_version = "2.0.0"
    // ViewModel and LiveData
    implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
    

    2. 简单使用起来

    1. 定义一个User数据类
    class User implements Serializable {
    
        public int age;
        public String name;
    
        public User(int age, String name) {
            this.age = age;
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "age=" + age +
                    ", name='" + name + '\'' +
                    '}';
        }
    }
    
    1. 然后引出我们今天的主角ViewModel
    public class UserModel extends ViewModel {
    
        public final MutableLiveData<User> mUserLiveData = new MutableLiveData<>();
    
        public UserModel() {
            //模拟从网络加载用户信息
            mUserLiveData.postValue(new User(1, "name1"));
        }
        
        //模拟 进行一些数据骚操作
        public void doSomething() {
            User user = mUserLiveData.getValue();
            if (user != null) {
                user.age = 15;
                user.name = "name15";
                mUserLiveData.setValue(user);
            }
        }
    
    }
    
    1. 这时候在Activity中就可以使用ViewModel了. 其实就是一句代码简单实例化,然后就可以使用ViewModel了.
    //这些东西我是引入的androidx下面的
    import androidx.fragment.app.FragmentActivity;
    import androidx.lifecycle.Observer;
    import androidx.lifecycle.ViewModelProviders;
    
    public class MainActivity extends FragmentActivity {
    
        private TextView mContentTv;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            mContentTv = findViewById(R.id.tv_content);
    
            //构建ViewModel实例
            final UserModel userModel = ViewModelProviders.of(this).get(UserModel.class);
    
            //让TextView观察ViewModel中数据的变化,并实时展示
            userModel.mUserLiveData.observe(this, new Observer<User>() {
                @Override
                public void onChanged(User user) {
                    mContentTv.setText(user.toString());
                }
            });
    
            findViewById(R.id.btn_test).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    //点击按钮  更新User数据  观察TextView变化
                    userModel.doSomething();
                }
            });
        }
    }
    

    这个时候,我们点击一下按钮(user中的age变为15),我们可以旋转手机屏幕(这个时候其实Activity是重新创建了,也就是onCreate()方法被再次调用,但是ViewModel其实是没有重新创建的,还是之前那个ViewModel),但是当我们旋转之后,发现TextView上显示的age居然还是15,这就是ViewModel的魔性所在.这个就不得不提ViewModel的生命周期了,它只有在Activity销毁之后,它才会自动销毁(所以别让ViewModel持有Activity引用啊,会内存泄露的). 下面引用一下谷歌官方的图片,将ViewModel的生命周期展示的淋漓尽致.

    3. ViewModel妙用1: Activity与Fragment"通信"

    有了ViewModel,Activity与Fragment可以共享一个ViewModel,因为Fragment是依附在Activity上的,在实例化ViewModel时将该Activity传入ViewModelProviders,它会给你一个该Activity已创建好了的ViewModel,这个Fragment可以方便的访问该ViewModel中的数据.在Activity中修改userModel数据后,该Fragment就能拿到更新后的数据.

    public class MyFragment extends Fragment {
         public void onStart() {
            //这里拿到的ViewModel实例,其实是和Activity中创建的是一个实例
             UserModel userModel = ViewModelProviders.of(getActivity()).get(UserModel.class);
         }
     }
    

    4. ViewModel妙用2: Fragment与Fragment"通信"

    下面我们来看一个例子(Google官方例子)

    public class SharedViewModel extends ViewModel {
        private final MutableLiveData<Item> selected = new MutableLiveData<Item>();
    
        public void select(Item item) {
            selected.setValue(item);
        }
    
        public LiveData<Item> getSelected() {
            return selected;
        }
    }
    
    
    public class MasterFragment extends Fragment {
        private SharedViewModel model;
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
            itemSelector.setOnClickListener(item -> {
                model.select(item);
            });
        }
    }
    
    public class DetailFragment extends Fragment {
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
            model.getSelected().observe(this, { item ->
               // Update the UI.
            });
        }
    }
    
    1. 首先定义一个ViewModel,在里面放点数据
    2. 然后在MasterFragment和DetailFragment都可以拿到该ViewModel,拿到了该ViewModel就可以拿到里面的数据了,相当于间接通过ViewModel通信了. so easy…

    二、ViewModel源码解析

    又到了我们熟悉的源码解析环节

    我们从下面这句代码start.

    final UserModel userModel = ViewModelProviders.of(this).get(UserModel.class);
    

    我们跟着ViewModelProviders.of(this)打开新世界的大门

    1. ViewModelProviders.of(this) 方法

    /**
     * 用于构建一个ViewModelProvider,当Activity是alive时它会保留所有的该Activity对应的ViewModels.
     */
    @MainThread
    public static ViewModelProvider of(@NonNull FragmentActivity activity) {
        return of(activity, null);
    }
    
    @MainThread
    public static ViewModelProvider of(@NonNull FragmentActivity activity,
            @Nullable Factory factory) {
        //检查application是否为空,不为空则接收
        Application application = checkApplication(activity);
        if (factory == null) {
            //构建一个ViewModelProvider.AndroidViewModelFactory
            factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
        }
        return new ViewModelProvider(activity.getViewModelStore(), factory);
    }
    
    

    ViewModelProviders里面的of()函数其实是为了方便我们构建一个ViewModelProvider.而ViewModelProvider,一看名字就知道干啥的了,就是提供ViewModel的.

    Factory是ViewModelProvider的一个内部接口,它的实现类是拿来构建ViewModel实例的.它里面只有一个方法,就是创建一个ViewModel.

    /**
     * Implementations of {@code Factory} interface are responsible to instantiate ViewModels.
     */
    public interface Factory {
        /**
         * Creates a new instance of the given {@code Class}.
         * <p>
         *
         * @param modelClass a {@code Class} whose instance is requested
         * @param <T>        The type parameter for the ViewModel.
         * @return a newly created ViewModel
         */
        @NonNull
        <T extends ViewModel> T create(@NonNull Class<T> modelClass);
    }
    

    Factory有2个实现类:一个是NewInstanceFactory, 一个是AndroidViewModelFactory .

    • NewInstanceFactory源码
    public static class NewInstanceFactory implements Factory {
    
            @SuppressWarnings("ClassNewInstance")
            @NonNull
            @Override
            public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
                //noinspection TryWithIdenticalCatches
                try {
                    return modelClass.newInstance();
                } catch (InstantiationException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                }
            }
        }
    

    NewInstanceFactory专门用来实例化那种构造方法里面没有参数的class,并且ViewModel里面是不带Context的,然后它是通过newInstance()去实例化的.

    • AndroidViewModelFactory 源码
    public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {
    
        private static AndroidViewModelFactory sInstance;
    
        /**
         * Retrieve a singleton instance of AndroidViewModelFactory.
         *
         * @param application an application to pass in {@link AndroidViewModel}
         * @return A valid {@link AndroidViewModelFactory}
         */
        @NonNull
        public static AndroidViewModelFactory getInstance(@NonNull Application application) {
            if (sInstance == null) {
                sInstance = new AndroidViewModelFactory(application);
            }
            return sInstance;
        }
    
        private Application mApplication;
    
        /**
         * Creates a {@code AndroidViewModelFactory}
         *
         * @param application an application to pass in {@link AndroidViewModel}
         */
        public AndroidViewModelFactory(@NonNull Application application) {
            mApplication = application;
        }
    
        @NonNull
        @Override
        public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
            if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
                //noinspection TryWithIdenticalCatches
                try {
                    return modelClass.getConstructor(Application.class).newInstance(mApplication);
                } catch (NoSuchMethodException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                } catch (InstantiationException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                } catch (InvocationTargetException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                }
            }
            return super.create(modelClass);
        }
    }
    

    AndroidViewModelFactory专门用来实例化那种构造方法里面有参数的class,并且ViewModel里面可能是带Context的.

    • 它是通过newInstance(application)去实例化的.如果有带application参数则是这样实例化
    • 如果没有带application参数的话,则还是会走newInstance()方法去构建实例.

    AndroidViewModelFactory通过构造方法给ViewModel带入Application,就可以在ViewModel里面拿到Context,因为Application是APP全局的,那么不存在内存泄露的问题.完美解决了有些ViewModel里面需要Context引用,但是又担心内存泄露的问题.

    下面我们继续ViewModelProviders.of(this)方法继续分析吧,注意最后一句new ViewModelProvider(activity.getViewModelStore(), factory);第一个参数会调用activity的getViewModelStore()方法(这个方法会返回ViewModelStore,这个类是拿来存储ViewModel的,下面会说到),这里的activity是androidx.fragment.app.FragmentActivity,看一下这个getViewModelStore()方法

    /**
     * 获取这个Activity相关联的ViewModelStore
     */
    @NonNull
    @Override
    public ViewModelStore getViewModelStore() {
        if (getApplication() == null) {
            throw new IllegalStateException("Your activity is not yet attached to the "
                    + "Application instance. You can't request ViewModel before onCreate call.");
        }
        if (mViewModelStore == null) {
            //获取最近一次横竖屏切换时保存下来的数据
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                // Restore the ViewModelStore from NonConfigurationInstances
                mViewModelStore = nc.viewModelStore;
            }
            if (mViewModelStore == null) {
                mViewModelStore = new ViewModelStore();
            }
        }
        return mViewModelStore;
    }
    
    //没想到吧,Activity在横竖屏切换时悄悄保存了viewModelStore
    //注意,这是FragmentActivity中的NonConfigurationInstances(其实Activity中还定义了一个NonConfigurationInstances,内容要比这个多一些,但是由于没有关系到它,这里就不提及了)
    static final class NonConfigurationInstances {
        Object custom;
        ViewModelStore viewModelStore;
        FragmentManagerNonConfig fragments;
    }
    
    

    Android横竖屏切换时会触发onSaveInstanceState(),而还原时会调用onRestoreInstanceState(),但是Android的Activity类还有2个方法名为onRetainNonConfigurationInstance()和getLastNonConfigurationInstance()这两个方法。

    来具体看看这2个素未谋面的方法

    /**
     保留所有fragment的状态。你不能自己覆写它!如果要保留自己的状态,请使用onRetainCustomNonConfigurationInstance()
     这个方法在FragmentActivity里面
     */
    @Override
    public final Object onRetainNonConfigurationInstance() {
        Object custom = onRetainCustomNonConfigurationInstance();
    
        FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();
    
        if (fragments == null && mViewModelStore == null && custom == null) {
            return null;
        }
    
        NonConfigurationInstances nci = new NonConfigurationInstances();
        nci.custom = custom;
        nci.viewModelStore = mViewModelStore;
        nci.fragments = fragments;
        return nci;
    }
    
    
    //这个方法在Activity里面,而mLastNonConfigurationInstances.activity实际就是就是上面方法中年的nci
    public Object getLastNonConfigurationInstance() {
        return mLastNonConfigurationInstances != null
                ? mLastNonConfigurationInstances.activity : null;
    }
    
    

    我们来看看getLastNonConfigurationInstance()的调用时机,

    protected void onCreate(@Nullable Bundle savedInstanceState) {
        ......
        super.onCreate(savedInstanceState);
    
        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        if (nc != null && nc.viewModelStore != null && mViewModelStore == null) {
            mViewModelStore = nc.viewModelStore;
        }
        ......
    }
    

    没想到吧,Activity在横竖屏切换时悄悄保存了viewModelStore,放到了NonConfigurationInstances实例里面,横竖屏切换时保存了又恢复了回来,相当于ViewModel实例就还在啊,也就避免了横竖屏切换时的数据丢失.

    2. viewModelProvider.get(UserModel.class)

    下面我们来到那句构建ViewModel代码的后半段,它是ViewModelProvider的get()方法,看看实现,其实很简单

    public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
        String canonicalName = modelClass.getCanonicalName();
        if (canonicalName == null) {
            throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
        }
        return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
    }
    
    public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
        //先取缓存  有缓存则用缓存
        ViewModel viewModel = mViewModelStore.get(key);
    
        if (modelClass.isInstance(viewModel)) {
            //noinspection unchecked
            return (T) viewModel;
        } else {
            //noinspection StatementWithEmptyBody
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }
        
        //无缓存  则重新通过mFactory构建
        viewModel = mFactory.create(modelClass);
        //缓存起来
        mViewModelStore.put(key, viewModel);
        //noinspection unchecked
        return (T) viewModel;
    }
    
    

    大体思路是利用一个key来缓存ViewModel,有缓存则用缓存的,没有则重新构建.构建时使用的factory是上面of()方法的那个factory.

    3. ViewModelStore

    上面多个地方用到了ViewModelStore,它其实就是一个普普通通的保存ViewModel的类.

    public class ViewModelStore {
    
        private final HashMap<String, ViewModel> mMap = new HashMap<>();
    
        final void put(String key, ViewModel viewModel) {
            ViewModel oldViewModel = mMap.put(key, viewModel);
            if (oldViewModel != null) {
                oldViewModel.onCleared();
            }
        }
    
        final ViewModel get(String key) {
            return mMap.get(key);
        }
    
        /**
         *  Clears internal storage and notifies ViewModels that they are no longer used.
         */
        public final void clear() {
            for (ViewModel vm : mMap.values()) {
                vm.onCleared();
            }
            mMap.clear();
        }
    }
    
    

    ViewModelStore有一个HashMap专门用于存储,普通吧.

    下面看看何时调用的clear()

    4. ViewModel.onCleared() 资源回收

    既然ViewModel是生命周期感知的,那么何时应该清理ViewModel呢?

    我们来到FragmentActivity的onDestroy()方法,发现它是在这里清理的.

    /**
     * Destroy all fragments.
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
    
        if (mViewModelStore != null && !isChangingConfigurations()) {
            mViewModelStore.clear();
        }
    
        mFragments.dispatchDestroy();
    }
    

    5. 再看 ViewModel

    很多朋友可能就要问了,ViewModel到底是什么?

    public abstract class ViewModel {
        /**
         * 这个方法会在ViewModel即将被销毁时调用,可以在这里清理垃圾
         */
        @SuppressWarnings("WeakerAccess")
        protected void onCleared() {
        }
    }
    

    其实很简单,就一个抽象类,里面就一个空方法??? 我擦,搞了半天,原来ViewModel不是主角…

    6. AndroidViewModel

    ViewModel有一个子类,是AndroidViewModel.它里面有一个Application的属性,仅此而已,为了方便在ViewModel里面使用Context.

    public class AndroidViewModel extends ViewModel {
        @SuppressLint("StaticFieldLeak")
        private Application mApplication;
    
        public AndroidViewModel(@NonNull Application application) {
            mApplication = application;
        }
    
        /**
         * Return the application.
         */
        @SuppressWarnings("TypeParameterUnusedInFormals")
        @NonNull
        public <T extends Application> T getApplication() {
            //noinspection unchecked
            return (T) mApplication;
        }
    }
    

    三、小结

    ViewModel 的源码其实不多,理解起来比较容易,主要是官方FragmentActivity提供了技术实现,onRetainNonConfigurationInstance()保存状态,getLastNonConfigurationInstance()恢复。

    原来Activity还有这么2个玩意儿,之前我还只是知道onSaveInstanceState()和onRestoreInstanceState(),涨姿势了。

    展开全文
  • 文章目录DataBinding库DataBinding的配置布局和绑定表达式双向数据绑定绑定数据事件处理ViewModel导入ViewModelViewModel的创建和使用LiveData概述LiveData的创建观察 LiveData 对象更新 LiveData 对象参考资料 ...

    DataBinding库

    数据绑定库是一种支持库,借助该库,可以使用声明性格式(而非程序化地)将布局中的界面组件绑定到应用中的数据源。

    DataBinding的配置

    在Module的build.gradle android模块中添加如下配置

    android {
     dataBinding {
        enabled = true
     }
    }
    

    同步时出现Cause: unable to find valid certification path to requested target错误的解决办法:在项目的build.gradle的buildscript的repositories下加入:

    maven { url "http://jcenter.bintray.com"}
    

    再在allprojects的repositories下加入

    mavenCentral()
    jcenter{ url "http://jcenter.bintray.com/" }
    maven { url "https://jitpack.io" }
    

    布局和绑定表达式

    <layout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:app="http://schemas.android.com/apk/res-auto">	//根节点变为layout,并且它不能指定长和宽等属性,只能声明命名空间,否则在构建时会报错
        <data>			//data节点作用是连接 View 和 Modle 的桥梁
            <variable
                name="viewmodel"
                type="com.myapp.data.ViewModel" />	//bean实体类
        </data>
            
        <LinearLayout	 //UI布局的根布局
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{viewmodel.name}" />
    
            <!--注意:这里age是int类型,必须转化为String,否则会运行时异常-->
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{String.valueOf(viewmodel.age)}" />
        </LinearLayout>
    </layout>
    

    可以在表达式语言中使用字符串连接运算符(即在@{…}中使用),逻辑和算术运算符等常用的运算符和关键字

    双向数据绑定

    上面的绑定为单向绑定(当ViewModel中的数据发生改变时,View相应的自动改变),而双向数据绑定多的一向是在用户行为对View发生影响时,ViewModel接收到View的改变并对其作出反应。

    示例:

        <CheckBox
            android:id="@+id/rememberMeCheckBox"
            android:checked="@={viewmodel.rememberMe}"
        />
    

    **注意:**双向数据绑定(@={})对于单向(@{})的区别是多了一个 =

    为了应对数据的更改,可以将布局变量设置为 Observable(通常为 BaseObservable) 的实现,并使用 @Bindable 注释get方法,如以下代码段所示:

        public class LoginViewModel extends BaseObservable {
            // private Model data = ...
            @Bindable
            public Boolean getRememberMe() {	//VM->View VM中数据的改变引起View的改变
                return data.rememberMe;
            }
            public void setRememberMe(Boolean value) {	//View->VM View的改变引起VM中数据的改变
                // Avoids infinite loops.
                if (data.rememberMe != value) {
                    data.rememberMe = value;
                    // React to the change.
                    saveData();
                    // Notify observers of a new value.
                    notifyPropertyChanged(BR.remember_me);
                }
            }
        }
    

    绑定数据

    系统会为每个布局文件生成一个绑定类。默认情况下,类名称基于布局文件的名称,它会转换为 Pascal 大小写形式并在末尾添加 Binding 后缀。以上布局文件名为 activity_main.xml,因此生成的对应类为 ActivityMainBinding。此类包含从布局属性(例如,user 变量)到布局视图的所有绑定,并且知道如何为绑定表达式指定值。建议的绑定创建方法是在扩充布局时创建,如以下示例所示:

        @Override
        protected void onCreate(Bundle savedInstanceState) {
           super.onCreate(savedInstanceState);
           ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
           User user = new User("Test", "User");
           binding.setUser(user);
        }
    

    事件处理

    通过数据绑定,可以编写从视图分派的表达式处理事件(例如,onClick() 方法)。事件特性名称由监听器方法的名称确定,但有一些例外情况。例如,View.OnClickListener 有一个 onClick() 方法,所以该事件的特性为 android:onClick

    可以使用以下机制处理事件:

    • 方法引用:在表达式中,您可以引用符合监听器方法名称的方法(即和它名称相同的方法)。当表达式求值结果为方法引用时,数据绑定会将方法引用和所有者对象封装到监听器中,并在目标视图上设置该监听器。如果表达式的求值结果为 ,则数据绑定不会创建监听器,而是设置 监听器。

      例如在上面布局和绑定表达式的代码中的TextView中加入 android:onClick="@{() -> viewmodel.onLike()}" 属性

    • 监听器绑定:这些是在事件发生时进行求值的 lambda 表达式。数据绑定始终会创建一个要在视图上设置的监听器。事件被分派后,监听器会对 lambda 表达式进行求值。使用类似与方法引用,也可在 lambda 表达式中使用多个参数。

    ViewModel

    ViewModel是一个抽象类,旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel类让数据可在发生屏幕旋转等配置更改后继续存在。在使用前需要声明相应的依赖。架构组件为界面控制器提供了ViewModel辅助程序类,该类负责为界面准备数据。 在配置更改期间会自动保留ViewModel对象,以便它们存储的数据立即可供下一个 Activity 或 Fragment 实例使用。

    导入ViewModel

    在Model - build.gradle添加依赖

    implementation "android.arch.lifecycle:viewmodel:1.1.1"
    

    ViewModel的创建和使用

        public class MyViewModel extends ViewModel {	//继承ViewModel抽象类
            private MutableLiveData<List<User>> users;
            public LiveData<List<User>> getUsers() {
                if (users == null) {
                    users = new MutableLiveData<List<User>>();
                    loadUsers();
                }
                return users;
            }
            private void loadUsers() {
                // Do an asynchronous operation to fetch users.	异步操作获取users
            }
        }
    

    创建ViewModel对象后,就可以在活动中使用了

        public class MyActivity extends AppCompatActivity {
            public void onCreate(Bundle savedInstanceState) {
                //当系统首次调用活动的onCreate方法时创建一个ViewModel对象
                //重新创建了该 Activity,它接收的 MyViewModel 实例与第一个 Activity 创建的实例相同
                MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);	//通过这种方法获取ViewModel对象
                model.getUsers().observe(this, users -> {
                    //更新UI
                });
            }
        }
    

    LiveData

    概述

    LiveData是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。

    LiveData的创建

    LiveData 是一种可用于任何数据的封装容器,其中包括可实现 Collections 的对象,如 List。LiveData对象通常存储在ViewModel对象中,并可通过 getter 方法进行访问,如以下示例中所示:

        public class NameViewModel extends ViewModel {//LiveData对象存储在ViewModel类中
        // Create a LiveData with a String
        private MutableLiveData<String> currentName;	//因为LiveData是一个抽象类,所以我们使用它的子类MutableLiveData
            public MutableLiveData<String> getCurrentName() {
                if (currentName == null) {
                    currentName = new MutableLiveData<String>();
                }
                return currentName;
            }
        // Rest of the ViewModel...
        }
    

    注意:确保将用于更新界面的LiveData对象存储在ViewModel对象中,而不是将其存储在 Activity 或 Fragment 中,原因如下:

    • 避免 Activity 和 Fragment 过于庞大。现在,这些界面控制器负责显示数据,但不负责存储数据状态。
    • 将 LiveData实例与特定的 Activity 或 Fragment 实例分离开,并使 对象在配置更改后继续存在

    观察 LiveData 对象

    应在活动的onCreate方法中观察LiveData,以确保 Activity 或 Fragment 变为活跃状态后具有可以立即显示的数据

        public class NameActivity extends AppCompatActivity {
            private NameViewModel model;
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                // Other code to setup the activity...
                //获取ViewModel对象
                model = ViewModelProviders.of(this).get(NameViewModel.class);
                //下面创建更新UI的观察者对象
                final Observer<String> nameObserver = new Observer<String>() {
                    @Override
                    public void onChanged(@Nullable final String newName) {
                        // Update the UI, in this case, a TextView.
                        nameTextView.setText(newName);
                    }
                };
                //观察LiveData,传入作为LifecycleOwner的活动和observer.
                model.getCurrentName().observe(this, nameObserver);
            }
        }
    

    更新 LiveData 对象

    LiveData 没有公开可用的方法来更新存储的数据。MutableLiveData类将公开 setValue(T) 和 postValue(T) 方法,如果需要修改存储在LiveData对象中的值,则必须使用这些方法。通常情况下会在 ViewModel中使用 MutableLiveData,然后 ViewModel 只会向观察者公开不可变的 LiveData对象。

    注意:必须调用 setValue(T) 方法以从主线程更新 LiveData 对象。如果在 worker 线程中执行代码,则可以改用 postValue(T) 方法来更新 LiveData 对象,即两个方法都可以用。

        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                String anotherName = "John Doe";
                model.getCurrentName().setValue(anotherName);
            }
        });
    

    在本例中调用 setValue(T) 导致观察者使用值 John Doe 调用其 onChanged() 方法。在所有情况下,调用 setValue() 或 postValue() 都会触发观察者并更新界面。

    参考资料

    Android JetPack

    展开全文
  • ViewModel+LiveData+DataBinding使用

    千次阅读 2019-07-30 15:30:36
    ViewModel+LiveData+DataBinding使用 Android DataBinding 使用博客说明 Android DataBinding 使用测试代码 简书:ViewModel、LiveData 使用 CSDN:ViewModel、LiveData 使用 在上面的内容中,知道了 ...

    ViewModel+LiveData+DataBinding使用

    Android DataBinding 使用博客说明

    Android DataBinding 使用测试代码

    简书:ViewModel、LiveData 使用

    CSDN:ViewModel、LiveData 使用

    在上面的内容中,知道了 DataBinding 的使用,以及 ViewModel和LiveData的使用,在LiveData的使用时,我们数据发生改变,如果需要更新UI,还需给数据增加一个监听:

    	// 增加改变监听
    	userViewModel.userLiveData.observe(this, Observer {user ->
    	    text_view.text = user.toString()
    	})
    

    这当然不是我们希望看到的,我们希望的是数据发生改变之后UI能够自动更新,而不是手动设置值更新UI界面。刚好,DataBinding 就能够实现这个功能,所以我们把 LiveData 和 DataBinding 一起使用,那么代码就更加的简洁了。


    以下的内容使用到了 DataBinding 的相关知识,同时使用到了 ViewModel 和 LiveData,如果对着几个点不了解的,可以先通过上面的连接对相关的知识点进行了解。

    ViewModel+LiveData+DataBinding使用

    **首先需要搭建 ViewModel+LiveData+DataBinding 环境:开启 DataBinding 支持,引入 ViewModel 和 LiveData 的依赖。**具体怎样开启可以通过上面链接查看。

    1. 建立数据类

       data class User(var name: String = "", var age: Int = 0, var address: String)
      
    2. 建立 ViewModel 类 UserViewModel

       class UserViewModel : ViewModel() {
           var userData: MutableLiveData<User> = MutableLiveData()
       
           init {
               userData.value = User("张三", 24, "杭州")
       
       		// 延迟3秒后修改数据,UI自动更新
               Thread{
                   SystemClock.sleep(3000)
                   userData.value!!.name  = "李四"
                   userData.postValue(userData.value)
               }.start()
           }
       
           override fun onCleared() {
               Log.i("UserViewModel","onCleared:ViewModel 即将销毁")
           }
       }
      
    3. 布局文件,布局文件中引入 UserViewModel

       <?xml version="1.0" encoding="utf-8"?>
       <layout xmlns:android="http://schemas.android.com/apk/res/android"
               xmlns:tools="http://schemas.android.com/tools"
               xmlns:app="http://schemas.android.com/apk/res-auto">
       
           <data>
               <variable name="userViewModel"
                         type="com.renj.mvvmtest.viewmodel.UserViewModel"/>
           </data>
       
       
           <android.support.constraint.ConstraintLayout
                   android:layout_width="match_parent"
                   android:layout_height="match_parent"
                   tools:context=".MainActivity">
       
               <TextView
                       android:layout_width="wrap_content"
                       android:layout_height="wrap_content"
                       android:text="@{userViewModel.userData.name}"
                       app:layout_constraintBottom_toBottomOf="parent"
                       app:layout_constraintLeft_toLeftOf="parent"
                       app:layout_constraintRight_toRightOf="parent"
                       app:layout_constraintTop_toTopOf="parent"/>
       
           </android.support.constraint.ConstraintLayout>
       
       </layout>
      
      • <data><data/>标签内容表示引入UserViewModel
      • android:text="@{userViewModel.userData.name}"UserViewModel 的变量 userData 的值设置给 TextView控件
    4. Activity:Activity的代码非常简单了

       class MainActivity : AppCompatActivity() {
      
           override fun onCreate(savedInstanceState: Bundle?) {
               super.onCreate(savedInstanceState)
               var mainBinding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
       
               mainBinding.userViewModel = ViewModelProviders.of(this).get(UserViewModel::class.java)
               mainBinding.lifecycleOwner = this
       
           }
       }
      
      • mainBinding.userViewModel = ViewModelProviders.of(this).get(UserViewModel::class.java)给布局文件设置 UserViewModel
      • mainBinding.lifecycleOwner = this表示调用DataBinding#setLifecycleOwner(@Nullable LifecycleOwner lifecycleOwner) 方法,调用了这个方法,我们使用的LiveData就能够感应到相关组件的生命周期,在对应的时候更新UI。
    展开全文
  • 之前几小章我们讲了DataBinding,其中将一个普通类化身为ViewModel,但是以我的观点来看,他仅仅只是一个普通类,一个将各种可观察属性封装起来的普通类,而这个普通类我们还在里面定义了各种相应按钮点击事件等方法...

    之前几小章我们讲了DataBinding,其中将一个普通类化身为ViewModel,但是以我的观点来看,他仅仅只是一个普通类,一个将各种可观察属性封装起来的普通类,而这个普通类我们还在里面定义了各种相应按钮点击事件等方法,其实这些都违背了官方的建议的,我只是想让大家知道可以这样做而已。所以我们要介绍Android Jetpack中正统的ViewModel类,以及一些它的最佳实践指南。

    本篇文章代码地址

    官方中文教学视频地址

    Android MVVM探索系列

    Android MVVM探索(一) - DataBiding初解

    Android MVVM探索(二) - DataBiding常用注解

    Android MVVM探索(三) - ViewModel,DataBinding,LiveData混合三打

    Android Jetpack是谷歌为了帮助开发者们更快更高效地开发安卓应用而推出来的一套组件。Android Jetpack包含了开发库,工具以及最佳实践指南。而我们今天要讲的ViewModel类是属于Android Jetpack库中的lifecycle库。说到这,顺带解释以下。lifecycle,中文意思为生命周期。所以这个库的存在就跟它的中文含义一样,它可以有效避免内存泄漏和解决Android常见的生命周期难题。(如果各位看官不知道内存泄露的可以去好好补补课)lifecycle最近发布了2.0版本,在这个版本中,可以结合DataBinding进行使用,那可以说是方便太多了。

    一,ViewModel的定义。

    来自官方的解释:ViewModel类是用来保存UI数据的类,它会在配置变更(即 Configuration Change,例如手机屏幕的旋转)之后继续存在。

    二,它的一些特点。

    我们都知道,当手机屏幕发生旋转的时候,Activity会被重新创建,也就是说生命周期又将从onCreate开始,如果你此时不及时保存,那么一些UI数据将会丢失,这样肯定是会出问题的。但是,ViewModel并不会受此影响,即便手机屏幕发生旋转,ViewModel依然存在,这样的话Activity的UI数据便可以保存下来。

    三,最佳实践(官方推荐做法)。

    1. 所有Activity的UI相关数据应该保存在ViewModel中,而不是保存在Activity中。这样做的好处是,在配置变更的时候,你应用的UI数据仍然存在。即使ViewModel这么强大,但它也不应该不承担过多责任,当有UI数据处理等相关事件建议创建Presenter类,或者创建一个更成熟的架构。

    2. Activity负责展示UI数据,并接收互动(一般来说是与用户的互动)。但是Activity不应当处理这些互动。

    3. 在应用需要加载数据或者保存数据的时候,建议创建一个Repository的存储区类,里面放置存储与加载应用数据的API。

    4. ViewModel不应持有Context,就像之前说的:

      它会在配置变更(即 Configuration Change,例如手机屏幕的旋转)之后继续存在。

      所以,ViewModel生命周期远比Activity,Fragment等生命周期更长,具体如下图所示。如果你这样做了,加入在屏幕旋转情况下,原Activity将会销毁,新的Activity将会被创建。而ViewModel会一直持有原Activity,这样便会造成内存泄漏。如果你的ViewModel确实需要Context,那么你的ViewModel可以继承AndroidViewModel,这样你的ViewModel中会有Application的引用。

    5. ViewModel不应当取代onSaveInstanceState方法。尽管ViewModel很出色了,但是它和onSaveInstanceState依然是相辅相成的作用。因为,当进程被关闭时,ViewModel将会被销毁,但是onSaveInstanceState不会受到影响。(个人猜想:比如在后台内存紧张情况下,你的应用处于后台被系统释放了,ViewModel会被销毁,但是你通过onSaveInstanceState存储下来的数据在你的应用重新回到前台时仍然可以被恢复)

    6. ViewModel与Activity生命周期对比图:

    四,ViewModel的用法

    1. 引入lifecycle库:

      implementation "android.arch.lifecycle:extensions:1.1.0"
      annotationProcessor "android.arch.lifecycle:compiler:1.1.0"
      复制代码
    2. 首先创建出我们的ViewModel类。我们需要新建一个普通类,(虽然类名是随意的,但是作为一名合格的程序员,我们取得每一个名字要具有规范性,要让代码阅读者一看名字就知道这个类或者这个变量是干嘛的)让它继承ViewModel类,并且在其中存放UI相关数据:

      // 假设我们要存放的UI数据就是User对象
      // 先新建一个实体对象
      data class User(val name: String, val age: Int, val sex: Int)
      
      // 新建ViewModel类
      // 新建ViewModel类
      class UserViewModel : ViewModel() {
          val user = User("张三", 21, 1)
      }
      复制代码
    3. 新建Activity,并且加入实例化ViewModel的代码。这里我们实例化ViewModel不再是new一下:

      class ViewModelActivity : AppCompatActivity() {
          override fun onCreate(savedInstanceState: Bundle?) {
              super.onCreate(savedInstanceState)
              setContentView(R.layout.activity_view_model)
              val userViewModel = ViewModelProviders.of(this).get(UserViewModel::class.java)
          }
      }
      复制代码

      至此,我们一个ViewModel就创建好了。

    4. 感觉单单一个ViewModel的存在没有很大的价值,但是如果搭配上LiveData和DataBinding你就能体会到什么是飞一样的感觉。用上这些,你就能够创建反应式界面(最基本的只要LiveData和ViewModel就可以创建反应式界面。或者单单DataBinding就可以完成,但是不具备生命周期感知能力,我们需要手动处理生命周期问题)。也就是说,当你底层数据发生变动时(这里暂时只是ViewModel中数据发生变动),UI会自动刷新。

    5. ViewModel只提供一个默认的无参构造函数,如果你需要一个有参构造函数,那么就需要使用ViewModelFactory这个类,具体使用方法如下所示(摘自官方sunflower Demo代码):

      // 新建一个Factory类,用来提供带有有参构造函数的ViewModel实例,必须继承ViewModelProvider.NewInstanceFactory,然后重写create方法
      class MessageViewModelFactory(private val message: Message) : ViewModelProvider.NewInstanceFactory() {
          @Suppress("UNCHECKED_CAST")
          override fun <T : ViewModel?> create(modelClass: Class<T>): T {
              return MessageViewModel(message) as T
          }
      }
      
      // 新建一个带有有参构造函数的ViewModel
      class MessageViewModel(val message: Message) : ViewModel()
      
      // Activity中初始化ViewModel的代码也要进行改动
      // 创建Factory对象
      val factory = MessageViewModelFactory(Message("我是通过有参构造函数直接初始化的信息内容",
              "我是通过有参构造函数直接构造出来的信息发送人"))
      // 通过Factory对象初始化带参构造函数的ViewModel
      val messageViewModel = ViewModelProviders.of(this, factory).get(MessageViewModel::class.java)
      // 将MessageViewModel实例赋值给xml中的msg
      binding.msg = messageViewModel
      复制代码

      这样便可以完成带有有参构造函数的ViewModel的初始化。

    五,搭配上LiveData

    1. LiveData简介:LiveData是一种具有生命周期感知能力的可观察数据持有类。它同属于Android Jectpack中的lifecycle库。LiveData对象通常保存在我们上面讲的ViewModel中。

    2. 结合ViewModel的使用。我们说过,使用LiveData加ViewModel可以创建一个反应式界面,那么我们应该怎么做呢?我们需要改写上面的UserViewModel,让其中的user具有可观察性:

      class UserViewModel : ViewModel() {
          val user = MutableLiveData<User>()
      }
      复制代码
    3. 接着,我们在ViewModelActivity中监听UserViewModel中的user属性的变化,并且在它变化后进行相应的操作:

      <!-- 为了演示效果,我们在布局文件activity_view_model中添加了一些控件 -->
      <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"
          android:orientation="vertical"
          tools:context=".viewmodel.ViewModelActivity">
      
          <TextView
              android:id="@+id/tv_vm"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content" />
      
          <Button
              android:id="@+id/bt_vm"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="设置姓名"/>
      </LinearLayout>
      
      // 在Activity中设置数据变化监听,并且进行相应处理
      class ViewModelActivity : AppCompatActivity() {
          private lateinit var tv: TextView
          private lateinit var bt: Button
      
          override fun onCreate(savedInstanceState: Bundle?) {
              super.onCreate(savedInstanceState)
              setContentView(R.layout.activity_view_model)
              tv = findViewById(R.id.tv_vm)
              bt = findViewById(R.id.bt_vm)
              val userViewModel = ViewModelProviders.of(this).get(UserViewModel::class.java)
              // 监听ViewModel中user的变化,当它变化时,将TextView重新设置文字
              userViewModel.user.observe(this, Observer {
                  tv.text = it?.name
              })
              // 为按钮设置点击事件,点击后设置user的值
              bt.setOnClickListener{
                  val user = User("张三", 21, 1)
                  userViewModel.user.value = user
                  // Java代码
                  // userViewModel.user.setValue(user)
              }
          }
      }
      复制代码

      写完以上代码,当我们点击按钮的时候TextView就会显示“张三”二字了。

    4. 上面代码中除了setValue,还有一个方法叫postValue。区别在于setValue只可以在主线程执行(即UI线程),postValue只可以在后台线程运行。

    5. LiveData能够感知生命周期的好处:1,当Activity不在屏幕上时(不可见),LiveData不会出发没必要的界面更新;2,当Activity被销毁时,LiveData将自动清空与Observer的连接;

    六,搭配上DataBinding

    我们看到,上面的代码还是有些繁琐,我们还要自己写代码监听数据变化,并且自己手动去更新UI。之前我们DataBinding可不是这样的。是的,我们还可以更简单。别忘了,lifecycle2.0是支持了DataBinding数据绑定的。我们可以通过以下步骤来结合DataBinding使用:

    1. 像DataBinding中那样写布局,所以将activity_view_model改成如下所示:

      <layout xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools">
          <data>
              <variable
                  name="viewModel"
                  type="top.cyixlq.test.viewmodel.UserViewModel"/>
          </data>
      
          <LinearLayout
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical"
              tools:context=".viewmodel.ViewModelActivity">
      
              <TextView
                  android:id="@+id/tv_vm"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:text="@{viewModel.user.name}"/>
      
              <TextView
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:text="@{String.valueOf(viewModel.user.age)}"/>
      
              <Button
                  android:id="@+id/bt_vm"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:text="设置姓名"/>
      
          </LinearLayout>
      </layout>
      复制代码
    2. 注释掉ViewModelActivity中的之前的代码,并重新写,所以有用的代码就是下面这样:

      class ViewModelActivity : AppCompatActivity() {
          override fun onCreate(savedInstanceState: Bundle?) {
              super.onCreate(savedInstanceState)
              setContentView(R.layout.activity_view_model)
              val userViewModel = ViewModelProviders.of(this).get(UserViewModel::class.java)
              val binding = DataBindingUtil.setContentView<ActivityViewModelBinding>(this, R.layout.activity_view_model)
              // Java代码
              // ActivityViewModelBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_view_model)
      
              binding.viewModel = userViewModel
              // java代码
              // binding.setViewModel(userViewModel)
      
              // 让xml内绑定的LiveData和Observer建立连接,也正是因为这段代码,让LiveData能感知Activity的生命周期
              binding.setLifecycleOwner(this)
          }
      }
      复制代码
    3. 为了验证效果,我们设置一下按钮的的点击事件,当按钮点击后TextView显示姓名年龄的信息:

      bt_vm.setOnClickListener { 
          userViewModel.user.value = User("李四", 22, 1)
      }
      // java代码
      // findViewById(R.id.bt_vm).setOnClickListener(new View.OnClickListener() {
      //     userViewModel.user.setValue(new User("李四", 22, 1))
      // })
      复制代码

    经过以上的步骤就可以结合DataBinding使用了

    转载于:https://juejin.im/post/5bd6acd1e51d457a976637c3

    展开全文
  • ViewModel可以将数据模块进行单独的管理,可以使我的控制器更加的简单,只需要专注于控制界面的逻辑和用户的操作。另外当我们的Activity被Destroy或者重新Create时数据不会丢失。(例如切换系统语言、屏幕旋转)其...
  • 简介: 使用 JetPack 中的 AndroidX + ViewModel + LiveData + DataBinding 组件,同时使用 ViewPager2 + RxJava2 + Retrofit2 + Glide 等主流框架进行搭建 更多:作者提 Bug 标签: 目录 介绍 De...
  • MVVM 架构,ViewModel和LiveData(一)

    万次阅读 2018-05-19 22:33:09
    MVVM 架构,ViewModel和LiveData(一) 标签(空格分隔): 翻译计划 Android开发 原文链接 MVVM architecture, ViewModel and LiveData (Part 1) 正文 在Google I/O之间,Google推出了包含LiveData和...
  • / 今日科技快讯 /近日,谷歌宣布2020年投资计划,承诺将在加州、科罗拉多州、乔治亚州、马萨诸塞州、内布拉斯加州、纽约州、俄亥俄州、俄克拉荷马州、宾夕法尼亚州、德克萨斯州和华盛...
  • Android架构组件——ViewModel

    万次阅读 多人点赞 2018-03-02 20:24:36
    正像它字面意思一样,它是负责准备和管理和UI组件(Fragment/Activity)相关的数据类,也就是说ViewModel是用来管理UI相关的数据的,同时ViewModel还可以用来负责UI组件间的通信。 之前存在的问题 ViewModel用来...
  • ViewModel

    千次阅读 2017-12-25 12:33:22
    ViewModel 负责根据生命周期来存储和管理 UI 相关(Activity 或 Fragment)的数据。当配置发生变化时,如:屏幕方向旋转,它可以保证数据不被销毁。
  • Model-View-ViewModel for iOS [译]

    千次阅读 2015-06-26 10:01:29
    如果你已经开发一段时间的...在本文,我将重温一下MVC是什么,详述它的缺点,并且告诉你一个新的方式来架构你的app:Model-View-ViewModel。拿出你的流行语bingo card(宾果卡,一种游戏卡片-译者注),因为我们即将进行
  • MVVM(Model-View-ViewModel)实例讲解

    千次阅读 2011-08-17 14:42:05
    MVVM模式大家应该不陌生吧,陌生的快来看看,可是WPF/Silverlight开发中,必备的设计模式。 MVVM模式解决了,我们在开发WPF/Silverlight应用程序过程中产生的业务层、表示层比较混乱问题,使表示层和业务层完全分离...
  • WPF Apps With The Model-View-ViewModel Design Pattern Josh Smith著 siyu77译 原文链接http://msdn.microsoft.com/zh-cn/magazine/dd419663.aspx#id0090120   本文讨论:  设计模式和WPF MVP模式...
  • 这篇文章主要介绍了MVVM模式中ViewModelViewModel有什么区别?本文分别解释了它们的功能和作用,然后总结了它之间的区别,需要的朋友可以参考下  Model:很简单,就是业务逻辑相关的数据对象,通常从数据库映射...
  • Asp.net mvc ViewModel

    千次阅读 2016-04-13 11:28:50
    MVC规定,View即V是纯UI,不允许包含任何的逻辑层,所以在上节实例中已经违反了MVC基本准则(上节实例也是初学者应该遇到的内容),在上例中违反MVC的体系架构规则如下: 1、显示全名——逻辑层 2、使用红色标识年龄...
  • MVC的概念已经逐渐被大家所熟悉——ModelView,Controllor。... 什么是MVVM呢,就是ModelViewViewModelModel就是对数据的抽象,数据的封装。比如,Person。View就是UI表现层,提供与终端用
  • 为什么80%的码农都做不了架构师?>>> ...
  • 简单的说,ViewModel就是ViewModel的连接器,ViewModel通过ViewModel实现双向绑定。 Model:很简单,就是业务逻辑相关的数据对象,通常从数据库映射而来,我们可以说是与数据库对应的modelView:也很简单,...
  • ViewModel:用户视图模型,与View层用户操作直接关联。本文以软件开发平台中客户(Customer)为例进行说明。 一个简单的Model Web开发框架中MVC架构,本来就只有一个Model的,这个Model在领域驱动开发中主要担任领域...
  • Android架构组件(三)——ViewModel

    万次阅读 多人点赞 2017-12-27 11:44:31
    Android架构组件(三)——ViewModel 上一篇文章讲到了Android架构组件之... ViewModel,从字面上理解的话,我们也能想到它肯定是跟视图(View)以及数据(Model)相关的。正像它字面意思一样,它是负责准备和管
  • 模型空间: @model PagedList<HYBCNS.ViewModel.StationViewModel> 它下面有两个部分页 @Html.Partial("_conditionPartial",Model) @Html.Partial("_Statics") 部分页(_conditionPartial): 它是一个...
  • 目录 介绍 代码 示例用法 介绍 我一直在开发一个工具来帮助团队中的其他...我在*每个ViewModel*中编写了一系列方法,在模型和视图模型之间来回切换数据。对于某些模型来说,这涉及20个或更多属性,并且支持它们...
  • WPF 数据绑定 命令绑定 事件绑定 ViewViewModel的通信
  • MVC 中的 ViewModel

    千次阅读 2017-11-24 10:28:44
    ViewModel这个概念不只是在在MVC模式中有,你会在很多关于MVC、MVP、MVVM的文章中见到这个说法,并且这个概念在任何技术中都有可能提到,比如ASP.NET, ...在一般的情况下,我们向View中传递数据的时候,都是一个Model
  • 在我们平常的开发当中使用频率最多的就是CRUD(添加、更新、删除、查询)。 而“添加”和“编辑”操作又是整个数据源的入口,在整个CRUD中占有非常重要的地位。常规情况下我们做一个编辑操作时,首先需要将实体对象...
  • 先声明此文是转自MSDN杂志的。之前我和一些同行讨论过MVVM模式,很多人都觉得Silverlight或者WPF项目中没多大必要使用它。今天看到这篇神作,我觉得有必要给大家转过来看看。。。仔细阅读,相信你会受益匪浅。...
  • 如果你已经开发一段时间...在本文,我将重温一下MVC是什么,详述它的缺点,并且告诉你一个新的方式来架构你的app:Model-View-ViewModel。拿出你的流行语bingo card(宾果卡,一种游戏卡片-译者注),因为我们即将进行...
  • ViewModel类是被设计用来以可感知生命周期的方式存储和管理 UI 相关数据,ViewModel中数据会一直存活即使 activity configuration发生变化。 ViewModel有什么优势? 1.数据持久化 activity 在销毁重建时,之前...
  • 还需要些什么呢 在前面几篇博客中我们尝试去实现了MVVM中的数据绑定、命令绑定和事件绑定。貌似实现的差不多了。我最早尝试用MVVM去开发的时候也是这么想的,没有用第三方框架,甚至只是实现了数据绑定和命令绑定就...
  • WPF ViewViewModel的交互 1.WPF中的View 即视图,用来显示的界面,可能是一个窗体,一个对话框等。 2.WPF中的ViewModel 即与View对应的视图模型,用来完成底部的数据操作与更新View显示。 3.初步实现逻辑 a.继承...

空空如也

1 2 3 4 5 ... 20
收藏数 356,532
精华内容 142,612
关键字:

viewmodel