Android Architecture Components
開發(fā)者經(jīng)常面臨的問(wèn)題
Android應(yīng)用由四大組件構(gòu)成,各組件可以被獨(dú)立且無(wú)序的調(diào)起,用戶會(huì)在各個(gè)App之間來(lái)回切換。組件啟動(dòng)后,生命周期會(huì)受用戶的操作和系統(tǒng)影響,不完全受開發(fā)者控制。而由于設(shè)備內(nèi)存問(wèn)題,進(jìn)程隨時(shí)可能被系統(tǒng)強(qiáng)殺,所以不要將數(shù)據(jù)和狀態(tài)直接存儲(chǔ)在組件中,也不要讓組件互相依賴。
問(wèn)題實(shí)例
-
內(nèi)存泄漏:在Activity中發(fā)起網(wǎng)絡(luò)請(qǐng)求,在網(wǎng)絡(luò)請(qǐng)求返回之前退出Activity, 那么Activity就被泄漏了。
-
崩潰:Activity destroy后,還被其他類操作,從而引發(fā)崩潰,例如Glide圖片庫(kù);
-
Activity類臃腫:數(shù)據(jù),邏輯,控件代碼都堆積在Activity中,導(dǎo)致Activity臃腫,不易維護(hù)和測(cè)試。
-
Fragment通信困難:開發(fā)中經(jīng)常會(huì)遇到Activity中含有多個(gè)Fragment的情況, 并且Fragment之間需要通信。通常會(huì)利用Activity轉(zhuǎn)發(fā)Fragment之間的通信,而且Fragment之間還需要依賴對(duì)方的生命周期和通信細(xì)節(jié)。
-
數(shù)據(jù)易銷毀:如果將內(nèi)存中的數(shù)據(jù)保存在Activity中,由于Activity很容易被銷毀重建(配置改變,內(nèi)存不夠),那么數(shù)據(jù)也就很容易被銷毀。
通用的框架原則
-
關(guān)注點(diǎn)分離:不要在Activity/Fragment中添加非UI控制、非系統(tǒng)接口調(diào)用的代碼。盡量讓他們保持精煉,以免引起生命周期相關(guān)的問(wèn)題。這些類是系統(tǒng)創(chuàng)建和管理的,并不完全受開發(fā)者控制。
-
模型驅(qū)動(dòng)UI:應(yīng)該用數(shù)據(jù)模型驅(qū)動(dòng)UI展示,最好是持久模型,因?yàn)楫?dāng)系統(tǒng)強(qiáng)殺進(jìn)程或者網(wǎng)絡(luò)不穩(wěn)定時(shí),持久模型能讓程序繼續(xù)工作。模型獨(dú)立于組件之外,不會(huì)受到生命周期的影響。
應(yīng)用框架組件
Android官方在17年IO大會(huì)上發(fā)布了一套框架組件,幫助開發(fā)者開發(fā)優(yōu)質(zhì)的App.
LifeCycle
將Activity/Fragment的生命周期剝離到其他類中,減少組件類中的代碼。
LifeCycle用兩個(gè)枚舉類追蹤組件的狀態(tài)。
- Event:從Framework層分發(fā)的,匹配Activity和Fragment中的生命周期方法回調(diào)。
- State:當(dāng)前組件的狀態(tài)。
使用方式
public class LearnLifeCycleObserver implements LifecycleObserver {@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)public void onCreate() {}@OnLifecycleEvent(Lifecycle.Event.ON_STOP)public void onStop() {} }public class LearnLifeCycleActivity extends AppCompatActivity {@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);getLifecycle().addObserver(new LearnLifeCycleObserver());} }實(shí)踐
-
將UI和數(shù)據(jù)分離,UI層不需要持有數(shù)據(jù)。
-
構(gòu)建數(shù)據(jù)驅(qū)動(dòng)UI的應(yīng)用,UI控制器負(fù)責(zé)根據(jù)數(shù)據(jù)更新UI以及將用戶的操作反饋給數(shù)據(jù)層。
-
將數(shù)據(jù)邏輯放在ViewModel中,將數(shù)據(jù)拉取邏輯放在數(shù)據(jù)倉(cāng)庫(kù)(Data Repository)中.
-
使用MVP模式,引入Presenter, 讓程序更加容易被測(cè)試。
LiveData
一個(gè)自帶觀察者模式的數(shù)據(jù)封裝類,不同的是LiveData有生命周期,會(huì)利用LifeCycle自動(dòng)監(jiān)聽與它綁定的組件的生命周期。當(dāng)數(shù)據(jù)發(fā)生改變時(shí),Activity或者Fragment要處于活動(dòng)狀態(tài),觀察者才會(huì)接收到數(shù)據(jù)改變的回調(diào),此時(shí)界面就可以安全的進(jìn)行渲染,而不會(huì)出現(xiàn)Activity銷毀后還更改界面的情況。
優(yōu)點(diǎn)
- 不會(huì)造成泄漏內(nèi)存。
- 不會(huì)由于操作銷毀的Activity而發(fā)生崩潰。
- 不需要手動(dòng)處理生命周期。
- 數(shù)據(jù)總能實(shí)時(shí)更新。
- 數(shù)據(jù)不會(huì)受configuration更改的影響。
- 易于共享數(shù)據(jù)。
使用
final MutableLiveData<String> userNameLiveData = new MutableLiveData<>();userNameLiveData.observe(this, new Observer<String>() {@Overridepublic void onChanged(@Nullable String s) {//Activity的lifecycle state處于STARTED或RESUMED時(shí)才會(huì)回調(diào)mUserNameTV.setText(s);} });mUserNameSetBtn.setOnClickListener(new View.OnClickListener(){@Overridepublic void onClick(View v) {//更新LiveData的數(shù)據(jù),以嘗試觸發(fā)觀察者的通知userNameLiveData.setValue("jayden");} });兩個(gè)擴(kuò)展類
MutableLiveData
開放了setValue和postValue方法,用于主動(dòng)改變LiveData的值,并通知觀察者。
MediatorLiveData
可以同時(shí)觀察多個(gè)LiveData, 當(dāng)被觀察的LiveData發(fā)生改變時(shí),可以對(duì)LiveData的數(shù)據(jù)進(jìn)行加工后再通知MediatorLiveData.
轉(zhuǎn)換LiveData
Transformations#map
利用MediatorLiveData將LiveData的數(shù)據(jù)加工后再通知給觀察者。
LiveData<User> userLiveData = ...; LiveData<String> userName = Transformations.map(userLiveData, user -> {user.name + " " + user.lastName });Transformations#switchMap
和map方法類似,而且也是用MediatorLiveData實(shí)現(xiàn)。但是switchMap方法的第二個(gè)形參接口的返回值是LiveData. 如下代碼塊中的例子,當(dāng)userId發(fā)生改變后,getUser(id)返回另一個(gè)LiveData: liveData1, user的觀察者開始觀察liveData1的變化。
舉個(gè)例子:id為1的用戶切換成id為2的用戶后,getUser(id)方法返回的LiveData就是id為2的用戶的用戶信息,以后如果id為2的用戶信息發(fā)生改變,user的觀察者就會(huì)接收到通知。
private LiveData<User> getUser(String id) {...; }LiveData<String> userId = ...; LiveData<User> user = Transformations.switchMap(userId, id -> getUser(id) );ViewModel
用來(lái)存儲(chǔ)和管理和UI相關(guān)的有生命周期的數(shù)據(jù)。當(dāng)Configuration改變,例如屏幕旋轉(zhuǎn),語(yǔ)言切換時(shí),ViewModel中的數(shù)據(jù)不會(huì)被銷毀,是一個(gè)不會(huì)被濫用的單例。
創(chuàng)建ViewModel
利用LiveData持有數(shù)據(jù)
public class MyViewModel extends ViewModel {private MutableLiveData<List<User>> mObservableUsers;public MyViewModel(){mObservableUsers = new MutableLiveData<List<Users>>();}public LiveData<List<User>> getUsers() {return mObservableUsers;}private void loadUsers() {// 異步加載數(shù)據(jù)后通知到users中。...mObservableUsers.setValue(users)} }在Activity中監(jiān)聽數(shù)據(jù)改變
public class MyActivity extends AppCompatActivity {public void onCreate(Bundle savedInstanceState) {MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);//監(jiān)聽LiveDatamodel.getUsers().observe(this, users -> {// update UI});} }如果由于屏幕旋轉(zhuǎn)或語(yǔ)言切換導(dǎo)致Activity重建,ViewModelProviders.of(this).get(MyViewModel.class);獲取的ViewModel還是Activity首次創(chuàng)建時(shí)所構(gòu)建的,只有當(dāng)Activity銷毀后,ViewModel才會(huì)被清除。
ViewModel的生命周期
在多個(gè)Fragment中共享數(shù)據(jù)
public class SharedViewModel extends ViewModel {private final MutableLiveData<Item> selected = new MutableLiveData<Item>();public void select(Item item) {selected.setValue(item);}public LiveData<Item> getSelected() {return selected;} }public class MasterFragment extends Fragment {private SharedViewModel model;public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);itemSelector.setOnClickListener(item -> {model.select(item);});} }public class DetailFragment extends Fragment {public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);model.getSelected().observe(this, { item ->// Update the UI.});} }兩個(gè)Fragment拿到的ViewModel對(duì)象是同一個(gè)。
這種方式的優(yōu)點(diǎn):
- Activity不需要了解Fragment之間的通信,完全松耦合。
- 兩個(gè)Fragment都不需要依賴對(duì)方的生命周期和通信細(xì)節(jié),即使一個(gè)Fragment被銷毀,也不會(huì)影響另一個(gè)Fragment.
最終的框架
推薦的框架原則
-
在Manifest文件中定義的程序入口:Activities, Services, BroadcastReceiver等,都不能作為數(shù)據(jù)的來(lái)源。
-
明確定義各模塊的職責(zé)。
-
盡可能少地暴露每個(gè)模塊的信息。
-
定義模塊間的交互時(shí),考慮如何讓他們易于測(cè)試。
-
將數(shù)據(jù)持久化,讓程序在離線時(shí)更加可用。
-
數(shù)據(jù)存儲(chǔ)庫(kù)應(yīng)該指定一個(gè)數(shù)據(jù)源作為單一的數(shù)據(jù)來(lái)源。
推薦閱讀
- 官網(wǎng)
- 官方Sample
總結(jié)
以上是生活随笔為你收集整理的Android Architecture Components的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: ODF光纤配线架
- 下一篇: 【转】Android 自己收集的开源项目