APP架子遷移指南(二)

來源:互聯網
上載者:User

標籤:

接上一篇,這一篇開始用android來解釋MVP概念、八股式的架子結構和命名規範。我在準備這篇文章的時候還看到不少在MVP基礎上衍生的架子思路,底子是MVP沒錯,但命名有區別、複雜度變了、架子也用到了module拆分而不單純用包進行拆分,所以接下來會基於googlesamples推薦的命名、架子結構來重構我的約炮APP,我會pull個新的branch來對應各個章節,接下來會從我認為合適的難度適中、實用的方向繼續重構。

搭架子切忌過度!。搭架子就是為了隔離代碼,該幹嘛幹嘛(說白了就是就是讀資料的放一個檔案夾,介面放一個檔案夾)。現在流行的“domain”、“repository”、“Service”等命名,你若.net出家肯定會心一笑:“又TM來裝逼了”--這些命名和早年的"module"、“Biz”、“helper”命名如出一轍(你可以去蘇菲論壇看看大神幾年前寫的,至今也非常好用的那套.NET通用庫)。

當你覺得看不明白的時候就該收手了。還是再強調一次這種觀點,比如我為了準備文章看了這篇clean-architecture和這篇mosby。一臉的懵逼,並不是因為鳥語差,我可以毫不費勁的看完,而是因為我在看的時候腦海裡一直深深的感覺“我有必要這樣搞嗎?”,後面我突然明白,廣點通2毛錢收入不是因為架子差,而是因為crash太多,哈哈哈。看不明白了還要繼續裝逼,就像剛開爐罩就尋思怎麼承載千萬級並發一樣傻逼。你只要記住哪個檔案夾放什麼代碼檔案,幹些啥這種層度,就足夠受用了。

順便預告一下,在後面講IOS端,我會來講講MVC模式怎麼結合搭架子的思路,正好也為出文章給點動力馬拉松一次把一直想做的ios端做了(因為到現在用廣點通收入才2毛錢不想弄,哈哈哈)。IOS現在炒MVVM火的很,關於MVVM模式我是很拒絕的,在早年做silverlight的時候用過,覺得太麻煩了(這也是我想提的觀點,不要過度),資料繫結這件事,邏輯簡單還好,要做很多其他工作,你光是寫架子的基礎代碼就夠折騰了。在後面講PHP端(Laravel)的時候,我就聊聊檔案夾該怎麼放,檔案名稱該怎麼取顯得很專業,以偉大又優雅的laravel架構來總結下全篇。

值得看的文章和項目

自從微博關注了很多大神和幾個開發部落格之後,各種技術文章炸屏有沒有..尤其是像我這種好奇心勝的,關注的方向不少,看得很壓抑啊。這裡我先給幾個我認為你應該學習的文章和項目,比我寫的好、寫的生動(打星標是指我認為的閱讀友好度)。

  • Google原味mvp實踐 ★★★★
  • Android:你是如何把Activity寫的如此“萬能”的 ★★★★
  • Android:“萬能”Activity重構篇 ★★★★★
  • MVP+Dagger2+Retrofit實現更清晰的架構★★★
  • 從零開始的Android新項目6 - Repository層(下) Realm、緩衝、異常處理★★★★(這個系列強烈推薦看完,大神還放了一個沒混淆沒加固已上線的apk讓你逆向,感動)
  • Architecting Android…The clean way? ★★★
  • Architecting Android…The evolution ★★★
  • the-clean-architecture ★★★
  • Model-View-Presenter library for android ★★★

項目,要發現新的會編輯添加:

  • MVP殿堂級代碼 ★★★★★
  • Crew(逆向看,注意dagger2會添加很多支援代碼)★★
白話MVP模式

在學習架子的過程中,各種翻譯差異和理解誤差造成了諸多困擾,什麼是“商務邏輯”?“領域層”?“資料對應層”?很煩有沒有,尤其是早期網上的文章作者都是大神,覺得人民群眾都是學霸,也不給點例子就用無比晦澀的描述帶過去了。好在現在很多大神發現了這一點,開始用生動輕巧的語言來描述這些概念。前面推薦的文章相信你也吸收的差不多了,我就結合實際細節再白話一遍MVP模式(我沒老司機帶,理解偏差請錯誤修正)。

你跟我一樣嗎

以前你是不是在一個叫data或者bean或者model的包裡面放了很多資料實體?如“UserBean”,定義使用者的名字、性別欄位,添加get/set方法,持久化(Parcelable),用gson或orm的話還會加上@SerializedName、@Table之類的注入。


