Android項目開發如何設計整體架構?

第一次獨立製作App(背單詞的App),沒有什麼經驗,真不知道該從何和下手啊,之前有過遊戲開發的經驗,因為在遊戲開發前我都會先設計一下遊戲整體的架構,所以我想,為了便於以後項目維護,首先也得有一個清晰的架構吧,但都不知道怎麼下手。。。求各位前輩指教一二

附一張之前的一個遊戲的UML架構圖......


時隔一年,這一年中又做了不少東西,反編譯看了幾個APP,還接觸了遊戲客戶端的開發,結合Google I/O 2017 推出的android-architecture-components,我覺得有必要重寫一下這篇回答,希望能夠幫助更多的人,少一點在黑暗中摸索的時間。

想要設計App的整體框架,首先要清楚我們做的是什麼

一般我們與網路交互數據的方式有兩種:主動請求(http),長連接推送

結合網路交互數據的方式來說一下我們開發的App的類型和特點:

  • 數據展示類型的App:特點是頁面多,需要頻繁調用後端介面進行數據交互,以http請求為主;推送模塊,IM類型App的IM核心功能以長連接為主,比較看重電量、流量消耗。
  • 手機助手類App:主要著眼於系統API的調用,達到輔助管理系統的目的,網路調用的方式以http為主。
  • 遊戲:一般分為遊戲引擎和業務邏輯,業務腳本化編寫,網路以長連接為主,http為輔。

一般我們做的App都是類型1,簡要來說這類app的主要工作就是

  1. 把服務端的數據拉下來給用戶展示
  2. 把用戶在客戶端修改的數據上傳給服務端處理

所以這類App的網路調用相當頻繁,而且需要考慮到網路差,沒網路等情況下,App的運行,成熟的商業應用的網路調用一般是如下流程:

UI發起請求 - 檢查緩存 - 調用網路模塊 - 解析返回JSON / 統一處理異常 - JSON對象映射為Java對象 - 緩存 - UI獲取數據並展示

這之中可以看到很明顯職責劃分,即:數據獲取;數據管理;數據展示

確定了職責,就可以進入正題了

1. 傳統的Android App架構

Android最原生也是最基礎的架構,可以理解為MVC,Controller即是ActivityFragment,但是這兩者掌握了Android系統中絕大多數的資源,並且在內部直接控制View,因此傳統的Android App一般是以Activity和Fragment為核心,將網路模塊,資料庫管理模塊,文件管理模塊,常用工具類等分離成若干工具類包,供Activity和Fragment使用。

這是比較基礎的Android項目架構,市面上大部分App都是這種造型

優點:就是開發簡單,以頁面為導向;如果構建水平可以,項目就已經基本實現模塊化,基於Activity,Fragment這這兩個上帝般的存在,很多事情直接就妥了,不用繞。

缺點:維護難,因為是以頁面為導向的,有些需要共用的業務邏輯就會很煩,don"t repeat your self, 你要不要repeat ?不想repeat就要寫模塊,慢慢的項目就會多出一堆亂七八糟的小模塊。另一方面,測試很困難,因為所有的數據處理都在Activity和Fragment,假如現在想先用假數據顯示,就要直接改Activity和Fragment的數據控制邏輯。

還有個最惱火的問題,那就是業務複雜起來後Activity和Fragment的代碼量激增,舉一個例子,電商App的購物車,如果只是管理一下購物車中的商品,無非就是查、刪、改調用,列表管理,300多行代碼應該就搞定了,假如現在加了個優惠券提示呢?光優惠券不夠,還有滿減,還有湊單,要計算運費。還要能領取優惠券…… 噢,忘了一般來說還有一個商品推薦,好了現在有兩個列表要管理了,你覺得CartActivity 2000行代碼能止住么?

在上面這些缺點的描述中,可以看到一個很大的痛點在於:Activity和Fragment不應該管這麼多數據處理邏輯

2. 分層架構

如果仔細看自己的項目,可以發現絕大多數數據處理的代碼是不需要使用Activity和Fragment持有的資源的(比如Context),而很多時候我們需要多個頁面共用一套數據和請求邏輯,很經典的例子是應用中的User對象,一般來說都是全局單例。

這些全局的數據源寫多了,很容易就能想到將數據處理統一抽出來形成一層,向上層提供數據介面,而上層並不關心數據的來源(內存,緩存,網路),因為不用從Activity和Fragment拿資源而且主要工作是數據處理,所以這一層是UI無關的,大幅提升了復用性,我把這一層稱為DataManager層。

這是我一個項目的包結構

