AAC全称Android Architecture Components,是Android官方推出的MVVM架构指导方案。我们知道Android官方之前为了支持MVVM已经推出了DataBinding方案,AAC与DataBinding之间没有任何关系,但它们可以结合使用。在阅读本文后续内容前可以先看下Android架构模式之MVC、MVP、MVVM这篇文章,本文后面所描述的例子是以该文章的例子为基础的。
使用AAC需要导入如下依赖:
compile "android.arch.lifecycle:runtime:1.1.1"
compile "android.arch.lifecycle:extensions:1.1.1"
annotationProcessor "android.arch.lifecycle:compiler:1.1.1"
网上不少文章都是基于1.0.0版本进行讲解,本文则是基于写此文章时最新的1.1.1版本,两个版本之间还是有不少差异性且1.1.1没有完全兼容1.0.0,读者需要注意。
AAC主要包含如下东西:
Lifecycle
Lifecycle一看就是用来管理生命周期的,它负责将Activity/Fragment的生命周期同步给其它模块,主要饱含三种角色:
- Lifecycle:生命周期本身,其它模块(
LifecycleObserver
)可以对其进行观测,以便在状态发生变化时接收通知,同时也可以主动从这里获取当前状态。 - LifecycleOwner:
Lifecycle
的持有者,一般为上下文对象,比如Activity
和Fragment
,因为生命周期就是从它们这里同步出去的。 - LifecycleObserver:生命周期观察者,观察者通过向
Lifecycle
注册来监听生命周期的变化。
一个简单的流程如下:
-
Activity
或Fragment
实现LifecycleOwner
接口,创建并持有Lifecycle
对象。 - 某模块实现
LifecycleObserver
接口,并将自身注册到步骤1创建的Lifecycle
对象中,以便观察Activity
或Fragment
生命周期的变化。 - 生命周期变化时,
Activity
或Fragment
将状态同步给Lifecycle
对象。 -
Lifecycle
对象dispatch
事件给所有LifecycleObserver
对象。
在1.1.1版本中,FragmentActivity
和Fragment
已经集成了Lifecycle
,也就是说需要我们处理的只有流程2。我们来看下代码:
UserActivity.java
public class UserActivity extends FragmentActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user);
getLifecycle().addObserver(new UserController(getLifecycle()));
log("onCreate");
}
@Override
protected void onStart() {
super.onStart();
log("onStart");
}
@Override
protected void onResume() {
super.onResume();
log("onResume");
}
@Override
protected void onPause() {
log("onPause");
super.onPause();
}
@Override
protected void onStop() {
log("onStop");
super.onStop();
}
@Override
protected void onDestroy() {
log("onDestroy");
super.onDestroy();
}
private void log(String msg) {
Log.i("sean_activity", msg);
}
}
UserController.java
public class UserController implements LifecycleObserver {
private Lifecycle mLifecycle;
public UserController(Lifecycle lifecycle) {
this.mLifecycle = lifecycle;
}
private void log(String msg) {
Log.i("sean_lifecycle", msg);
}
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void onCreate() {
log("onCreate");
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onStart() {
log("onStart");
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume() {
log("onResume");
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void onPause() {
log("onPause");
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onStop() {
log("onStop");
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
public void onDestroy() {
log("onDestroy");
}
@OnLifecycleEvent(Lifecycle.Event.ON_ANY)
public void onAny() {
log("onAny:" + mLifecycle.getCurrentState());
}
}
读者可以先运行下上面的例子(xml布局随便搞一个),看下日志输出,接着我们来分析下:
-
UserController
作为控制器是为了分离出原本在UserActivity
中处理的逻辑代码,因此它需要监听Activity
的生命周期,所以它实现了LifecycleObserver
。 -
UserActivity
继承了FragmentActivity
而不是Activity
是因为前者集成了Lifecycle
而后者没有,它扮演的是LifecycleOwner
的角色,且是Lifecycle
的创建者和持有者。 -
Lifecycle
对象的实际类型是LifecycleRegistry
。 - 生命周期的分发我们不需要关心,想了解原理的自行查看源码,我们需要关心的是
Observer
如何接收生命周期的变化。这里使用OnLifecycleEvent
注解,该注解只有一个参数,表示生命周期变化对应的事件,所有事件在代码中都列出来了,看事件名就可以知道对应哪个生命周期了,这里不再多说。当生命周期发生变化时,Observer
中对应的方法会被调用,其中ANY
是比较特殊的,每次生命周期发生变化时都会在原事件触发后触发。 - CREATE/START/RESUME事件由
Owner
先触发,Observer
后触发;PAUSE/STOP/DESTROY由Observer
先触发,Owner
后触发。
UserController
之后会被废弃,因为AAC是MVVM模式的应用,后面会使用ViewModel来代替UserController
。之所以本例中使用UserController
,是为了排除其它干扰因素,能更直接地理解和掌握Lifecycle
。
LiveData
LiveData
是一个可被观察的数据持有者,即它既是一个Observable
(被观察者/发布者),同时持有数据模型(或者本身作为数据模型也可以),它的Observer
(观察者)通常都是控制层对象(如Activity
或Fragment
)。与一般的Observable
不同,LiveData
能知道Observer
的生命周期变化,这意味着它能同步到Activity
、Fragment
等组件的生命周期,这确保了LiveData
只更新处于活跃状态的Observer
。
如果一个
Observer
的生命周期处于非DESTROYED
状态时,那么LiveData
将认为这个Observer
处于活跃状态。LiveData
仅通知活跃的Observer
去更新UI。非活跃状态的Observer
,即使订阅了LiveData
,也不会收到更新的通知。
之后为了简化语言和便于直观理解,我们以Activity作为控制层来讲解,即之后提到的Activity同时代表控制层及LiveData
的观察者。
我们上面提到LiveData
可以观察到Activity
的生命周期变化,同时它的数据变化也能够被Activity
观测到,因此LiveData
和Activity
互为观察者。
-
LiveData
作为观察者时:根据前面Lifecycle
所掌握到的知识,LiveData
要观察Activity
就需要实现LifecycleObserver
,同时将自身注册到Activity
中。 -
LiveData
作为被观察者时:它需要保存观察者的集合,提供注册和反注册的方法。Android中已经提供了两个LiveData
相关的类,分别是LiveData
和MutableLiveData
,提供了作为被观察者需要的方法,同时也提供了第1点提到的注册自身的方法,二者的区别是前者的数据不可变,后者可变。因此,我们在应用LiveData
时,只需要根据情况选择继承它们其一即可。如没有特别说明,
LiveData
指概念本身,而非具体的类。 -
Activity
作为被观察者时:需要实现LifecycleOwner
接口,根据前面掌握的知识,实际上只需要继承FragmentActivity
即可。 -
Activity
作为观察者时:需要实现Observer
,并注册到LiveData
中。
结合Lifecycle
和LiveData
在之前MVC的基础上进行重构,代码如下:
UserLiveData.java
public class UserLiveData extends MutableLiveData {
}
UserActivity.java
public class UserActivity extends FragmentActivity implements Observer, UserBusiness.UserListener {
private TextView mNameView;
private TextView mAgaView;
private UserBusiness mUserBusiness = UserBusiness.get();
private UserLiveData mUserLiveData;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user);
mNameView = findViewById(R.id.tv_name);
mAgaView = findViewById(R.id.tv_age);
findViewById(R.id.btn_refresh).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 向服务器请求最新用户信息
mUserBusiness.requestUser();
}
});
// 加载数据库缓存中的用户信息
User user = mUserBusiness.getUser();
mUserLiveData = new UserLiveData();
// LiveData注册对Activity的监听,同时Activity注册对LiveData的监听
mUserLiveData.observe(this, this);
// 更新LiveData中的数据
mUserLiveData.postValue(user);
mUserBusiness.addListener(this);
}
@Override
protected void onDestroy() {
mUserBusiness.removeListener(this);
super.onDestroy();
}
@Override
public void onChanged(@Nullable User user) {
// LiveData中的数据更新,在这里刷新UI,这个方法是在主线程中调用的,可放心刷新UI
mNameView.setText("昵称:" + user.name);
mAgaView.setText("年龄:" + user.age);
}
@Override
public void onRequestUserResult(int code, User user) {
if(code == 0) {
// 更新LiveData中的数据
mUserLiveData.postValue(user);
} else {
Toast.makeText(this, "刷新失败", Toast.LENGTH_SHORT).show();
}
}
}
分析一下:
-
LiveData
的observe
方法内部进行了双向注册,Activity
观察LiveData
的数据变化,数据变化时会触发Activity.onChange
方法;LiveData
观察Activity
生命周期的变化,当生命周期状态变更为DESTROYED时(Activity.onDestroy
),移除Activity
在LiveData
中的注册信息,后续发生数据变化时便不会再通知Activity
。 -
LiveData
类已经帮我们做了很多事了,所有必要的注册逻辑都封装在里面了,我们只需要调用一个observe
方法即可。 -
LiveData
类提供了两个刷新数据的方法,分别是setValue
和postValue
,前者必须在主线程中调用,后者没有线程限制会自动post到主线程中。 - 多个界面可以共享一个
LiveData
对象,当数据发生变化时,这些界面都可以观测到,适应于全局性的数据(比如用户信息)。
ViewModel
之前已经讲过,VM的作用类似于C、P,这里不再过多描述。Android中提供了两个VM相关的基础类,分别是ViewModel
和AndroidViewModel
,后者比前者多了一个Application
上下文对象。查看ViewModel
的代码,会发现代码非常简单,就一个空方法onCleared
,因此如果是手动new
一个ViewModel
对象那就没什么意义了。创建ViewModel
对象可以使用ViewModelProvider
(使用ViewModelProviders
创建ViewModelProvider
对象),这样创建出来的ViewModel
对象便有了管理者,会在适当的时机调用它的onCleared
方法以便开发者清理资源。另外,ViewModelProvider
会根据key缓存ViewModel
对象。
下面来看下使用ViewModel
重构后的代码:
UserViewModel.java
public class UserViewModel extends AndroidViewModel implements UserBusiness.UserListener {
private UserBusiness mUserBusiness = UserBusiness.get();
private UserLiveData mUserLiveData;
public UserViewModel(@NonNull Application application) {
super(application);
}
public void observe(LifecycleOwner owner, Observer observer) {
// 加载数据库缓存中的用户信息
User user = mUserBusiness.getUser();
mUserLiveData = new UserLiveData();
// LiveData注册对Activity的监听,同时Activity注册对LiveData的监听
mUserLiveData.observe(owner, observer);
// 更新LiveData中的数据
mUserLiveData.postValue(user);
mUserBusiness.addListener(this);
}
@Override
protected void onCleared() {
mUserBusiness.removeListener(this);
super.onCleared();
}
@Override
public void onRequestUserResult(int code, User user) {
if(code == 0) {
// 更新LiveData中的数据
mUserLiveData.postValue(user);
} else {
Toast.makeText(getApplication(), "刷新失败", Toast.LENGTH_SHORT).show();
}
}
public void refresh() {
mUserBusiness.requestUser();
}
}
UserActivity.java
public class UserActivity extends FragmentActivity implements Observer {
private TextView mNameView;
private TextView mAgaView;
private UserViewModel mViewModel;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user);
mNameView = findViewById(R.id.tv_name);
mAgaView = findViewById(R.id.tv_age);
findViewById(R.id.btn_refresh).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mViewModel.refresh();
}
});
mViewModel = ViewModelProviders.of(this).get(UserViewModel.class);
mViewModel.observe(this, this);
}
@Override
public void onChanged(@Nullable User user) {
// LiveData中的数据更新,在这里刷新UI,这个方法是在主线程中调用的,可放心刷新UI
mNameView.setText("昵称:" + user.name);
mAgaView.setText("年龄:" + user.age);
}
}
至此,我们的Activity
又成功地从控制层+视图层转变成单纯的视图层了。
AAC结合DataBinding
通过上面的几次重构,我们的代码已经分层得很好了,下面直接贴代码:
activity_user.xml
UserViewModel.java
public class UserViewModel extends AndroidViewModel implements UserBusiness.UserListener, Observer {
private UserBusiness mUserBusiness = UserBusiness.get();
private UserLiveData mUserLiveData;
private User mUser;
public UserViewModel(@NonNull Application application) {
super(application);
}
public void observe(LifecycleOwner owner, ActivityUserBinding binding) {
// 加载数据库缓存中的用户信息
mUser = mUserBusiness.getUser();
if(mUser == null) {
mUser = new User();
}
binding.setUser(mUser);
binding.setHost(this);
mUserLiveData = new UserLiveData();
// LiveData注册对Activity的监听,同时Activity注册对LiveData的监听
mUserLiveData.observe(owner, this);
// 更新LiveData中的数据
mUserLiveData.postValue(mUser);
mUserBusiness.addListener(this);
}
@Override
protected void onCleared() {
Log.i("sean_vm", "onCleared");
mUserBusiness.removeListener(this);
super.onCleared();
}
@Override
public void onRequestUserResult(int code, User user) {
if(code == 0) {
// 更新LiveData中的数据
mUserLiveData.postValue(user);
} else {
Toast.makeText(getApplication(), "刷新失败", Toast.LENGTH_SHORT).show();
}
}
public void onRefresh(View v) {
mUserBusiness.requestUser();
}
@Override
public void onChanged(@Nullable User user) {
mUser.setName(user.name);
mUser.setAge(user.age);
}
}
UserActivity.java
public class UserActivity extends FragmentActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityUserBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_user);
ViewModelProviders.of(this).get(UserViewModel.class).observe(this, binding);
}
}
可以看到Activity
已经没什么代码了,它完全成了一个载体,视图部分交给xml布局,而控制逻辑交给ViewModel
。