Google Architecture ViewModel

关于ViewModel 介绍,文章不过多阐述。官方文档html

本文将从三个方面作必定阐述java

  1. 为何会推出ViewModel,它能带来什么好处?
  2. 一些例子
  3. 相关注意事项

为何须要ViewModel

  • 你须要处理配置变化android

    • 笔者认为,用户能够随时改变配置(i.e 旋转屏幕,切换语言,切换系统文字大小 ...),这可能会致使当前Activity重建,这些都不受开发者的控制,可是你又不得不处理它
    • 可能不少APP在配置清单文件中申明了每个Activityorientation = portrait ,可是你没法禁止用户去改变语言、文字大小。这样就可能会致使Activity被移除或者从新建立
  • 为何onSaveInstanceState依旧不够git

    传统的作法都是在配置发生变化即 onSaveInstanceState 方法去save data, 在onCreate去restore datagithub

    可是这里有两个限制api

    • onSaveInstanceState方法不可以缓存较大的数据,笔者以前尝试缓存上百兆数据发现抛出了TransactionTooLargeException
    • 保存的数据必定须要实现serializable 或者 Parceable, 可是有时候这些数据来自第三方库,咱们不能修改它,对于某些场景,很难在onSaveonSaveInstanceState中保存数据

基于上述两点,ViewModel应运而生缓存

  • 配置改变先后数据存储与恢复

一些例子

基础功能

public class ZeroViewModel extends ViewModel {
    public User user;
}
复制代码
public class ZeroDemo extends AppCompatActivity {
    private TextView tv;
    private ZeroViewModel vm;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tv_btn);
        tv = findViewById(R.id.tv_simple);
        
        vm = ViewModelProviders.of(this).get(ZeroViewModel.class);
        System.out.println("szw vm.user = " + vm.user);
    }
    
    // android:onClick="onClickSimpleButton"
    public void onClickSimpleButton(View v) {
        vm.user = new User(23, "jorden");
    }
}
复制代码

旋转屏幕,vm.user 依旧 != null网络

同一个Activity不一样实例

  1. 同时存在两个实例
public class SameClass01 extends AppCompatActivity {
    private TextView tv;
    private ZeroViewModel vm;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tv_btn);
        tv = findViewById(R.id.tv_simple);

        vm = ViewModelProviders.of(this).get(ZeroViewModel.class);
        System.out.println("szw SameClass01 : " + vm.user);

    }
    // launch the second instance
    // android:onClick="onClickSimpleButton"
    public void onClickSimpleButton(View v) {
        vm.user = new User(100, "SuperMario");
        startActivity(new Intent(this, SameClass01.class));
    }
}
复制代码

即便有两个同类的Activity实例,第一个vm.user 持有的依旧是Mario,第二个vm.user 持有null . 这符合笔者的预期oracle

  1. finish再从新建立
public class SameClass02 extends AppCompatActivity {
    private TextView tv;
    private ZeroViewModel vm;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tv_btn);
        tv = findViewById(R.id.tv_simple);
        vm = ViewModelProviders.of(this).get(ZeroViewModel.class);
        System.out.println("szw SameClass02 onCreate() : " + vm.user);
    }
    // android:onClick="onClickSimpleButton"
    public void onClickSimpleButton(View v) {
        vm.user = new User(22, "test");
    }

    // android:onClick="onClickSimpleButton2"
    public void onClickSimpleButton2(View v) {
        System.out.println("szw SameClass02 : saved = "+vm.user);
    }
}
复制代码

先启动SameClass02 ,执行onClickSimpleButton,finish从新打开,日志输出nullapp

上述两个例子表现正常

和Static申明的变量比较

  1. 基础比较
public class SameVm {
    public static User user;
}
复制代码
public class ZeroDemo extends AppCompatActivity {
    private TextView tv;
    private ZeroViewModel vm;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tv_btn);
        tv = findViewById(R.id.tv_simple);

        String value = savedInstanceState == null ? "emptyBundle" : savedInstanceState.getString("key");
        System.out.println("szw onCreate() " + value);

        vm = ViewModelProviders.of(this).get(ZeroViewModel.class);
        System.out.println("szw vm.user = " + vm.user);

        System.out.println("szw static = "+SameVm.user);
    }

    // android:onClick="onClickSimpleButton"
    public void onClickSimpleButton(View v) {
        vm.user = new User(23, "jorden");
        SameVm.user = new User(21, "king");
    }
}
复制代码

旋转屏幕后,日志输出

szw vm.user = User{id=23, name='jorden'}
szw static = User{id=21, name='king’}
复制代码
  1. 终止应用Terminate Application

和1一样的操做

szw vm.user = null
szw static = null
复制代码

从上面两个例子,感受没什么不一样。他们都能缓存数据,终止应用程序都会被销毁

它们的不一样之处:

  • ViewModel 主要是为了解耦,有点相似于MVP中的P,ViewModel 是MvvM中VM。你能在ViewModel中作异步操做(i.e访问网络),你能够改变data而且让View接受到通知LiveData
  • static value 能被任何类修改,可是ViewModel 是Activity的私有变量,有点相似ThreadLocal
  • ViewModel 能够判断Activity是正常销毁或者配置改变,进而作出不一样的响应,finish->removedata ,configurationchange->savedata,静态变量却不能

相关注意事项

  1. ViewModel不要应用Activity等相关实例,容易形成内存泄漏
  2. 若是你须要在ViewMolde中获取Resource LocationManager等系统服务,能够继承AndroidViewModel
  3. ViewModel自己不支持事件模型(EventBus),你能够使用LiveData,固然为了解决旋转屏幕后,再次注册Observer,重复提示,能够使用SingleLiveEvent
  4. 当系统回收咱们应用时,ViewModel 并不能保存数据,咱们依旧须要复写onSaveInstanceState方法

源码以下

public class DupliViewModel extends ViewModel {
    private SingleLiveEvent<String> message = new SingleLiveEvent<>();

    public void fetchMessage(){
        message.setValue("A New Value");
    }

    public LiveData<String> getMessage() {
        return message;
    }
}
复制代码
public class DupliObserverDemo extends AppCompatActivity {
    private TextView tv;
    private DupliObserverDemo self;
    private DupliViewModel vm;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tv_btn);
        self = this;
        tv = findViewById(R.id.tv_simple);

        vm = ViewModelProviders.of(this).get(DupliViewModel.class);
        vm.getMessage().observe(this, new Observer<String>() {
            @Override
            public void onChanged(@Nullable String s) {
                System.out.println("szw updated ~");
                Toast.makeText(self, "updated "+s, Toast.LENGTH_SHORT).show();
            }
        });
    }
    
    // android:onClick="onClickSimpleButton"
    public void onClickSimpleButton(View v) {
        vm.fetchMessage();
    }

}
复制代码
相关文章
相关标签/搜索