2016年7月23日 星期六

Android MVP 基本了解與實作

這篇文章適合初學者想要了解MVP pattern到底是什麼(因為講得很白話)以及如何實作(簡單登入APP)!!

最一開始大部分的人寫android,都會在Activity寫很多function或是邏輯判斷,頂多用到資料庫會新建類別在建構它使用,最後導致Activity又臭又長,其實學習MVP不只是為了讓架構更清楚了解,其實最大的好處是方便測試和移植,為什麼呢等等最後會解釋


一.MVP(Model-View-Presenter)介紹:

很多人聽過MVC,其實MVP是從MVC衍伸出來的,為了更細分View與Model的功能,讓View處理UI的資料數據變化,這裡不多說MVC是什麼,在MVP模式裡通常包含4個要素:

1. View : 負責繪製UI元素,簡單來說就是Activity以及Fragment。
2. View interface : 需要View的實現接口,View 通過View interface 與 Presenter進行交互,降低耦合,方便進行單元測試。
3. Model : 負責儲存、搜尋、操作資料數據(有時候也會實現一個Model interface用來降低耦合)。
4. Presenter : 作為View與Model交互的橋樑,處理與用戶對應的邏輯功能。

最主要的是MVP都需要透過Presenter當作橋梁去溝通彼此都不認識的View以及Model

二.為甚麼要使用MVP模式

並不是說你用了MVP你的程式碼就更好維護或是更清楚,如果自己的思路很清楚也當然不必使用,但是使用這種架構是可以讓別人比較容易懂得你的程式碼,而最主要的核心思想其實是單元測試(Unit Test),回想一下你在開發Android應用是如何對程式邏輯進行測試?是否每次都要重新佈署在手機或是模擬器上,然而Android平台的特性,每次部屬都會耗費大量時間而降低開發效能,根據上面的介紹,MVP的P把所有與用戶對應的邏輯都集中在這裡,所以可以透過MOCK一個View及Model來測試P,進而省去部屬跟測試的時間。

三. MVC跟MVP差異

首先我們看到了以下的圖


MVC:

  • View可以與Model直接互動 

  • Controller是用於更新UI介面和數據實例,並且可以被多個View共享
View層接受用戶的輸入,然後通過Controller修改對應的Model實例;同時,當Model實例的數據發生變化的時候,需要修改UI界面,可以通過Controller更新界面。 View層也可以直接更新Model實例的數據,而不用每次都通過Controller,這樣對於一些簡單的數據更新工作會變得方便許多。


MVP:
  • View不直接與Model交互,而是通過與Presenter交互來與Model間接交互 

  • Presenter與View的交互是通過接口來進行的,更有利於添加單元測試 

  • 通常View與Presenter是一對一的,但複雜的View可能綁定多個Presenter來處理邏輯
這樣的話,Activity的工作變簡單了,只用來響應生命週期,其他工作都丟到Presenter中去完成。從上圖可以看出,Presenter是Model和View之間的橋樑,為了讓結構變得更加簡單,View並不能直接對Model進行操作,這也是MVP與MVC最大的不同之處。

四. demo實作

那我們來實作一個簡單的loginApp,成功的話就對丟出Toast訊息



這個布局很簡單,我就不多介紹



再讓我們來看到架構,分成Model,Presenter,View跟主要的activity, 個人習慣及建議是從Presenter開始著手,因為當你設計一個程式,你會知道你需要什麼功能以及你的layout,進而知道你的邏輯function到底要設計什麼,而Presenter就是在處理這些!

Presenter

讓我們來看看Presenter,其實我們要做的邏輯很簡單,登入無非是抓去使用者資料去比對資料庫!所以很清楚的知道我們的主要邏輯就是抓View的String 物件,再去Model裡抓值比對。
所以一開始我在onloginclick(String,String)設了String 參數,然後再去Model裡的checkaccount()裡抓值比對,然後我希望當我輸入完我的欄位值可以清空,所以再View寫了clearEdittext(),最後我想推出是否成功登入或失敗的訊息,所以我在View寫了toastmsg(參數),參數是在Model裡做了如果是成功登入我會回傳訊息(也就是checksuccessaccountmsg()),以上就是Presenter要做的事其實很簡單。

其實Model跟View 誰先寫誰後寫我覺得差不多,我個人習慣是在Presenter其實就順便把Interface 的View 一起寫好,畢竟是在最後Activity才要實做出來。

View (interface)

那View的程式介紹其實在上面就有提到,只需要在Activity實作因為他是個介面(interface)

Model