Activity和Fragment剝離了數據處理的責任後,持有DataManager的引用,負責獲取數據並展示,向DataManager傳遞數據,絕不進行網路請求和緩存讀寫。

舉一個例子,分頁載入

一般來說分頁載入介面返回的數據是這樣的

{
code=0,
message="success",
data={
page=1,
totalPage=10,
pageSize=20,
total=200,
list=[......]
}
}

在傳統的寫法中,一般在Activity/Fragment中緩存page,totalPage,pageSize去進行分頁請求,根據請求結果刷新數據並判斷是否還有更多;每一個分頁介面都要寫一遍,假如把這段邏輯放到DataManager會怎麼樣?我是這麼寫的

//定義回調介面
public interface ActionCallback& {
void onSuccess(T data);

void onFailure(String message, Throwable e);
}

分頁載入DataManager實現

public class PageLoadDataManager extends BaseDataManager {
private static final int PAGE_COUNT = 20;

private List& mDataList = new ArrayList&<&>();
private int currentPage = 0;
private int totalPage = 0;

public PageLoadDataManager() {
// init something......
}

public void loadData(final boolean refresh, ActionListener& listener) {
if (refresh) {
currentPage = 0;
}
currentPage++;
RequestParams params = new RequestParams();
params.put("page", currentPage);
Request request = new Request(url, params);
request.request(new RequestCallback(){
@Override
public void onSuccess(JSONObject data) {
if (refresh) {
mDataList.clear();
}
totalPage = response.optInt("total_page");
// 返回數據添加到 mDataList ......
if (listener != null) {
boolean hasMore = currentPage &<= totalPage listener.onSuccess(hasMore); } } @Override public void onFailure(String message, Throwable e) { if (listener != null) { listener.onFailure(message, e); } } }); } public List& getDataList() {
return mDataList;
}
}

Activity/Fragment初始化DataManager之後,只需要將數據源綁定到Adapter,loadData設置的回調告訴上層還有沒有更多數據,UI層調用adapter.notifyDataSetChanged( );至於數據從哪來,分頁邏輯,根本不需要UI層管理。UI層只需要通過loadData(refresh),告訴DataManager是否需要重新載入分頁,與下拉刷新的邏輯完美契合。

當然,在此基礎上實現資料庫緩存讀寫,也毫無壓力。DataManager也很容易實現對某一數據的多個介面的統一管理,通過單例模式或者其他管理方法,將數據配發給多個頁面。

優點:大幅減輕Activity/Fragment的壓力,實現數據統一管理,DataManager層成為了一個UI無關的AppSDK層

缺點:需要添加嵌套回調,這個問題在引入RxJava之後被完美處理

其實到了這一步,已經能滿足大多數幾萬行代碼規模中小App的框架需求了,而且分層架構統一處理數據以及代碼復用度高的特點,使得項目中按照框架思路實現業務成為最快速可靠的開發方法。

我認為一個優秀的框架,很重要的特性就是方便業務開發而不是給開發找麻煩,比如在分層設計過後,就算開發時間再緊張,依託分層框架依然是最快最保險的開發方法,假如某個介面直接在UI中寫了,就意味著數據管理層提供的一切便利都無法直接使用,而且假如其他UI用到這個介面,還得再複製粘貼一遍改來改去,相反,依託框架,網路調用只實現一遍,上層即可重複使用這一業務介面(比較典型的:關注、收藏等)

即便如此,項目規模進一步往上之後,DataManager,Activity/Fragment的壓力仍然會增大,更高的測試需求,要求進一步分離Activity/Fragment的代碼。這時候就可以看看MVP和MVVM了

3. MVP 架構

MVC的C是即持有具體Model,又持有具體View,所以C很臃腫,分層架構就算抽出了DataManager,實質上仍然是一個MVC架構,而MVP和MVVM則是C持有具體View這個問題做了點文章,其中MVP就是將大量的View &<-&> Model 交互剝離出來交由Presenter,Presenter持有抽象的View。

在去年寫這個回答的時候,我曾經寫過這麼一段:

看上去很美好,但是網上很多博客的那種Demo寫法我在嘗試應用中發現並不實用,就是抽象出很多View介面,然後建立Presenter類來作為Presenter,這樣做寫些簡單的列表獲取,登錄之類看起來很漂亮,好像做到了代碼分離,但是業務場景一複雜就有點蛋疼

那個時候我還僅僅只是嘗試,不實用是一個很感性的認識,也沒有多說,那時候是在做一個商城應用,使用MVP編寫諸如購物車之類複雜場景的時候遇到了很大的困難,以至於讓我懷疑我是不是在用MVP給自己找麻煩,寫登錄這些還好,寫到購物車的時候我就開始懷疑人生了。

