App 組件化/模塊化—Android 框架組件
來源:原創(chuàng) 時(shí)間:2017-10-27 瀏覽:0 次面臨越來越雜亂的 App 需求,Google 官方發(fā)布了Android 結(jié)構(gòu)組件庫(Android Architecture Components )。為開發(fā)者更好的開發(fā) App 供給了十分好的樣本。這個(gè)結(jié)構(gòu)里的組件是合作 Android 組件生命周期的,所以它能夠很好的躲避組件生命周期辦理的問題。今日我們就來看看這個(gè)庫的運(yùn)用。
通用的結(jié)構(gòu)原則
官方主張?jiān)诩軜?gòu) App 的時(shí)分遵從以下兩個(gè)原則:
重視別離
其間前期開發(fā) App 最常見的做法是在 Activity 或許 Fragment 中寫了許多的邏輯代碼,導(dǎo)致 Activity 或 Fragment 中的代碼很臃腫,十分不易保護(hù)?,F(xiàn)在許多 App 開發(fā)者都留意到了這個(gè)問題,所曾經(jīng)兩年 MVP 結(jié)構(gòu)就十分有商場,現(xiàn)在普及率也很高。
模型驅(qū)動(dòng)UI
模型耐久化的優(yōu)點(diǎn)就是:即便體系回收了 App 的資源用戶也不會(huì)丟掉數(shù)據(jù),而且在網(wǎng)絡(luò)不穩(wěn)定的情況下 App 仍然能夠正常地運(yùn)轉(zhuǎn)。然后確保了 App 的用戶體會(huì)。
?
App 結(jié)構(gòu)組件
結(jié)構(gòu)供給了以下幾個(gè)中心組件,我們將經(jīng)過一個(gè)實(shí)例來闡明這幾個(gè)組件的運(yùn)用。
ViewModel
LiveData
Room
假定要完成一個(gè)用戶信息展現(xiàn)頁面。這個(gè)用戶信息是經(jīng)過REST API 從后臺(tái)獲取的。
樹立UI
我們運(yùn)用 fragment (UserProfileFragment.java) 來完成用戶信息的展現(xiàn)頁面。為了驅(qū)動(dòng) UI,我們的數(shù)據(jù)模型需求持有以下兩個(gè)數(shù)據(jù)元素
用戶ID: 用戶的僅有標(biāo)識(shí)。能夠經(jīng)過 fragment 的 arguments 參數(shù)進(jìn)行傳遞這個(gè)信息。這樣做的優(yōu)點(diǎn)就是如果體系銷毀了運(yùn)用,這個(gè)參數(shù)會(huì)被保存而且下次從頭啟動(dòng)時(shí)能夠康復(fù)之前的數(shù)據(jù)。
用戶目標(biāo)數(shù)據(jù):POJO 持有用戶數(shù)據(jù)。
我們要?jiǎng)?chuàng)立 ViewModel 目標(biāo)用于保存以上數(shù)據(jù)。
那什么是 ViewModel 呢?
A ViewModel provides the data for a specific UI component, such as a fragment or activity, and handles the communication with the business part of data handling, such as calling other components to load the data or forwarding user modifications. The ViewModel does not know about the View and is not affected by configuration changes such as recreating an activity due to rotation.
ViewModel 是一個(gè)結(jié)構(gòu)組件。它為 UI 組件 (fragment或activity) 供給數(shù)據(jù),而且能夠調(diào)用其它組件加載數(shù)據(jù)或許轉(zhuǎn)發(fā)用戶指令。ViewModel 不會(huì)關(guān)懷 UI 長什么樣,也不會(huì)遭到 UI 組件裝備改動(dòng)的影響,例如不會(huì)受旋轉(zhuǎn)屏暗地 activity 從頭啟動(dòng)的影響。因而它是一個(gè)與 UI 組件無關(guān)的。
public class UserProfileViewModel extends ViewModel {
private
String
userId;
private
User
user;
public
void
init(
String
userId) {
this
.userId = userId;
}
public
User
getUser() {
return
user;
}
}
public class UserProfileFragment extends LifecycleFragment {
private
static
final
String
UID_KEY =
"uid"
;
private
UserProfileViewModel
viewModel;
@Override
public
void
onActivityCreated(
@Nullable
Bundle
savedInstanceState) {
super
.onActivityCreated(savedInstanceState);
String
userId = getArguments().getString(UID_KEY);
viewModel =
ViewModelProviders
.of(
this
).get(
UserProfileViewModel
.
class
);
viewModel.init(userId);
}
@Override
public
View
onCreateView(
LayoutInflater
inflater,
@Nullable
ViewGroup
container,
@Nullable
Bundle
savedInstanceState) {
return
inflater.inflate(R.layout.user_profile, container,
false
);
}
}
需求的是:由于結(jié)構(gòu)組件現(xiàn)在還處于預(yù)覽版別,這兒 UserProfileFragment 是承繼于 LifecycleFragment 而不是 Fragment。待正式發(fā)布版別之后 Android Support 包中的 Fragment 就會(huì)默許完成 LifecycleOwner 接口。而 LifecycleFragment 也是完成了 LifecycleOwner 接口的。即正式版別發(fā)布時(shí) Support 包中的 UI 組件類就是支撐結(jié)構(gòu)組件的。
現(xiàn)在現(xiàn)已有了 UI 組件和 ViewModel,那么我們怎么將它們進(jìn)行銜接呢?這時(shí)分就需求用到 LiveData 組件了。
LiveData is an observable data holder. It lets the components in your app observe LiveDataobjects for changes without creating explicit and rigid dependency paths between them. LiveData also respects the lifecycle state of your app components (activities, fragments, services) and does the right thing to prevent object leaking so that your app does not consume more memory.
LiveData 的運(yùn)用有點(diǎn)像 RxJava。因而完全能夠運(yùn)用 RxJava 來代替 LiveData 組件。
現(xiàn)在我們修正一下 UserProfileViewModel 類
public
class
UserProfileViewModel
extends
ViewModel
{
...
private
LiveData
<
User
> user;
public
LiveData
<
User
> getUser() {
return
user;
}
}
將 Useruser 替換成 LiveDatauser
然后再修正 UserProfileFragment 類中
@Override
public
void
onActivityCreated(
@Nullable
Bundle
savedInstanceState) {
super
.onActivityCreated(savedInstanceState);
viewModel.getUser().observe(
this
, user -> {
// update UI
});
}
當(dāng)用戶數(shù)據(jù)發(fā)作改動(dòng)時(shí),就會(huì)告訴 UI 進(jìn)行更新。ViewModel 與 UI 組件的交互就是這么簡略。
但仔細(xì)的朋友可能發(fā)現(xiàn)了:fragment 在 onActivityCreated 辦法中添加了相應(yīng)的監(jiān)聽,可是沒有在其它對(duì)應(yīng)的生命周期中移除監(jiān)聽。有經(jīng)歷的朋友就會(huì)覺得這是不是有可能會(huì)發(fā)作引證走漏問題呢?其實(shí)不然,LiveData 組件內(nèi)部現(xiàn)已為開發(fā)者做了這些作業(yè)。即 LiveData 會(huì)再正確的生命周期進(jìn)行回調(diào)。
獲取數(shù)據(jù)
現(xiàn)在現(xiàn)已成功的把 ViewModel 與 UI 組件(fragment)進(jìn)行了通訊。那么 ViewModel 又是怎么獲取數(shù)據(jù)的呢?
假定我們的數(shù)據(jù)是經(jīng)過REST API 從后天獲取的。我們運(yùn)用 Retrofit 庫完成網(wǎng)絡(luò)懇求。
以下是懇求網(wǎng)絡(luò)接口 Webservice
public
interface
Webservice
{
/**
* @GET declares an HTTP GET request
* @Path("user") annotation on the userId parameter marks it as a
* replacement for the {user} placeholder in the @GET path
*/
@GET
(
"/users/{user}"
)
Call
<
User
> getUser(
@Path
(
"user"
)
String
userId);
}
ViewModel 能夠引證 Webservice 接口,可是這樣做違反了我們在上文說到的重視別離原則。由于我們引薦運(yùn)用 Repository 模型對(duì) Webservice 進(jìn)行封裝。
Repository modules are responsible for handling data operations. They provide a clean API to the rest of the app. They know where to get the data from and what API calls to make when data is updated. You can consider them as mediators between different data sources (persistent model, web service, cache, etc.).
關(guān)于 Repository 形式能夠參閱我的上一篇《App 組件化/模塊化之路——Repository形式》
以下是運(yùn)用 Repository 封裝 WebService
public
class
UserRepository
{
private
Webservice
webservice;
// ...
public
LiveData
<
User
> getUser(
int
userId) {
// This is not an optimal implementation, we'll fix it below
final
MutableLiveData
<
User
> data =
new
MutableLiveData
<>();
webservice.getUser(userId).enqueue(
new
Callback