Google AAC(Android Architecture Components)实现MVVM展示架构

1.AAC架构简介

Android Architecture Components,实际上是android官方提供的一系列组件,用来实现MVVM架构。

官方架构图如下:

View层 绿色框中的Activity/Fragment,继承至LifecycleActivity\LifecycleFragment,是UI控件的宿主。核心职责是:

  • 更新UI控件显示,包括状态及数据,由ViewModel驱动
  • 监听UI事件及其生命周期,驱动ViewModel

View层不直接处理任何业务逻辑及数据加工。尽量做到瘦身,代码逻辑简约,减轻UI线程负担。

ViewModel层 蓝色框的ViewModel。只做业务逻辑操作,不持有任何UI控件的引用。那数据的更新如何通知到View层,这就要仰仗LiveData

Model层 橘黄色框的Repository及其下都是Model层。Model层就是数据层。数据来源有:

  • 本地存储数据,如数据库,文件,SharedPreferences
  • 内存的缓存或临时数据
  • 通过各种网络协议获取的远程数据

Repository是数据仓库,整合各路来源的数据,再统一暴露给ViewModel层使用。官方新框架在这一层只提供给了一个新的SQLite数据库封装类库Room,这是可选的。换言之,Model层,官方只提供指导思想,并未有具体实现方案。那问题来了:

  • Model层如何与ViewModel通信
  • Repository 如何整合各路数据,进行业务处理

各层的依赖关系如下:

这与通常的MVVM架构存在不一样的地方。使用官方提供的Data Binding类库,可以实现MVVM架构,各层依赖关系如下:

但是View与ViewMode是双向绑定的,即View的改动会反馈到ViewModel,反之亦然。而且使用Data Binding,需要在xml布局文件添加过多逻辑,数据与xml布局交叉在一起。在AAC实现的MVVM架构中,使用LiveData类实现单向绑定,对使用者相对友好,而且,上层只依赖临近的下层,下层不可调用上层,减少了相互之间的依赖。

2. AAC组件详解

 

从上图里可以看到几个比较重要的概念:

    LifeCycle

生命周期管理,把原先Android生命周期的中的代码抽取出来,如将原先需要在onStart()等生命周期中执行的代码分离到Activity或者Fragment之外。

    ViewModel

用于实现架构中的ViewModel,同时是与Lifecycle绑定的,使用者无需担心生命周期。可以在多个Fragment之间共享数据,比如旋转屏幕后Activity会重新create,这时候使用ViewModel还是之前的数据,不需要再次请求网络数据。

    LiveData

一个数据持有类,持有数据并且这个数据可以被观察被监听,和其他Observer不同的是,它是和Lifecycle是绑定的,在生命周期内使用有效,减少内存泄露和引用问题。

    Room

谷歌推出的一个Sqlite ORM库,不过使用起来还不错,使用注解,极大简化数据库的操作,有点类似Retrofit的风格。
3. 实例解析

3.1 LifeCycle

这里通过一个示例:自定义View结合LifeCycle使用,来学习和了解。

import android.annotation.SuppressLint;
import android.arch.lifecycle.Lifecycle;
import android.arch.lifecycle.LifecycleObserver;
import android.arch.lifecycle.OnLifecycleEvent;
import android.content.Context;
import android.graphics.Canvas;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;

@SuppressLint("AppCompatCustomView")
public class MyTv extends TextView implements LifecycleObserver {
    private String TAG = "MyTv";
    private boolean lifeCycleEnable;
    private Lifecycle lifecycle;

    public boolean isLifeCycleEnable() {
        return lifeCycleEnable;
    }

    public void setLifeCycleEnable(boolean lifeCycleEnable) {
        this.lifeCycleEnable = lifeCycleEnable;
    }

    public Lifecycle getLifecycle() {
        return lifecycle;
    }

    public void setLifecycle(Lifecycle lifecycle) {
        this.lifecycle = lifecycle;
    }

    public MyTv(Context context) {
        super(context);

    }

    public MyTv(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

    }

    public MyTv(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }


