国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

完整的Android MVP開發之旅

2020-04-11 10:44:53
字體:
來源:轉載
供稿:網友

開發背景
最近是在做一個與健身相關的APP,里面有訓練器模塊基本功能是按照特點動作的演示和描述來引導用戶完成訓練。在第一個版本時由于沒接觸過些類項目與功能花了幾周的時間大概1500行代碼才完成這個功能,
當時雖然我已經盡量讓代碼表現的清晰,但是可以想像到當一個Activity中包含這么多代碼是什么感覺。自己維護起來都難受。

先談設計
有了前一次設計經驗此次開發使用MVP、模塊化、面向接口等概念,將整個訓練器分為控制器、數據模型、音頻、視圖、可訓練對象五個模塊分別用以下接口表示:

  • ITrainerController
  • ITrainerModel
  • IAudioFlow
  • ITrainerView
  • ITrainable

去掉一些抽象類后接口圖如下:

設計以上接口后引入MVP概念使用ITrainerController做為Presenter,ITrainerModel做Model,ITrainerView做View下面介紹主要模塊。

控制器
可以用在MVC和MVP中這取決于用哪種開發模式,在我開發的項目控制器用來控制訓練器的運行管理訓練器的生命周期如訓練、暫停、休息、完成等狀態協調ITrainerModel、ITrainerView、IAudioFlow等各個模塊。
在使用過程中控制器并不止一個這也是抽象出一個接口的原因,ITrainerController接口繼承IPresenter接口使其能做為Presenter使用。

數據模型
數據模型中包含大量的ITrainable對象,對內組織數據對外提供數據支持。對數據的組織方式主要分兩種:

  • 從本地數據庫
  • 從網絡獲取

在訓練器中可能是正常的訓練或是一次訓練測試而訓練數據和測試數據又有一些差異但它們的數據都被當做ITrainable,測試數據是不需要保存的只需要從服務器拉取后按要求完成就行而訓練是會產生本地記錄的。
針對不同數據組織方式提供不同的數據模型這是有必要的。

音頻
音頻比較多樣化像訓練過程中包含動作名、時間、單位詞、提醒等音頻這些音頻都是分開的不同的音頻文件。Android主要有兩種實現方式:

  • SoundPool
  • MediaPlayer

首先說SoundPool優點自然就是免去了加載、管理音頻等過程但是它并不適應我們的訓練器,主要原因是缺少準備、完成后的一些回調而在訓練器運行過程中這些過程必不可少比如在播放完一段預備開始后音頻這時我們才能進行正式的訓練。
最后是采用MediaPlayer,但是在使用過程又要考慮到音頻的集中管理與資源的釋放免不了多封裝一次。設計時我將全部音頻邏輯放在Android Service中Activity通過bind AudioService來使用音頻,將音頻邏輯放入AudioService這樣可以音頻完
全獨立起來使其能在后臺播放并且也可以提高進程優先級。

在設計中AudioService僅僅播放與管理音頻和資源并不具備音頻播放的邏輯功能。由于不同的訓練方式音頻的播放邏輯也有不同之處所以在此設計IAudioFlow接口來負責音頻邏輯。

訓練視圖
Android常用Activity作為視圖,通過實現ITrainerView接口來完成訓練視圖的顯示。視圖中不包含任何業務邏輯代碼。

再談實現
說到實現其實這并不是最需要關注的內容,因為上面提供了很全面的接口而我們的模塊又是使用的接口所以不管如何實現那些功能并不會對各個模塊之間產生大的影響除非功能實現與實際要求相差太多。這里我只詳細說一下音頻模塊的實現。

音頻實現
音頻模塊又可分為音頻管理與音頻業務邏輯。音頻管理就是加載、播放、回收資源等功能,音頻業務邏輯主要處理在正確的狀態下應該播放什么樣的音頻。將整個音頻管理模塊放在Android Service中與業務邏輯完全分離。音頻模塊涉及以下類與接口:

  • AudioService: 音頻服務器繼承Android Service
  • IAudioService: 音頻抽象接口包含播放、暫停等事件
  • MediaPlayerHolder: 持有MediaPlayer管理MediaPlayer生命同期
  • IAudioFlow: 為不同的訓練內容提供音頻邏輯
  • AudioServiceImpl: 實現IAudioService

基本使用流程是首先通過綁定AudioService的onBind方法返回IAudioService的實現類供IAudioFlow使用,IAudioFlow持有IAudioService實現后加載訓練音頻然后供ITrainerController使用。在AudioServiceImpl中會維持一個音頻優化級隊列,
上面提到因為音頻都是不在一個文件中的所有需要在使用時將它們連接起來形成一段音頻。通過優先級隊列結合MediaPlayer播放完成時回調可以將多個音頻組合在一起形成需要的音頻。由于音頻的播放越來越多MediaPlayer的回收利用特別重
要在AudioServiceImpl同樣也具備MediaPlayer的回收與利用功能。這個功能實現是通過MediaPlayerHolder來處理的,通過MediaPlayerHolder的靜態get方法獲取MediaPlayerHolder如果回收池中有空閑的MediaPlayerHolder則拿來用沒有時則
新建一個,同樣也在一個音頻播放完成后調用MediaPlayerHolder的recycle來進行回收利用。

模塊整合
為減少依賴模塊之間的整合需提供管理或幫助類,新建TrainerHelper來創建模塊實現類其中包含一個Mode枚舉來列舉訓練模式。

public class TrainerHelper {  public enum Mode{TEST, TRAINING, EXAM}  private static Mode mode;  public static void setMode(Mode m){    mode = m;  }  public static ITrainerController createPresenter(ITrainerView view, Bundle createArgs){    return new TrainerPresenter(view,createArgs);  }  public static ITrainerModel createTrainerModel(ITrainerController controller){    return = new DefaultTrainerModel(bundle);;  }  public static IAudioFlow createTrainerAudioFlow(ITrainerController controller){    return new DefaultAudioFlow(controller);  }}

總結
成功的設計與架構能減少大量的工作時間,利用接口可讓開發人員更加注重功能上的實現同時隔離各個模塊之間的依賴。下次產品經理再改需求或再整出個訓練模式時咱也能從容應對。

由于本人水平有限如有錯誤,請大家諒解。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 乐平市| 华坪县| 兴仁县| 锦州市| 宜君县| 重庆市| 巴彦淖尔市| 静海县| 红原县| 乌拉特前旗| 蒙阴县| 贡觉县| 灵石县| 民丰县| 丰台区| 菏泽市| 北碚区| 东港市| 扶绥县| 龙岩市| 柳林县| 元谋县| 铜鼓县| 高雄市| 舞钢市| 个旧市| 和政县| 塔河县| 罗田县| 古丈县| 阳东县| 陇西县| 彩票| 贺兰县| 临潭县| 宁德市| 东明县| 仪陇县| 同心县| 金沙县| 和静县|