Android架構之AAC

一、AAC簡介

AAC全稱Android Architecture Components,是Android官方推出的MVVM架構指導方案。Android官方之前為了支持MVVM已經推出了DataBinding方案,AAC與DataBinding之間沒有任何關系,但它們可以結合使用。

二、使用AAC需要導入如下依賴:
 dependencies {
    def lifecycle_version = "2.3.1"

    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"

    implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"

    implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"

    //非java8使用
    //annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
    //java8使用
    implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
}
三、AAC主要包含:
1、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 :

public class UserActivity extends FragmentActivity implements Observer<User> {
    private final String TAB = "UserActivity";
    @Override
    protected void onCreate(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(TAB, msg);
    }

    @Override
    public void onChanged(User user) {

    }
}

UserController :

public class UserController implements LifecycleObserver {
    private Lifecycle mLifecycle;

    public UserController(Lifecycle lifecycle) {
        this.mLifecycle = lifecycle;
    }

    private void log(String msg) {
        Log.i("UserController", 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());
    }
}

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。

2、LiveData
2.1、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互為觀察者。

2.2、LiveData作為觀察者時:根據前面Lifecycle所掌握到的知識,LiveData要觀察Activity就需要實現LifecycleObserver,同時將自身注冊到Activity中。

2.3、LiveData作為被觀察者時:它需要保存觀察者的集合,提供注冊和反注冊的方法。Android中已經提供了兩個LiveData相關的類,分別是LiveData和MutableLiveData,提供了作為被觀察者需要的方法,同時也提供了第1點提到的注冊自身的方法,二者的區別是前者的數據不可變,后者可變。因此,在應用LiveData時,只需要根據情況選擇繼承它們其一即可。

如沒有特別說明,LiveData指概念本身,而非具體的類。

2.4、Activity作為被觀察者時:需要實現LifecycleOwner接口,根據前面掌握的知識,實際上只需要繼承FragmentActivity即可。
2.5、Activity作為觀察者時:需要實現Observer,并注冊到LiveData中。
結合Lifecycle和LiveData在之前MVC的基礎上進行重構,代碼如下:
UserLiveData:

public class UserLiveData extends MutableLiveData<User> {

}

UserActivity:

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) {
            // 向服務器請求最新用戶信息
            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對象,當數據發生變化時,這些界面都可以觀測到,適應于全局性的數據(比如用戶信息)。

3、ViewModel

之前已經講過,VM的作用類似于C、P,這里不再過多描述。Android中提供了兩個VM相關的基礎類,分別是ViewModel和AndroidViewModel,后者比前者多了一個Application上下文對象。
查看ViewModel的代碼,會發現代碼非常簡單,就一個空方法onCleared,因此如果是手動new一個ViewModel對象那就沒什么意義了。創建ViewModel對象可以使用ViewModelProvider(使用ViewModelProviders創建ViewModelProvider對象),這樣創建出來的ViewModel對象便有了管理者,會在適當的時機調用它的onCleared方法以便開發者清理資源。另外,ViewModelProvider會根據key緩存ViewModel對象。
使用ViewModel重構后的代碼:
UserViewModel:

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) {
    // 加載數據庫緩存中的用戶信息
    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();
 }
}

Activity又成功地從控制層+視圖層轉變成單純的視圖層了。

四、AAC結合DataBinding

通過上面的幾次重構,代碼已經分層得很好了,下面直接貼代碼:
目錄結構:


AAC方式實現的MVVM.png

XML布局:

<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="user"
            type="com.ecactus.androidappframework.mvvm2.model.User" />

        <variable
            name="host"
            type="com.ecactus.androidappframework.mvvm2.viewModel.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

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) {
        // 加載數據庫緩存中的用戶信息
        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("UserViewModel", "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

public class UserActivity extends FragmentActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user);
        ActivityUserBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_user);
        // 獲取ViewModel
        ViewModelProvider.AndroidViewModelFactory instance = ViewModelProvider.AndroidViewModelFactory
                        .getInstance(getApplication());
        UserViewModel userViewModel = new ViewModelProvider(this, instance).get(UserViewModel.class);
        userViewModel.observe(this,binding);
    }
}

這里只貼出了部分代碼,其他代碼在https://gitee.com/zyd_gitee/androidappframework.git
本文參考了https://www.haomeiwen.com/subject/uymjmqtx.html

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容