Model就是存取資料的地方,那我在這裡其實做了偷吃步,我並沒有去資料庫的建置,我只假設我的帳號是andy就可以登入,除了這個都是失敗,這裡的部分就請大家自己實作瞜!其實做好的方式是把帳號密碼取出來並回傳到Presenter去做邏輯測判斷,那我在一開始其實設置了Globla變數 msg ,並在checksuccessaccountmsg()做回傳。

Activity



Activity實作View interface,而我在一開始宣告new一個Presenter物件,並傳遞view跟model,那大家有沒有看到我是用Presenter.onCreate(),這裡是因為MVC都是透過Presenter去做,包括介面更新所以我想讓View做更少,當然其實簡單點還是用原本的setContentView來也可以,實作完方法最後就只剩點擊事件,那我在XML設置Button onClick=btn_login,也就是叫Presenter開始做事情啦!

可以看到,View只負責處理與用戶進行交互,並把數據相關的邏輯操作都扔給了Presenter去做。而Presenter調用Model處理完數據之後,再通過InterfaceView更新ActivyView顯示的訊息。

附上github : https://github.com/andy086912597/Mvplogindemo,大家有興趣可以下載了解,有問題也可以互相討論說明,謝謝!

參考網址














2016年7月16日 星期六

Android Service 基本學習!

這篇文章你知道Service的基本程式碼會更加知道我在說什麼,也當然初學者(像我)這篇文章我覺得有很多觀念跟例子我覺得是可以提供大家做參考的,那接下來就開始我們的Service


首先你要先了解什麼是Service?
簡單來說就是在背景裡默默地執行程式而不受介面關閉所影響
那為什麼要用?
很簡單啊!不就是一些耗時的執行程序,像是下載阿,總不能叫使用者下載完畢才可以使用
所以讓我們來開始慢慢探討一些Service的東西

首先我們看到了Service的生命週期

                                 























這裡就不多敘述LifeCycle

那其實Service 常見的就分了兩種
startService & bindService

先來介紹startService
生命週期 : onCreate() ➞ onStartCommand() ➞ onDestroy()
Activity 透過 startService(intent)來啟動Service,那首先系統會先執行OnCreate()將所帶入的intent帶到Service的onStartCommand(intent,int,int),這樣就完成了Service的第一步,而這個Service會一直跑下去除非你呼叫StopService()或是手機記憶體吃緊時會把某些系統收掉,那這時候出現了一個問題,那我的Service被砍掉了可是我需要用怎麼辦?
這時候有幾個參數在onStartCommand回傳值可以讓系統替你重新啟動Service。
  • START_STICKY : Service被殺掉, 系統會重啟, 但是Intent會是null。
  • START_NOT_STICKY : Service被系統殺掉, 不會重啟。
  • START_REDELIVER_INTENT : Service被系統殺掉, 重啟且Intent會重傳。
    透過以上的參數, 放在onStartCommand的return參數就可以使用重啟的功能了。

再來是bindService
生命週期 : onCreate() ➞ onBind() ➞ onUnbind() ➞ onDestroy()
Activity透過bindService(intent,connection,flag)建立一個與Service綁定的連線,首先建立serviceConnection的匿名類,在裡面重寫onServiceConnected()方法和onServiceDisconnected()方法,而這兩個方法會在Activity與Service建立或解除聯繫時候所調用,而把這匿名類別物件放到bindService(connection)裡,而flag參數預設 BIND_AUTO_CREATE,也就是當我們綁定的時候會自動產生 Service。當連線時在onServiceConnected()我們可以透過IBinder接收到Service內的onBind()所丟出的IBinder物件,利用這 IBinder 物件取得 Service 物件,就可以直接操作 Service 內各個 public 的 method。而當想要解除繫節怎麼辦?這時候使用unbindService()就可以解除或是你使用的Activity已經結束了,因為綁定再一起所以會共存亡

以上兩個是實作Service的基本方法,那使用時機呢?讓我來舉個例子

當你想要在後台撥放音樂,這時候可以透過startServie(intent)來播放,而你可能想要知道音樂

的資訊或是下一首,只時Activity就可以調用bindService()方法與Service建立連線並使用你想要

的方法。

這樣有看懂嗎?其實差別就是Activity可不可以跟Service做溝通前者不可(start)後者可以(bind)

而在這裡再跟大家說很重要的事,那就是其實ServiceThread是很像的,只是Service其實是運行在main process裡!WOW!!就是因為這個原因如果直接在Service中處理一些耗時的邏輯,就會導致程序ANR。那該如何解決呢?應該在Service中開啟線程去執行耗時任務,這樣就可以有效地避免ANR的出現。也可利用遠程service 

遠程Service請自己google一下,簡單來說它已經在另外一個進程當中運行了,所以只會阻塞該進程中的Main process,並不會影響到當前的應用程序。

程式實作代碼有需要再email給我!有什麼疑問或是講得有錯誤的請大家多多指教!!