Android 專案最新架構

拉丁吳發表於2017-07-02

0.前言

為了幫助開發者打造一款優秀的APP,Google可謂費盡心力,推出了各種諸如MVP,MVVM等等專案架構的思路,幫助開發者更加高效的開發,儘管這樣,Google還是接著推出了一個新的專案架構,以便給予開發者更多的選擇,至於這種架構思路和MVP等框架的優劣,各位看完文章或許自有定論。

1.生命週期

在移動作業系統上開發軟體其實是十分複雜的一件事情,因為我們隨時需要面對系統和使用者的各種不可預料的操作,很多時候,事情並不向著我們預設的方向方向進展。因此係統向我們提供了核心元件的生命週期這種東西,告知我們的APP正處在什麼樣的狀況中,以便於我們做出相應的處理。

Android 專案最新架構

如上圖。雖然Google給出了Activity非常詳盡的生命週期結構,因此我們對根據生命週期做出相應的合理的安排,比如新增和移除實時GPS位置監聽:

Android 專案最新架構

可是隨著業務的逐漸複雜,我們可能在新增監聽之間需要向伺服器驗證某些使用者資訊,等返回資訊正確才去監聽定位。那麼在網路非同步回撥的時候,我們就很難知道當前的activity的生命週期狀態。

Android 專案最新架構

如果發生上圖的情況,那麼我們的佔用的相關資源就可能永遠無法移除了。這還只是冰山一角,大家儘可以想想,當我們的非同步呼叫面對無法預知的使用者操作和系統處理的時候,什麼問題都可能發生。

總而言之,由於我們對於UI實時的狀態做不到了如指掌,以至於對資料和邏輯的處理就無法盡善盡美。這是類似隱患得不到很好的解決根本原因。

2. Google大禮包

這次Google推出了一套新的專案架構元件和架構思路,從UI到Data,幫助我們更加精準的開發自己的APP。

2.1 核心:Lifecycle Components

這套架構最核心的就是生命週期元件,:Lifecycle Components用於管理UI控制器(Activity/Freagment)的生命週期,方便查詢當前元件生命週期的狀態。

可查詢的狀態如下:

Android 專案最新架構

具體的使用方式有兩種:

  • 繼承LifecycleActivity/LifecycleFragment即可
  • 自己實現LifecycleRegistryOwner介面

java

// 通過繼承,就已經將自己的生命週期的交給了Lifecycle Components管理了。
public class MainActivity extends LifecycleActivity {

}
複製程式碼

那我們如何使用呢?

// 通過繼承LifecycleObserver,保證我們可以通過註解或者介面查詢UI的生命週期
public class MyTest implements LifecycleObserver {
    private Lifecycle lifecycle;
    // Lifecycle包含了當前元件的生命週期
    public MyTest(Lifecycle lifecycle){
        lifecycle.addObserver(this);
        this.lifecycle=lifecycle;
    }

// 當onResume發生的時候,該方法被呼叫
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void resume(){
        Log.i("TAG","it called when resume ");
    }

    public void doTest(String s){
        // 隨時可以查詢當前的UI狀態
        if(lifecycle.getCurrentState().equals(Lifecycle.State.RESUMED)){
            Log.i("TAG","resume");
        }else{
            Log.i("TAG","is not resume !! ");
        }
    }

}


public class MainActivity extends LifecycleActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //將當前Activity的生命週期傳遞到MyTest中即可
        MyTest myTest=new MyTest(this.getLifecycle());
    }
}
複製程式碼

看到這裡,你一定心頭一喜,如果有這個元件,那麼我們就完全有能力將Activity作為一個UI的控制器,僅僅用來顯示UI和相應使用者操作,把Activity的大小縮小至最小。不用著急,大禮包遠不止這些。

3.ViewModel和LiveData

  • ViewModel 是一個UI相關資料的暫存器,當所有相關的UI都finish掉的時候,它才會清除自己的資料。
  • LiveData則是一個持有具體資料並且可被觀察,能感知生命週期的元件(它就像RxJava中一個能遵循元件生命週期的Observable)

他倆的關係,就是,ViewModel負責管理著不同的LiveData,並把它提供給UI。

3.1 LiveData

我們可以先來說說LiveData。由於它已經能夠感知生命週期,也就意味著我們並不需要在去查詢當前UI的生命週期,由於可被觀察,也就意味著當它持有的資料發生改變,觀察者可以立即受到資訊。livedata最重要的方法是一下幾個:

 onActive() // 當前LiveData有超過一個的活躍的觀察者時,被呼叫

