完整文章地址:App開發(fā)架構(gòu)指南(谷歌官方文檔譯文)
通用的架構(gòu)準(zhǔn)則
最重要的一個(gè)原則就是盡量在app中做到separation of concerns(關(guān)注點(diǎn)分離)。常見的錯(cuò)誤就是把所有代碼都寫在Activity或者Fragment中诈悍。任何跟UI和系統(tǒng)交互無關(guān)的事情都不應(yīng)該放在這些類當(dāng)中自沧。盡可能讓它們保持簡單輕量可以避免很多生命周期方面的問題柄慰。別忘了能并不擁有這些類踢械,它們只是連接app和操作系統(tǒng)的橋梁奸晴。根據(jù)用戶的操作和其它因素贱枣,比如低內(nèi)存监署,Android OS可能在任何時(shí)候銷毀它們。為了提供可靠的用戶體驗(yàn)纽哥,最好把對它們的依賴最小化钠乏。
第二個(gè)很重要的準(zhǔn)則是用model驅(qū)動(dòng)UI,最好是持久化的model春塌。之所以要持久化是基于兩個(gè)原因:如果OS銷毀app釋放資源晓避,用戶數(shù)據(jù)不會(huì)丟失;當(dāng)網(wǎng)絡(luò)很差或者斷網(wǎng)的時(shí)候app可以繼續(xù)工作摔笤。Model是負(fù)責(zé)app數(shù)據(jù)處理的組件够滑。它們不依賴于View或者app 組件(Activity,F(xiàn)ragment等)吕世,因此它們不會(huì)受那些組件的生命周期的影響彰触。保持UI代碼的簡單,于業(yè)務(wù)邏輯分離可以讓它更易管理命辖。
分離出Repository
ViewModel的一個(gè)簡單的實(shí)現(xiàn)方式是直接調(diào)用Webservice獲取數(shù)據(jù)况毅,然后把它賦值給User對象分蓖。雖然這樣可行,但是隨著app的增大會(huì)變得難以維護(hù)尔许。ViewModel的職責(zé)過多也違背了前面提到的關(guān)注點(diǎn)分離(separation of concerns)原則么鹤。另外,ViewModel的有效時(shí)間是和Activity和Fragment的生命周期綁定的味廊,因此當(dāng)它的生命周期結(jié)束便丟失所有數(shù)據(jù)是一種不好的用戶體驗(yàn)蒸甜。相反,我們的ViewModel將把這個(gè)工作代理給Repository模塊余佛。
緩存數(shù)據(jù)
UserRepository的問題在于當(dāng)獲取完數(shù)據(jù)之后柠新,它并沒有把數(shù)據(jù)保存下來。如果用戶離開UserProfileFragment然后在回來辉巡,app會(huì)重新獲取數(shù)據(jù)恨憎。這是很不好的,原因有二:1.浪費(fèi)了帶寬資源郊楣,2.用戶被迫等待新的查詢完成憔恳。為了解決這個(gè)問題,我們向UserRepository中添加了一個(gè)新的數(shù)據(jù)源净蚤,它將把User對象緩存到內(nèi)存中钥组。
暴露網(wǎng)絡(luò)狀態(tài)
在前面app架構(gòu)推薦一節(jié)中,為了保持例子的簡單塞栅,我們有意省略了網(wǎng)絡(luò)錯(cuò)誤以及加載狀態(tài)者铜。這一節(jié)我們將演示一種暴露網(wǎng)絡(luò)狀態(tài)的方法,使用一個(gè)Resource類來封裝數(shù)據(jù)以及數(shù)據(jù)的狀態(tài)放椰。
//a generic class that describes a data with a status
public class Resource<T> {
@NonNull public final Status status;
@Nullable public final T data;
@Nullable public final String message;
private Resource(@NonNull Status status, @Nullable T data, @Nullable String message) {
this.status = status;
this.data = data;
this.message = message;
}
public static <T> Resource<T> success(@NonNull T data) {
return new Resource<>(SUCCESS, data, null);
}
public static <T> Resource<T> error(String msg, @Nullable T data) {
return new Resource<>(ERROR, data, msg);
}
public static <T> Resource<T> loading(@Nullable T data) {
return new Resource<>(LOADING, data, null);
}
}