一個ICartView,我要寫多少介面?購物車查刪改、優惠券滿減查、湊單、價格計算、運費……二十個介面少不了吧?那麼這個抽象的View除了給CartActivity用,還有其它什麼卵用嗎?
假如我寫成ICartView,IBonusView,IXXXView……可是有的界面並不需要刪改購物車列表啊,難道我還要再細分?然後讓Activity實現一堆介面?搞成這個樣子,假如哪天需求變了怎麼辦……
Presenter聽起來很吊,主導者啊,但是沒有Activity和Fragment的資源啊,我要怎麼才能讓它主導?需要獲取系統的一些信息(需要Context)的時候怎麼辦?不持有Context難道再開介面嗎?
寫這麼多介面,介面實現,Presenter,多寫了幾百行代碼n個類,就為了把1~200行代碼從Activity移出去?
還是放棄吧……

後來Google出了TODO-MVP,但是發現跟上面那種Demo寫法一樣很麻煩,我也沒有實際運用。後來反編譯了某個大型App,發現其正好是MVP架構,於是仔細看了一下代碼,就如同我最開始的想法,一個IXXXView有多少功能就寫多少介面。再看看Presenter的實現,我忽然就明白我為什麼會感覺不實用了:

任何想要構建一個其他什麼東西取代Activity/Fragment地位的嘗試都是自找麻煩

MVP正是一個典型

既然MVP把Activity/Fragment抽象為View,那麼就意味著當它作為一個抽象View去使用的時候,生命周期,Context這些極其重要的資源Presenter是看不到的,但是這些東西是不可能不使用的。為了能讓Presenter使用到這些,Presenter就必須持有Context,綁定Activity、Fragment的生命周期,就算如此,在一些需要確定使用Activity、Fragment的場合,仍需要使用強制轉型。

正因為Presenter這個「主導」,導致Presenter和Activity/Fragment高度綁定,Presenter和IXXXView,沒有什麼復用性。

這是我對目前Android MVP的一點看法,如果有小夥伴有比較好的實踐經驗,可以在評論告訴我。

4. MVVM 架構

在我研究MVP的時間點,MVVM也是一個很火的概念,基於data-binding框架的demo也很多,但是我看過之後立刻否決了這個方案,大部分應用在從介面獲取數據後都會進行數據變換,哪怕拿到一個圖片URL都會在Java層添加後綴獲取縮略圖,有的要根據數據源控制View大小,顯隱,XML能做的事情太少了,如果將Model綁定到XML,大規模應用將會面臨多少坑……

MVVM相比於MVP,最重要的一個概念就是「數據綁定」,Presenter還持有抽象的View,ViewModel連這個都不需要,View通過ViewModel訂閱其所需的數據源,ViewModel向View提供改變數據的介面,當View的操作引起數據改變或者數據源發生改變時,ViewModel通過訂閱告知View,View進行視圖更新。

這就是MVVM吸引人的地方,ViewModel只提供數據訂閱和數據介面,做到了與UI分離,ViewModel體量比Presenter小,復用性要比Presenter強太多,而且基於分層架構可以做到小幅修改就能實現。唯一的痛點在於:如何實現數據綁定?

之前提到的data-binding,並不是那麼如意,而這次Google I/O 2017放出的android-architecture-components則很好的解決了這個問題

ViewModel組件規範了ViewModel的所處地位,生命周期,生成方式,以及一個Activity下多個Fragment共享ViewModel數據的問題

LiveData組件則提供了在Java層面View訂閱ViewModel數據源的實現方案,很輕量。

ViewModel的引入能夠很好應對Activity銷毀重建時大規模數據的恢復問題,以及多個界面依賴一個介面返回數據的場景,在這兩個組件的規範下實現MVVM架構會十分容易,而且十分有意義。

由於我已經在項目中大規模使用了RxJava,因此數據綁定我是採用RxJava方案實現的

關於使用 android-architecture-components 組件實現MVVM的方案可以參考

googlesamples/android-architecture-components

關於 新型MVVM結構的思路,推薦這三篇文章

Android官方架構組件指南

Android官方架構組件介紹之ViewModel

Android官方架構組件介紹之LiveData

5. 組件化和插件化

這兩年來這兩個概念很火,但需要注意的一點是,這兩個概念和上面的東西並不是一個層級的,組件化和插件化是比上面說的那一堆亂七八糟更上層的東西,是針對整個大工程下的若干小模塊來說的,而這些小模塊怎樣搭建,則還是上面那些內容:)

6. 一點總結