onInactive() // 當前沒有任何活躍的觀察時,著被呼叫

setValue()  // 勇於改變當前資料,這樣觀察者可以受到改變後的資料。

// 觀察資料變化,並感知當前UI的生命週期
observe(LifecycleOwner owner, Observer<T> observer) 
複製程式碼

這裡有一個活躍的觀察者的概念,我們不妨把它放在後面來看。LiveData的用法如下:

public class LocationLiveData extends LiveData<Location> {
    private LocationManager locationManager;

    private SimpleLocationListener listener = new SimpleLocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            setValue(location);
        }
    };

    public LocationLiveData(Context context) {
        locationManager = (LocationManager) context.getSystemService(
                Context.LOCATION_SERVICE);
    }

    @Override
    protected void onActive() {
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener);
    }

    @Override
    protected void onInactive() {
        locationManager.removeUpdates(listener);
    }
}



public class MainActivity extends LifecycleActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        LiveData<Location> myLocationListener = new LocationLiveData();
        /*
        * observe(LifecycleOwner owner, Observer<T> observer)
        * 這個方法就是向LiveData中新增觀察者,
        * LiveData則可以通過LifecycleOwner來判斷
        * 當前傳入的觀察者是否是活躍的(也就是UI是否可見了)
        */
        myLocationListener.observe(this, new Observer<Location>() {
            @Override
            public void onChanged(@Nullable Location location) {
                // update
                //當LiveData中通過setValue()修改了資料時,
                //這裡將會受到修改後的資料
            }
        });
    }
}

複製程式碼

好了,LiveData基本的用法講完了,由於有了LiveData,我們的data更加“智慧”了。當UI不可見的時候,改變的資料將不會被更新到UI上。

而且如果資料在不同的UI介面都會被用到的時候,我們還可以一個單例的LiveData,為不同的UI提供統一的資料。這些操作就不去細講了。

現在回頭看LiveData,我們發現它至少有以下幾個優點:

  • 可以避免記憶體洩露:由於 Observer 和 Lifecycle 繫結,當 Lifecycle 被銷燬後,Observer 自動被清理。
  • 避免在 Activity 被銷燬後更新資料導致的崩潰情況
  • 資料可共享
  • 資料更新更智慧:當資料在UI不可見的時候更新了,在恢復可見的時候,最新的資料會及時更新到UI上。
  • 不需要在Activity中額外處理生命週期事件

一顆賽艇!

3.2 ViewModel

ViewModel則相對簡單些,因為他的作用是暫存UI相關的資料,保證即使Activity配置更改,重新建立時,資料依然能夠被儲存好。

基本用法如下:

public class MyViewModel extends ViewModel {
    // MyViewModel用於管理不同的LiveData
    private MutableLiveData<List<User>> users;
    public LiveData<List<User>> getUsers() {
        if (users == null) {
            users = new MutableLiveData<List<Users>>();
            loadUsers();
        }
        return users;
    }

    private void loadUsers() {
        // do async operation to fetch users
    }
}

public class MyActivity extends AppCompatActivity {
    public void onCreate(Bundle savedInstanceState) {
    // 通過了ViewModelProviders來獲取ViewModel
    // 使用者獲取和Activity繫結的ViewModel
        MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
        model.getUsers().observe(this, users -> {
            // update UI
        });
    }
}

複製程式碼

這是ViewModel的最基本的用法,它負責從各個地方獲取資料,然後把資料裝到LiveData中,提供給UI;當然ViewModel也可以在不同的Fragment中共享,在這裡就不多講了。

由於ViewModel的本身和activity/fragment的生命週期繫結,當與之繫結的UI控制器被銷燬時,ViewModel才會clean自身的資料。

如圖所示

Android 專案最新架構

4.資料持久化:Room

Room是Google提供的SQLite的ORM的解決方案,其實本質上和其他的ORM框架沒什麼特別大的差別,沒有太多新意,因此只給出大體的架構圖,有興趣的同學可以自行去學習

Android 專案最新架構

5.總結

我們現在回頭看整個架構

Android 專案最新架構

其實最有有趣的就是UI-ViewModel這個部分,這套架構至少可以幫助我們做到一下幾點:

  • UI與Data真正分離
  • 非同步呼叫和邏輯控制可以更加精細(因為對生命週期感知更多)
  • 實現Model驅動UI

6.勘誤

暫無

附錄

android官網: developer.android.com/topic/libra…

相關文章