    // ****************** lifeCycle ******************

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    public void create() {
        if (lifeCycleEnable) {
            String text = System.currentTimeMillis() + "-creat\n";
            Log.e(TAG, text);
            this.setText(text);
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    public void start() {
        if (lifeCycleEnable) {
            String text = System.currentTimeMillis() + "-start\n";
            Log.e(TAG, text);
            this.setText(text);
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void resume() {
        if (lifeCycleEnable) {
            String text = System.currentTimeMillis() + "-resume\n";
            Log.e(TAG, text);
            this.setText(text);
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void pause() {
        if (lifeCycleEnable) {
            String text = System.currentTimeMillis() + "-pause\n";
            Log.e(TAG, text);
            this.setText(text);
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    public void stop() {
        if (lifeCycleEnable) {
            String text = System.currentTimeMillis() + "-stop\n";
            Log.e(TAG, text);
            this.setText(text);
        }
    }

}

分析:

    implements LifecycleObserver
    定义2个变量
    @OnLifecycleEvent 注解使用
MainActivity.class:

import android.arch.lifecycle.LifecycleRegistry;
import android.arch.lifecycle.LifecycleRegistryOwner;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity implements LifecycleRegistryOwner {

    private LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this);

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

        proxy.zj.com.lifecycledemo.MyTv mTv = findViewById(R.id.dfttv);
        mTv.setLifecycle(getLifecycle());
        getLifecycle().addObserver(mTv);
        mTv.setLifeCycleEnable(true);

    }

    @Override
    public LifecycleRegistry getLifecycle() {
        return lifecycleRegistry;
    }
}

分析:

    implements LifecycleRegistryOwner
日志如下:

02-24 16:18:31.188 4694-4694/proxy.zj.com.lifecycledemo E/MyTv: Hello World!1519460311207-creat 02-24 16:18:31.198 4694-4694/proxy.zj.com.lifecycledemo E/MyTv: 1519460311209-start 02-24 16:18:31.198 4694-4694/proxy.zj.com.lifecycledemo E/MyTv: 1519460311210-resume 02-24 16:32:46.058 4694-4694/proxy.zj.com.lifecycledemo E/MyTv: 1519461166069-pause 02-24 16:32:46.798 4694-4694/proxy.zj.com.lifecycledemo E/MyTv: 1519461166812-stop 02-24 16:32:47.988 4694-4694/proxy.zj.com.lifecycledemo E/MyTv: 1519461168004-start 02-24 16:32:47.988 4694-4694/proxy.zj.com.lifecycledemo E/MyTv: 1519461168004-resume
 

    LifeCycle是什么?

首先,LifeCycle它是一个持有Activity/Fragment生命周期的的类。
第二,它通过接口LifecycleRegistryOwner/LifecycleObserver(注解事件@OnLifecycleEvent),以及外部调用观察者模式addObserver(mTv),来完成将(Activity/Fragment)”生命周期”共享给其他组件这么一件事。

    它包含俩个角色分别是:

LifecycleObserver:MyTv
LifecycleRegistryOwner:MainActivity

    这里再简化下逻辑就是:

LifecycleRegistryOwner.addObserver(LifecycleObserver)
LifecycleObserver > @OnLifecycleEvent onCreate…
 

3.2 LiveData

通过上一个例子,我们了解了2个重要的概念:LifecycleRegistryOwner,LifecycleObserver

而liveData实际上也有这俩个概念.

MainActivity 相当于LifecycleRegistryOwner

package proxy.zj.com.livedatademo;

import android.arch.lifecycle.LifecycleRegistry;
import android.arch.lifecycle.LifecycleRegistryOwner;
import android.arch.lifecycle.MutableLiveData;
import android.arch.lifecycle.Observer;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends AppCompatActivity implements LifecycleRegistryOwner {

    private LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//        MutableLiveData
        UserData userData = new UserData();
        userData.observe(this, new Observer() {
            @Override
            public void onChanged(@Nullable Object o) {
                Log.e("UserData","onChanged");
            }
        });

        userData.setValue("");

    }

    @Override
    public LifecycleRegistry getLifecycle() {
        return lifecycleRegistry;
    }
}

LifecycleObserver

package proxy.zj.com.livedatademo;

import android.arch.lifecycle.LifecycleObserver;
import android.arch.lifecycle.LiveData;
import android.util.Log;

/**
 * Created by thinkpad on 2018/2/26.
 */

public class UserData extends LiveData implements LifecycleObserver {

    private static final String TAG = "UserData";

    public UserData() {
    }

    @Override
    protected void onActive() {
        super.onActive();
        Log.e(TAG, "onActive");
    }

    @Override
    protected void onInactive() {
        super.onInactive();
        Log.e(TAG, "onInactive");
    }

    @Override
    protected void setValue(Object value) {
        super.setValue(value);
        Log.e(TAG, "setValue");
    }


}

日志输出:

02-26 14:43:54.444 20885-20885/proxy.zj.com.aacdemo E/UserData: setValue
02-26 14:43:54.456 20885-20885/proxy.zj.com.aacdemo E/UserData: onActive
02-26 14:43:54.456 20885-20885/proxy.zj.com.aacdemo E/UserData: onChanged
02-26 14:51:11.974 20885-20885/proxy.zj.com.aacdemo E/UserData: onInactive
02-26 14:51:23.304 20885-20885/proxy.zj.com.aacdemo E/UserData: onActive
02-26 14:51:23.317 20885-20885/proxy.zj.com.aacdemo E/UserData: onInactive
02-26 14:52:04.743 20885-20885/proxy.zj.com.aacdemo E/UserData: onActive
02-26 14:52:04.754 20885-20885/proxy.zj.com.aacdemo E/UserData: onInactive
02-26 14:52:21.350 20885-20885/proxy.zj.com.aacdemo E/UserData: onActive
02-26 14:52:21.362 20885-20885/proxy.zj.com.aacdemo E/UserData: onInactive
02-26 14:52:32.738 20885-20885/proxy.zj.com.aacdemo E/UserData: onActive
02-26 14:52:32.749 20885-20885/proxy.zj.com.aacdemo E/UserData: onInactive
02-26 14:53:25.746 20885-20885/proxy.zj.com.aacdemo E/UserData: onActive
02-26 14:53:25.764 20885-20885/proxy.zj.com.aacdemo E/UserData: onInactive
02-26 14:53:44.762 20885-20885/proxy.zj.com.aacdemo E/UserData: onActive
02-26 14:53:44.778 20885-20885/proxy.zj.com.aacdemo E/UserData: onInactive

分析observe

可以看到Owner内是通过observe方法对LiveData进行将2者”连接”的。

@MainThread
    public void observe(LifecycleOwner owner, Observer<T> observer) {

        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }

        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        LifecycleBoundObserver existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing != null && existing.owner != wrapper.owner) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }

        if (existing != null) {
            return;
        }

        owner.getLifecycle().addObserver(wrapper);
        wrapper.activeStateChanged(isActiveState(owner.getLifecycle().getCurrentState()));

    }

重点关注这3点:

    The observer will only receive events if the owner is in {@link Lifecycle.State#STARTED} or {@link Lifecycle.State#RESUMED} state (active).

可以看到active()方法的回调是基于Owner的 【Lifecycle.State#STARTED】和【@link Lifecycle.State#RESUMED】。

    If the owner moves to the {@link Lifecycle.State#DESTROYED} state, the observer will automatically be removed

如果Owner状态转换至destroy状态,将会自动移除observer。

    If the given owner is already in {@link Lifecycle.State#DESTROYED} state, LiveData ignores the call.

如果Owner已经处于destroy状态,那么LiveData则会自动过滤(体现在源码内前俩行)

onChange()调用链:

另外简单梳理了一下它的调用链,有兴趣的朋友可以看下源码。

LiveData.class:

setValue(T value) —> dispatchingValue(@Nullable LifecycleBoundObserver initiator) —> considerNotify(LifecycleBoundObserver observer) —> onChanged

可以看到,onchange方法的执行有俩个必要条件

    1.调用了setValue
    2.owner是active的

小结:

    LiveData处于AAC架构中的Observer这一环。

    LiveData的三个重要方法—onActive的作用:
    当生命周期处于onStart,onResume时激活,且当这个方法被调用时,表示LiveData的观察者数量从0变为了1,这时就我们的位置监听来说,就应该注册我们的时间监听了。

    LiveData的三个重要方法—onInActivive的作用:
    当生命周期处于onDestroy时激活,且当这个方法被调用时,表示LiveData的观察者数量变为了0,既然没有了观察者,也就没有理由再做监听,此时我们就应该将位置监听移除。

    LiveData的三个重要方法—setValue的作用:
    当调用此方法时,会激活Observer内的onChange方法,且通过调用这个方法来更新LiveData的数据,并通知处于活动状态的观察者。

    LiveData和Owner相连是通过observe这个方法
    一句题外话,一般来说,工程项目内不直接用LiveData,而是用它的子类:MutableLiveData。另外,AppCompactActivity内部实现了Owner,所以我们实际上也不需要再去impl lifeCycleOnwer这个接口了
3.3 ViewModel

这个东西就类似mvc,mvp中的c和p,属于逻辑处理层,调用Model层获取数据,并通过LiveData通知UI更新数据。

结合Retrofit网络请求,完整的例子如下:

RxActivity:

package proxy.zj.com.networklivedata.rx;

import android.arch.lifecycle.MutableLiveData;
import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProviders;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.TimeUtils;
import android.view.View;
import android.widget.TextView;

import java.util.Date;

import proxy.zj.com.networklivedata.R;
import proxy.zj.com.networklivedata.bean.TestData;
import proxy.zj.com.networklivedata.okgo.OkGoActivity;
import proxy.zj.com.networklivedata.okgo.OkGoViewModel;

public class RxActivity extends AppCompatActivity {

    private TextView content;
    private String TAG = "RxActivity";

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

        content = findViewById(R.id.content);

        final RxJavaViewModel model = ViewModelProviders.of(this).get(RxJavaViewModel.class);

        findViewById(R.id.getdata).setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {

                MutableLiveData data = model.getData();

                data.observe(RxActivity.this, new Observer<TestData>() {
                    @Override
                    public void onChanged(@Nullable TestData o) {
                        Date a = new Date(System.currentTimeMillis());
                        content.setText( proxy.zj.com.networklivedata.TimeUtils.date2String(a) +"   >>>>>   "+o.getContent());
                    }
                });

            }

        });

    }
}

 

RxJavaViewModel:

package proxy.zj.com.networklivedata.rx;

import android.arch.lifecycle.MutableLiveData;
import android.arch.lifecycle.ViewModel;
import android.support.annotation.NonNull;
import android.util.Log;


import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;

import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;

import java.util.concurrent.TimeUnit;

import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import proxy.zj.com.networklivedata.bean.TestData;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.converter.scalars.ScalarsConverterFactory;

/**
 * Created by thinkpad on 2018/2/27.
 */
public class RxJavaViewModel extends ViewModel {

    private static final String TAG = "RxJavaViewModel";

    private MutableLiveData<TestData> data = new MutableLiveData<>();

    RequestApi retrofitPostApi = null;

    public RxJavaViewModel() {
        init();
    }

    public MutableLiveData getData() {
        loadData();
        return data;
    }

    private void init() {
        //初始化Retrofit实例
        Retrofit retrofit = initRetrofit();

        //这里采用的是Java的动态代理模式,得到请求接口对象
        retrofitPostApi = retrofit.create(RequestApi.class);
    }

    private void loadData() {
        String url = "v2/book/1003078";
        retrofitPostApi.getPathDoubadataRx(url)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<String>() {

                    @Override
                    public void onSubscribe(Disposable d) {
                        Log.e(TAG,"onSubscribe");
                    }

                    @Override
                    public void onNext(String value) {
                        Log.e(TAG,"onNext");
                        data.setValue(new TestData(value));
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e(TAG,"onError");
                    }

                    @Override
                    public void onComplete() {
                        Log.e(TAG,"onComplete");
                    }
                });
    }

    /**
     * 初始化Retrofit实例
     * @return
     */
    private Retrofit initRetrofit() {
        //日志拦截器
        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
            @Override
            public void log(String message) {
                //打印retrofit日志
                Log.i(TAG, "retrofitBack = " + message);
            }
        });
        OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
        OkHttpClient client = builder
                //超时时间 不设置的话 默认30秒
                .addInterceptor(loggingInterceptor)
//                .connectTimeout(mTimeOut, TimeUnit.SECONDS)
//                .readTimeout(mTimeOut, TimeUnit.SECONDS)
//                .writeTimeout(mTimeOut, TimeUnit.SECONDS)
                .build();

        String BASE_URL = "https://api.douban.com/"; //豆瓣接口

        Retrofit retrofit = new Retrofit.Builder()
                .client(builder.build())
                .baseUrl(BASE_URL)//baseurl设置
                .addConverterFactory(ScalarsConverterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())//增加返回值为Gson的支持(返回实体类)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())//这个adapter很重要,专门找了方案来解决这个问题
                .build();

        return retrofit;
    }
}

Retrofit接口 RequestApi

package proxy.zj.com.networklivedata.rx;

import io.reactivex.Flowable;
import io.reactivex.Observable;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Path;
import retrofit2.http.Query;

/**
 * Created by thinkpad on 2018/2/28.
 */

public interface RequestApi {

    /**
     * 结合rxJava
     */
    @GET("{url}")
    Observable<String> getPathDoubadataRx(@Path("url") String url);
    
}

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值