你定義資料的地方

接下來你會把網路訪問哪個網址取得使用者資料的代碼寫在一個叫Manager或者Api或者Network的包裡面,json資料從網路讀取並通過gson轉換你會寫在listview所在的fragment或者activity檔案中(比如叫loadNewData)。


你定義網路訪問的地方
你把網路訪問資料轉換為listview可讀取資料的地方

如果你是有心之人,那麼你還會寫sqlite操作的邏輯並放在一個叫dao或者db的包,把資料寫入到sqlite中去存起來。每次從資料庫讀或者寫,會用asyncTask執行(可能你會建立一個叫task的包或者listview所在的fragment或者activity檔案中,當時我圖省事沒弄)

如果你拿著票子想讓功能更健壯,上傳資料的代碼寫在service裡面,那就會添加一個service包;需要添加notification,那麼你會建立一個叫boardcase的包和notification的包,一個存廣播、一個存notificaition;圖片處理、時間字串處理等功能寫在一個叫utils的包裡面;第三方輪子View控制項寫在一個叫widget的包裡面。

發現啥問題沒

寫代碼講究個“邏輯分離”,簡單講讀寫資料的湊一堆;讀寫網路的湊一堆;介面互動(包括資料顯示)湊一堆,這樣的好處就是維護起來方便,易於擴充(項目小沒這種體驗?那在硬碟裡面,代碼放一個檔案夾,ui設計素材放一個檔案夾,文檔放一個檔案夾,要用的時候直接開啟哪個檔案夾心裡了如指掌,這樣理解了吧)。

那其他文章裡總是提“商務邏輯”、“功能邏輯”,怎麼區分呢。以登入功能來舉例:

  1. 你用手機號或者登入,驗證格式或者通過擷取token和userinfo,都是為了實現登入功能,但是方法不同,完成這些操作你可以調用umeng或者第三方的原生SDK,為這些寫代碼,算商務邏輯。
  2. 把使用者註冊資訊發送到伺服器儲存,並接收伺服器反饋(比如保持使用者登入狀態的token),存進preference或者資料庫,這些代碼算商務邏輯。
  3. 怎麼把資料就存入preference或者資料庫,無非就是增刪改查,那麼這部分代碼就算功能邏輯。

為實現具體業務功能寫的代碼,叫做“商務邏輯”。登入的時候擷取人員位置、簡訊驗證碼都算。並且,你存入資料庫之前需要修改伺服器反饋的資料(比如從拿使用者性別是m、f,你想存為0、1表示),這種代碼也算入商務邏輯中去的。在各種架子中,“domain”、“service”、“repository”裡面乾的全是這些事。

為實現可複用的功能函數代碼,叫做“功能邏輯”。不管業務是登入還是登出,想訪問網路或者讀取資料庫,最後都會調用平台的方法吧,那麼如何調用平台方法的代碼,就是功能邏輯。如訪問網路,不管是想post登入的網址或者post登出的網址,都會用到調用android網路訪問的代碼;如增刪改查,不管你是preference或者sqlite,最後都會調用android方法執行;如數群組轉換、臨時檔案管理、圖片壓縮、檢查字串是否為空白、md5加密、時間格式化等等,你可以寫一個叫utils的包儲存這些代碼。boardcase、receiver、sevice、notifacation都應該以包為單位分離。


很多輪子已經幫你搞定了,比如讀取圖片的Glide或則網路訪問的okhttp

按照這樣的思路進行細分,那麼很明顯的,上一節中目前我app的架構雖然包的結果清晰,但是讀起來是一團糟的,而且確實是“讀”起來一團糟,比如index的fragment程式碼數過高,我不得不簡單的把代碼“挪”到一個BaseIndexFragment中,簡單的把資料讀取和介面互動的代碼分開便於閱讀。MVP模式就很好的解決了我這樣不專業的分離方案,提供了標準模板,什麼代碼該放哪就放哪。

Model層不再只是放資料實體了

按照MVP的說法,Model層是要把所有和資料有關的代碼都放在這裡的,也就是說定義資料實體、網路讀取json並轉換為資料數組、資料庫讀寫資料這些代碼全部都寫在這裡。Presenter層想擷取資料,那就一定是已經處理好不需要再處理的資料了,怎麼擷取資料(從網路或者資料庫)的、資料怎麼轉換的,通通都不用管。


