轻量级的MVVM

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/a296777513/article/details/84498314

背景

现在的项目中各种开发框架都有,MVC,MVP,MVVM。比较混乱,虽然也推出了MVVM,但是由于没有强制和代码历史的问题,大部分的时候还是使用之前的开发框架进行开发,所以现在整个项目的结构比较复杂和混乱。

先设立一个小目标,先在咱们组内,统一开发框架,实践出真知,在实践中检测这个框架的易用性,然后加以改造,在推广出去。

目标

老话再谈,在已有的项目中引入、更新框架,都是有成本的,这就需要分析利弊,看是否值得去做。

目标就是为了解耦,让开发人员更加专注逻辑的实现。一句话就是让开发者用起来更爽。

本文重点

  1. 分析现在已有的框架MVC、MVP、MVVM的优缺点
  2. 介绍本文MVVM使用到的类以及优点
  3. 介绍实现的原理
  4. 介绍使用方式

MVVM-livedata

谷歌写了很多开发框架demo,MVP-xx和MVVM-xx系列,感兴趣的同学可以研究研究。android-architecture

MVC就不说了,最老的一款开发框架,带来的缺点就是所有的处理逻辑都在Activity或者Fragment中,造成一个类成百上千行代码

MVP(Model-View-Presenter)

  • View 对应的Activity、Fragment,负责界面的交互和UI的绘制
  • Model 负责业务逻辑和实体模型
  • Presenter 是M和V的纽带,通过定义接口和V交互

缺点

  1. Presenter除了自身的逻辑外,有大量的Model->View,View->Model,造成了Presenter臃肿,难以维护。
  2. 由于每个Presenter通过自定义的接口和View交互,也就是说一旦UI变动,需要变动的代码就会很多。
  3. 每一个Presneter对一个接口,那么接口就会成倍的增加

根据以上的描述,我们需要解决

  1. 过于繁重的传递,当然这些是必须的,但是怎么能做到对使用者屏蔽细节,通过一些方法帮我们处理了。
  2. 解决成堆的创建接口。
  3. 基本没有学习成本,拿来即用。

当然优秀的框架是高内聚、低耦合、可维护、可扩展。其实对于任何的开发框架,没有绝对的好和绝对的坏,只有合不合适,MVP->MVVM只不过是让模型和视图分离的更加彻底。用什么框架还是要跟着业务的需求走。

MVVM-livedata

基于ViewModel、LiveData、Bolt.Task的MVVM系统架构,并且使用了泛型,深度解耦。

简单介绍一下这几个组件。

ViewModel

The ViewModel class is designed to store and manage UI-related data in a lifecycle conscious way. The ViewModel class allows data to survive configuration changes such as screen rotations.

上面是官方的介绍,大概的意思是:ViewModel是用来存储和管理UI相关的数据,并且感知生命周期。不会对着configuration的改变而重新创建,举个例子,就是不会因为竖屏转为横屏,从新创建。

优点

  1. 数据共享
  2. 感知生命周期

LiveData

LiveData is an observable data holder class. Unlike a regular observable, LiveData is lifecycle-aware, meaning it respects the lifecycle of other app components, such as activities, fragments, or services. This awareness ensures LiveData only updates app component observers that are in an active lifecycle state.

大概的意思:它可以用来持有可被观察的数据,可以感知到UI组件的生命周期,只有组件处于活动(STARTED和RESUMED)状态时,LivedData才可以用来更新数据。当组件DESTROYED的时候,它会自动移出,不会引起内存泄露。

优点

  1. 感知生命周期,不用手动解注册。
  2. 尽可能减少了内存泄漏的情况,不用使用WeakHandler了
  3. 共享资源

Bolt.Task

是一个轻量级的异步线程管理的框架,可以理解为轻量级的Rx。可以进行函数式编程。使用方法也简单,这里就不介绍了。

对于MVVM的讨论可以看下官方介绍。还可以看下一个介绍的比较清晰的文章

从上线的介绍来看,MVVM最重要的一点就是DataBinding,但是这个框架为什么没有用呢?原因有以下几点:

  1. 看其他文章和朋友介绍(自己没用过),坑比较多。
  2. 有学习成本,引入新的方式,改变的比较多。
  3. debug的时候不方便。

如何使用MVVM-LiveData

  1. 先定义BaseViewModel基类
public class BaseViewModel<T extends BaseRepository> extends AndroidViewModel {

    public T mRepository;

    public BaseViewModel(@NonNull Application application) {
        super(application);
        mRepository = AnnotationUtil.getNewInstance(this, 0);
    }