一般來說我們做App,比如小外包,其實是用不到MVP,MVVM這樣的架構的,一個分層架構就足以讓我們快速高效的開發出App,選用什麼框架,不僅要看你的應用類型,也要看你的應用規模,在分層架構的基礎上,只要介面實現的足夠好,代碼夠規範,切換到MVVM這樣的架構也不是什麼很難的事情。

如果你有現成成熟的框架那無需多言,但如果你的應用只有幾千行代碼,為了追求MVVM,寫了十幾個類,踩了若干坑,只為了把一個Activity中的幾十行代碼抽到ViewModel裡面,豈不是南轅北轍?

最後分享一個我自己的代碼庫和基礎框架工程,有沒集成RxJava的基礎分支和集成了RxJava的分層框架分支還有一個使用android-arch-components的mvvm-rx分支,目前網路調用這塊還不怎麼完善,後面會逐步完善演示示例,希望能幫助到大家

ShonLin/QuickDevFramework

------------- end -------------

參考資料

【譯】Android應用架構 - 泡在網上的日子

Android App整體架構設計的思考(一)

怎樣搭高質量的Android項目框架,框架的結構具體描述? - 馬天宇的回答

Android MVP 詳解(上)

Android官方架構組件指南

Android官方架構組件介紹之ViewModel

Android官方架構組件介紹之LiveData


Android架構合集(請關注github,後續github上面會繼續更新)僅供參考學習.
看題主說沒有什麼經驗,那就不要一下用那麼高級的架構 .容易扯著蛋.
規範的把包名 類名寫好.設計模式用好. android項目自帶的架構就夠用了.


這個題目換一個方式問,如何快速搭建一個app。

整體框架先考慮分層結構。分層思想可以參考Android系統的設計。分層大概有核心基礎庫(包括http庫,圖片緩存庫,基礎控制項庫,通用工具庫,資料庫基礎模塊),中間層(提取的通用業務層),數據層(資料庫業務,伺服器通信數據),業務層。

再將每層再細分成模塊。例如提取的通用業務層在你這個項目中可以字典模塊,用戶模塊,遊戲模塊。

最後再考慮業務層的代碼目錄。如果業務層不複雜,可以按照mvc設計模式分目錄(activity/service/provider/receiver/model)。如果業務複雜,建議按照業務模塊分目錄。

做項目還需要設計一套編碼規範,這樣方便以後的維護和團隊協作。


謝邀,先去看看官方給的樣板吧https://github.com/googlesamples/android-architecture


可以看下我的這個小app的項目架構。readme中有架構的原文。用mvp+rxjava+retrofit+dagger進行架構。 GitHub - Zane96/GithubQuery: 由rxjava+retrofit2+dagger2+mvp架構完成的查詢github用戶信息的app by android。


推薦一個GitHub 上 3k Star,成熟穩定且強大的快速開發框架:

MVPArms!


自帶一鍵代碼生成器
向複製粘貼模板代碼說 No!

自帶上萬字文檔
向晦澀難懂說 No!

融合大量主流框架
向差人一步說 No!

兼容組件化框架,後期會給出基於 MVPArms 的一整套企業級組件化解決方案及 Demo
向中小公司不能玩組件化說 No!

架構相關的文章,太多了,前面的很多回答也說的不錯,這裡就不再多說,就直接給大家來點實際的,馬上就能用的,看下面!

https://github.com/JessYanCoding/MVPArms

上千個 企業/團體 都在用,你還不快加入!


這有張圖還可以:https://github.com/nekocode/kotgo


需求功能設計交互,一個都沒有,你也沒法設計


建議多用用市面上好評率高的背單詞APP,如可可英語,百詞斬等,看看它的結構有什麼,然後自己就會懂了


summit dev 2015歡迎你


不錯啦!我現在連個UML都不會畫。項目照樣寫。


看我的博客:
Android的5層平台架構 - 世上只有一種英雄主義 - 博客頻道 - CSDN.NET


大家有什麼關於項目架構的想法可以多多討論呀,我跟著學習學習.


同求一個好方法,我們現在做項目,也頭疼這個呢。


同上


推薦閱讀:

推薦幾款安卓版不錯的濾鏡軟體?
移動設備上的 2K 屏耗電量如何?
如何看待那岩開箱OPPO R11時吐槽雙攝後直播中斷?
彼岸天製作動畫電影《大魚·海棠》遇到的問題,哪些是今天中國動畫電影界的普遍現象,哪些是其獨有的挑戰?
如何評價魅族的 mBack 交互模式?

TAG:Android應用 | Android開發 | Android | Android應用設計 | AndroidStudio |