AAC全稱Android Architecture Components,是Android官方推出的MVVM架構(gòu)指導(dǎo)方案召嘶。我們知道Android官方之前為了支持MVVM已經(jīng)推出了DataBinding方案,AAC與DataBinding之間沒有任何關(guān)系哮缺,但它們可以結(jié)合使用弄跌。在閱讀本文后續(xù)內(nèi)容前可以先看下Android架構(gòu)模式之MVC、MVP尝苇、MVVM這篇文章铛只,本文后面所描述的例子是以該文章的例子為基礎(chǔ)的。
使用AAC需要導(dǎo)入如下依賴:
compile "android.arch.lifecycle:runtime:1.1.1"
compile "android.arch.lifecycle:extensions:1.1.1"
annotationProcessor "android.arch.lifecycle:compiler:1.1.1"
網(wǎng)上不少文章都是基于1.0.0版本進行講解糠溜,本文則是基于寫此文章時最新的1.1.1版本淳玩,兩個版本之間還是有不少差異性且1.1.1沒有完全兼容1.0.0,讀者需要注意非竿。
AAC主要包含如下東西:
Lifecycle
Lifecycle一看就是用來管理生命周期的凯肋,它負責(zé)將Activity/Fragment的生命周期同步給其它模塊,主要飽含三種角色:
- Lifecycle:生命周期本身汽馋,其它模塊(
LifecycleObserver
)可以對其進行觀測侮东,以便在狀態(tài)發(fā)生變化時接收通知,同時也可以主動從這里獲取當前狀態(tài)豹芯。 - LifecycleOwner:
Lifecycle
的持有者悄雅,一般為上下文對象,比如Activity
和Fragment
铁蹈,因為生命周期就是從它們這里同步出去的宽闲。 - LifecycleObserver:生命周期觀察者,觀察者通過向
Lifecycle
注冊來監(jiān)聽生命周期的變化握牧。
一個簡單的流程如下:
-
Activity
或Fragment
實現(xiàn)LifecycleOwner
接口容诬,創(chuàng)建并持有Lifecycle
對象。 - 某模塊實現(xiàn)
LifecycleObserver
接口沿腰,并將自身注冊到步驟1創(chuàng)建的Lifecycle
對象中览徒,以便觀察Activity
或Fragment
生命周期的變化。 - 生命周期變化時颂龙,
Activity
或Fragment
將狀態(tài)同步給Lifecycle
對象习蓬。 -
Lifecycle
對象dispatch
事件給所有LifecycleObserver
對象。
在1.1.1版本中措嵌,FragmentActivity
和Fragment
已經(jīng)集成了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
中處理的邏輯代碼,因此它需要監(jiān)聽Activity
的生命周期浪规,所以它實現(xiàn)了LifecycleObserver
或听。 -
UserActivity
繼承了FragmentActivity
而不是Activity
是因為前者集成了Lifecycle
而后者沒有,它扮演的是LifecycleOwner
的角色罗丰,且是Lifecycle
的創(chuàng)建者和持有者神帅。 -
Lifecycle
對象的實際類型是LifecycleRegistry
。 - 生命周期的分發(fā)我們不需要關(guān)心萌抵,想了解原理的自行查看源碼找御,我們需要關(guān)心的是
Observer
如何接收生命周期的變化。這里使用OnLifecycleEvent
注解绍填,該注解只有一個參數(shù)霎桅,表示生命周期變化對應(yīng)的事件,所有事件在代碼中都列出來了讨永,看事件名就可以知道對應(yīng)哪個生命周期了滔驶,這里不再多說。當生命周期發(fā)生變化時卿闹,Observer
中對應(yīng)的方法會被調(diào)用揭糕,其中ANY
是比較特殊的萝快,每次生命周期發(fā)生變化時都會在原事件觸發(fā)后觸發(fā)。 - CREATE/START/RESUME事件由
Owner
先觸發(fā)著角,Observer
后觸發(fā)揪漩;PAUSE/STOP/DESTROY由Observer
先觸發(fā),Owner
后觸發(fā)吏口。
UserController
之后會被廢棄奄容,因為AAC是MVVM模式的應(yīng)用,后面會使用ViewModel來代替UserController
产徊。之所以本例中使用UserController
昂勒,是為了排除其它干擾因素,能更直接地理解和掌握Lifecycle
舟铜。
LiveData
LiveData
是一個可被觀察的數(shù)據(jù)持有者戈盈,即它既是一個Observable
(被觀察者/發(fā)布者),同時持有數(shù)據(jù)模型(或者本身作為數(shù)據(jù)模型也可以)深滚,它的Observer
(觀察者)通常都是控制層對象(如Activity
或Fragment
)奕谭。與一般的Observable
不同,LiveData
能知道Observer
的生命周期變化痴荐,這意味著它能同步到Activity
血柳、Fragment
等組件的生命周期,這確保了LiveData
只更新處于活躍狀態(tài)的Observer
生兆。
如果一個
Observer
的生命周期處于非DESTROYED
狀態(tài)時难捌,那么LiveData
將認為這個Observer
處于活躍狀態(tài)。LiveData
僅通知活躍的Observer
去更新UI鸦难。非活躍狀態(tài)的Observer
根吁,即使訂閱了LiveData
,也不會收到更新的通知合蔽。
之后為了簡化語言和便于直觀理解击敌,我們以Activity作為控制層來講解,即之后提到的Activity同時代表控制層及LiveData
的觀察者拴事。
我們上面提到LiveData
可以觀察到Activity
的生命周期變化沃斤,同時它的數(shù)據(jù)變化也能夠被Activity
觀測到,因此LiveData
和Activity
互為觀察者刃宵。
-
LiveData
作為觀察者時:根據(jù)前面Lifecycle
所掌握到的知識衡瓶,LiveData
要觀察Activity
就需要實現(xiàn)LifecycleObserver
,同時將自身注冊到Activity
中牲证。 -
LiveData
作為被觀察者時:它需要保存觀察者的集合哮针,提供注冊和反注冊的方法。Android中已經(jīng)提供了兩個LiveData
相關(guān)的類,分別是LiveData
和MutableLiveData
十厢,提供了作為被觀察者需要的方法等太,同時也提供了第1點提到的注冊自身的方法,二者的區(qū)別是前者的數(shù)據(jù)不可變寿烟,后者可變澈驼。因此,我們在應(yīng)用LiveData
時筛武,只需要根據(jù)情況選擇繼承它們其一即可。如沒有特別說明挎塌,
LiveData
指概念本身徘六,而非具體的類。 -
Activity
作為被觀察者時:需要實現(xiàn)LifecycleOwner
接口榴都,根據(jù)前面掌握的知識待锈,實際上只需要繼承FragmentActivity
即可。 -
Activity
作為觀察者時:需要實現(xiàn)Observer
嘴高,并注冊到LiveData
中竿音。
結(jié)合Lifecycle
和LiveData
在之前MVC的基礎(chǔ)上進行重構(gòu)肿男,代碼如下:
UserLiveData.java
public class UserLiveData extends MutableLiveData<User> {
}
UserActivity.java
public class UserActivity extends FragmentActivity implements Observer<User>, 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) {
// 向服務(wù)器請求最新用戶信息
mUserBusiness.requestUser();
}
});
// 加載數(shù)據(jù)庫緩存中的用戶信息
User user = mUserBusiness.getUser();
mUserLiveData = new UserLiveData();
// LiveData注冊對Activity的監(jiān)聽床绪,同時Activity注冊對LiveData的監(jiān)聽
mUserLiveData.observe(this, this);
// 更新LiveData中的數(shù)據(jù)
mUserLiveData.postValue(user);
mUserBusiness.addListener(this);
}
@Override
protected void onDestroy() {
mUserBusiness.removeListener(this);
super.onDestroy();
}
@Override
public void onChanged(@Nullable User user) {
// LiveData中的數(shù)據(jù)更新抖部,在這里刷新UI洞拨,這個方法是在主線程中調(diào)用的骤竹,可放心刷新UI
mNameView.setText("昵稱:" + user.name);
mAgaView.setText("年齡:" + user.age);
}
@Override
public void onRequestUserResult(int code, User user) {
if(code == 0) {
// 更新LiveData中的數(shù)據(jù)
mUserLiveData.postValue(user);
} else {
Toast.makeText(this, "刷新失敗", Toast.LENGTH_SHORT).show();
}
}
}
分析一下:
-
LiveData
的observe
方法內(nèi)部進行了雙向注冊固蛾,Activity
觀察LiveData
的數(shù)據(jù)變化改化,數(shù)據(jù)變化時會觸發(fā)Activity.onChange
方法逆趋;LiveData
觀察Activity
生命周期的變化潜沦,當生命周期狀態(tài)變更為DESTROYED時(Activity.onDestroy
)萄涯,移除Activity
在LiveData
中的注冊信息,后續(xù)發(fā)生數(shù)據(jù)變化時便不會再通知Activity
唆鸡。 -
LiveData
類已經(jīng)幫我們做了很多事了涝影,所有必要的注冊邏輯都封裝在里面了,我們只需要調(diào)用一個observe
方法即可争占。 -
LiveData
類提供了兩個刷新數(shù)據(jù)的方法燃逻,分別是setValue
和postValue
,前者必須在主線程中調(diào)用燃乍,后者沒有線程限制會自動post到主線程中唆樊。 - 多個界面可以共享一個
LiveData
對象,當數(shù)據(jù)發(fā)生變化時刻蟹,這些界面都可以觀測到逗旁,適應(yīng)于全局性的數(shù)據(jù)(比如用戶信息)。
ViewModel
之前已經(jīng)講過,VM的作用類似于C片效、P红伦,這里不再過多描述。Android中提供了兩個VM相關(guān)的基礎(chǔ)類淀衣,分別是ViewModel
和AndroidViewModel
昙读,后者比前者多了一個Application
上下文對象。查看ViewModel
的代碼膨桥,會發(fā)現(xiàn)代碼非常簡單蛮浑,就一個空方法onCleared
,因此如果是手動new
一個ViewModel
對象那就沒什么意義了只嚣。創(chuàng)建ViewModel
對象可以使用ViewModelProvider
(使用ViewModelProviders
創(chuàng)建ViewModelProvider
對象)沮稚,這樣創(chuàng)建出來的ViewModel
對象便有了管理者,會在適當?shù)臅r機調(diào)用它的onCleared
方法以便開發(fā)者清理資源册舞。另外蕴掏,ViewModelProvider
會根據(jù)key緩存ViewModel
對象。
下面來看下使用ViewModel
重構(gòu)后的代碼:
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<User> observer) {
// 加載數(shù)據(jù)庫緩存中的用戶信息
User user = mUserBusiness.getUser();
mUserLiveData = new UserLiveData();
// LiveData注冊對Activity的監(jiān)聽调鲸,同時Activity注冊對LiveData的監(jiān)聽
mUserLiveData.observe(owner, observer);
// 更新LiveData中的數(shù)據(jù)
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中的數(shù)據(jù)
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<User> {
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中的數(shù)據(jù)更新盛杰,在這里刷新UI,這個方法是在主線程中調(diào)用的藐石,可放心刷新UI
mNameView.setText("昵稱:" + user.name);
mAgaView.setText("年齡:" + user.age);
}
}
至此即供,我們的Activity
又成功地從控制層+視圖層轉(zhuǎn)變成單純的視圖層了。
AAC結(jié)合DataBinding
通過上面的幾次重構(gòu)贯钩,我們的代碼已經(jīng)分層得很好了募狂,下面直接貼代碼:
activity_user.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="user"
type="com.sean.mvvm.model.entity.User" />
<variable
name="host"
type="com.sean.mvvm.UserViewModel"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text='@={user.name}'
android:id="@+id/tv_name"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text='@{"年齡:" + String.valueOf(user.age)}'/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_marginTop="20dp"
android:text="刷新"
android:onClick="@{host.onRefresh}"/>
</LinearLayout>
</layout>
UserViewModel.java
public class UserViewModel extends AndroidViewModel implements UserBusiness.UserListener, Observer<User> {
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) {
// 加載數(shù)據(jù)庫緩存中的用戶信息
mUser = mUserBusiness.getUser();
if(mUser == null) {
mUser = new User();
}
binding.setUser(mUser);
binding.setHost(this);
mUserLiveData = new UserLiveData();
// LiveData注冊對Activity的監(jiān)聽,同時Activity注冊對LiveData的監(jiān)聽
mUserLiveData.observe(owner, this);
// 更新LiveData中的數(shù)據(jù)
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中的數(shù)據(jù)
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
已經(jīng)沒什么代碼了角雷,它完全成了一個載體祸穷,視圖部分交給xml布局,而控制邏輯交給ViewModel
勺三。