    @Override
    protected void onCleared() {
        super.onCleared();
        if (mRepository != null) {
            mRepository.cancel();
        }
    }
}

BaseViewModel通过泛型类型参数BaseRepository子类初始化mRepository数据仓库,同时在页面activity/fragment的onDestroy中回调onCleared的方式中释放资源和停止网络请求。

ps:最好不要在BaseViewModel的子类中直接请求网络并且处理返回数据,所有的请求数据应该在BaseRepository的子类中进行。

  1. 定义BaseRepository
public class BaseRepository {
    private CancellationTokenSource cancellationTokenSource;

    public BaseRepository() {
        cancellationTokenSource = new CancellationTokenSource();
    }


    protected <TResult> Task<TResult> callInBackground(Callable<TResult> callable) {
        return Task.callInBackground(callable, cancellationTokenSource.getToken());
    }

    protected <TResult> Task<TResult> callInBackground(String type, Callable<TResult> callable) {
        return Task.callInBackground(callable, cancellationTokenSource.getToken())
                .continueWith(task -> {
                    if (task.isFaulted()) {
                        sendResult(type, task.getError());
                    } else if (task.isCompleted()) {
                        sendResult(type, task.getResult());
                    }
                    return null;
                }, cancellationTokenSource.getToken());
    }

    protected <TResult> Task<TResult> call(String type, Callable<TResult> callable) {
        return Task.call(callable, cancellationTokenSource.getToken())
                .continueWith(task -> {
                    if (task.isFaulted()) {
                        sendResult(type, task.getError());
                    } else if (task.isCompleted()) {
                        sendResult(type, task.getResult());
                    }
                    return null;
                }, cancellationTokenSource.getToken());
    }

    protected <TResult> Task<TResult> call(Callable<TResult> callable) {
        return Task.call(callable, cancellationTokenSource.getToken());
    }


    protected void sendResult(String type, Object o) {
        LifecycleBus.get().postAction(Action.type(type).put(o).build());
    }

    public void cancel() {
        if (cancellationTokenSource != null) {
            cancellationTokenSource.cancel();
        }
    }
}

BaseRepository分装了网络请求,异步线程和当前的线程,对结果使用LifecycleBus发送请求结果,在页面销毁的时候取消网络请求。主要是方便管理网络请求。

  1. 然后自定义LifecycleBaseActivity和LifecycleBaseFragment,所有的子类继承这两个类,再无感知的情况下使用(6不6)
public class LifecycleBaseActivity<T extends BaseViewModel> extends AmeActivity {


    protected T mViewModel;
    private List<String> mEventKeys;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mViewModel = VMProviders(this, AnnotationUtil.getClass(this, 0));
        if (mViewModel != null) {
            dataObserver();
        }
    }

    protected void dataObserver() {

    }

    protected void registerObserver(String key, Observer<Action> action) {
        if (mEventKeys == null) {
            mEventKeys = new ArrayList<>();
        }
        mEventKeys.add(key);
        LifecycleBus.get().addObserve(this, key, action);
    }


    protected T VMProviders(AppCompatActivity activity, Class<T> tClass) {
        return ViewModelProviders.of(activity).get(tClass);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        for (String key : mEventKeys) {
            LifecycleBus.get().removeKey(key);
        }
    }
}

onCreate的时候,通过反射获取泛型参数的Class,然后通过ViewModelProviders.of(activity).get(tClass)来实例化ViewModel。子类通过registerObserver()函数监听事件。这样就完成了基类的基本编写。

Java反射为何慢?

《Java Reflection in Action》中这样说

Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications.

大概意思:
反射是动态的对类型、方法进行解析,肯定是会比直接调用慢一点。jvm无法优化。
java反射机制,是在运行状态中,对于任何一个类,都能够访问这个类的所有属性和方法,同时任何一个对象也都能够调用它的任意一个方法和属性,这个功能称为java语言的反射机制。

做了一个实验,对一个创建一个对象10000次,看下耗时


fun test(){
     Log.i("liyachao", "begin")

        var time = System.currentTimeMillis();
        for (i in 1..10000) {
            AnnotationUtil.getNewInstance<Test>(this, 0);
        }

        Log.i("liyachao", "reflect waste time " + (System.currentTimeMillis() - time))

        time = System.currentTimeMillis();
        for (i in 1..10000) {
            var temp = Test()
        }
        Log.i("liyachao", "new waste time " + (System.currentTimeMillis() - time))
}
 // reflect waste time 343
 // new waste time 105

从上面来看,我们平时使用反射做一些事情是可以的,在纳秒级别,不会对应用有性能的影响。

猜你喜欢

转载自blog.csdn.net/a296777513/article/details/84498314
今日推荐