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);
}