APP架子遷移指南(二)

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

搭架子切忌過分!。搭架子就是爲了隔離代碼,該幹嗎幹嗎(說白了就是就是讀數據的放一個文件夾,界面放一個文件夾)。如今流行的「domain」、「repository」、「Service」等命名,你若.net出家確定會心一笑:「又TM來裝逼了」--這些命名和早年的"module"、「Biz」、「helper」命名一模一樣(你能夠去蘇菲論壇看看大神幾年前寫的,至今也很是好用的那套.NET通用庫)。android

當你以爲看不明白的時候就該收手了。仍是再強調一次這種觀點,好比我爲了準備文章看了這篇clean-architecture和這篇mosby。一臉的懵逼,並非由於鳥語差,我能夠絕不費勁的看完,而是由於我在看的時候腦海裏一直深深的感受「我有必要這樣搞麼?」,後面我忽然明白,廣點通2毛錢收入不是由於架子差,而是由於crash太多,哈哈哈。看不明白了還要繼續裝逼,就像剛開爐罩就尋思怎麼承載千萬級併發同樣傻逼。你只要記住哪一個文件夾放什麼代碼文件,幹些啥這種層度,就足夠受用了。ios

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

值得看的文章和項目

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

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

白話MVP模式

在學習架子的過程當中,各類翻譯差別和理解偏差形成了諸多困擾,什麼是「業務邏輯」?「領域層」?「數據映射層」?很煩有沒有,尤爲是早期網上的文章做者都是大神,以爲人民羣衆都是學霸,也不給點例子就用無比晦澀的描述帶過去了。好在如今不少大神發現了這一點,開始用生動輕巧的語言來描述這些概念。前面推薦的文章相信你也吸取的差很少了,我就結合實際細節再白話一遍MVP模式(我沒老司機帶,理解誤差請糾錯)。sql

你跟我同樣嗎

之前你是否是在一個叫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文件中,當時我圖省事沒弄)json

若是你拿着票子想讓功能更健壯,上傳數據的代碼寫在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

相關文章
相關標籤/搜索