資料處理全部移步Model層

在項目裡面體現在什麼地方呢,listview所在的fragment中,從網路擷取json並轉換為資料數組操作的代碼從原來的loadNewData函數中移到了Model層的XXRemoteDataSource檔案中去。從資料庫擷取資料的asyncTask代碼移到了XXXLocalDatasource中去,判斷顯示本機資料還是網路資料的代碼移到了XXXDataRepository中去。這樣一來,fragment中的代碼一下就清爽了很多,是不是感覺很好?我們繼續看Presenter。

Presenter層就像電梯

資料讀取前、讀取後該幹嘛?點擊登入按鈕後伺服器返回登入狀態該跳轉首頁還是提示密碼錯誤?這些事都是Presenter乾的:把Model層準備好的資料顯示在介面上,有互動時提醒Model層資料需要更新。就像一台電梯,人進來,去按摩到3樓,去ktv到4樓,去開房到5樓。進來的是男是女你不需要關心,出去幹嘛你也不需要關心。

在Presenter層裡面會大量用到介面(interface)定義行為。以前是不用介面的,第一嫌麻煩,第二人家是團隊這樣方便測試,我只搞暴力測試沒那麼講究。現在還是老老實實用吧,如果不習慣你可以先實現功能,再重構介面,或者把常用的增刪改查先複製進去用,慢慢習慣。


要開始寫介面了,有點心理準備

這時你可能會有一定的困惑,如果有涉及諸如IM通訊、百度LBS定位這樣功能邏輯的代碼,該放哪裡?這些代碼可能需要依賴上下文(就是建構函式要context或者activity,你肯定見過),我認為應該放到utils包裡面。傳遞參數、狀態成功或失敗該怎麼處理的代碼才放到Presenter中去。也就是說和介面有關的代碼才放在Presenter中,其他按商務邏輯或功能邏輯能歸類的盡量重構。

View層不是指的控制項

這裡的View是思想,不是具體指按鈕控制項或者列表。你可以腦補一個畫面:View和Presenter在床(fragment或activity)上搞基,一會Viwe在上面,一會Presenter在上面。


View是讓你在通知介面哪個該隱藏了,哪個該重新整理了

從一個簡單的新聞列表,到複雜點有輪播banner、多級下拉式功能表,都可以在View層中表達控制項的狀態和互動動作,通知presenter這個控制項被點擊要執行啥操作了,或者prenseter通知這個控制項應該被隱藏或顯示了。View層在MVP結構中,反而是寫代碼量較輕的一塊,只要Model和Presenter寫好了,明天在github上看到一個更酷炫的輪子或者想添加一個動畫效果,都是很清爽的事。

聊聊別的

我相信你已經看過我推薦的那幾篇文章了,那麼我這很白話的把mvp模式講了一遍,用很多平時會用上的細節來解釋,應該對概念的把握比較深刻了。那麼在我把我的項目更新完成寫下一篇之前,我們再聊聊別的。

RxJava和handler到底該用哪一個?

你們是不是也喜歡把自訂的handler寫在fragment檔案裡面?或者asyncTask之類的,或者adapter。功能簡單點的倒是問題不大,這樣寫又快又省事,閱讀性也可以。但要是你遇上登入功能,首先通過umeng擷取使用者資訊,成功了再從伺服器擷取七牛的上傳token,然後傳圖片,圖片上傳成功把頭像地址和使用者資訊post到資料庫裡面,成功了從伺服器擷取token存app資料庫。像這樣“圓環套圓環”的業務代碼,畫時序圖都挺麻煩,用handler可以寫,但是隔一段時間再閱讀起來就很不開心了。


頻繁的網路訪問會讓handler變得臃腫

RxJava的流編程思路就可以很好的解決這種問題,雖然代碼量並不見得變少,但卻是可以讓閱讀起來開心一點。至於網路模組你用async-http-client或者okhttp或者volley,或者最近很火的retrofit2,這就看自己了吧。我一直在用async-http-client,夠老的輪子了吧,也沒覺得有什麼不妥的(可能我的網路訪問規則太簡單了)。另外你想當技術網紅的話,RxJava+Retrofit2是必備神器,但要.net出家的人,還是呵呵吧,沒必要炒到這種高度。

我的文章肯定有問題,求指正

我沒老司機帶,全靠github和逆向工程學習。肯定會有問題,還請發現了指正,非常感謝!qq群533838427

APP架子遷移指南(二)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.