Android開發(fā)-淺談架構(gòu)(一)

寫在前面的話

嗯 聊聊架構(gòu)。 這段時間一直在維護舊項目胆剧。 包括自己之前寫的新項目 越來越發(fā)現(xiàn) 一個架構(gòu)清晰的項目往往讓人賞心悅目缭保。不至于在一個bug丟過來之后手足無措。包括以后別人接收自己的項目 能很快上手 何樂而不為呢核无?

曾經(jīng)的"MVC"

先從我們曾經(jīng)的 "MVC" 說起, "MVC" 全名 "Model View Controller".即 視圖層(View), 控制層(Controller)藕坯,模型層(Model).他們之間的關(guān)系 如圖:


MVC

視圖層(View) 一般由 xml布局文件擔(dān)任 控制層(Controller) 一般由 activity和fragment 擔(dān)任 模型層 (Model) 一般指的是 抽離出來的接口擴展团南。 嘗嘗可以復(fù)用的那一部分。 你只需要把接口 在Controller 拋出炼彪。 更新 View即可吐根。其實我們剛開始參與項目開發(fā) 技術(shù)薄弱的時候 都會想到把復(fù)用的部分抽離出來 但是activity類寫的很臃腫 至少不夠優(yōu)雅這其實就是MVC

寫到這里 我們知道android中 Controller 控制層一般有Activity(主要)和fragment 擔(dān)任。但是activity類中 常常包含一些ui 初始化 或者 網(wǎng)絡(luò) 第三方sdk 的初始化又或者是業(yè)務(wù)邏輯辐马。那么 這樣寫起代碼層就會變得臃腫拷橘。而且不夠優(yōu)雅。那么MVP就從MVC中眼花誕生了喜爷。


MVP

MVP中的model層繼續(xù)沿用MVC中的model

大家看這個圖 也許不是很清楚或者說不是太理解冗疮。
在這里 "View" 由presenter中的接口擔(dān)任 實現(xiàn)向View實現(xiàn)類通信,你也可以在Android組件中實現(xiàn)它檩帐。有時最好直接使用Activity术幔,F(xiàn)ragment或自定義View。>The view that receives commands from a presenter in MVP, is referred to as "view"

先說Model: 它是一個負(fù)責(zé)管理數(shù)據(jù)的接口湃密。模型的職責(zé)包括使用API诅挑、緩存數(shù)據(jù)、管理數(shù)據(jù)庫等泛源。該模型也可以是一個接口揍障,與其他模塊負(fù)責(zé)這些職責(zé)的溝通。例如俩由,如果您使用的是存儲庫模式,則該模型可能是一個存儲庫癌蚁。如果您使用的是干凈的建筑幻梯,相反兜畸,該模型可以關(guān)聯(lián)。(翻譯過來略顯生硬 簡而言之 Model層是數(shù)據(jù)訪問層碘梢,如數(shù)據(jù)庫API或遠(yuǎn)程服務(wù)器API)

Presenter:大家可以看到Model和View是完全沒有交互的咬摇。那么 Presenter則擔(dān)當(dāng)Model與View之間的中間人。你所有的業(yè)務(wù)邏輯都屬于它煞躬。Presenter負(fù)責(zé)查詢模型和更新視圖肛鹏,響應(yīng)用戶交互更新模型。

View:The view can be implemented by Activities, Fragments, any Android widget or anything that can do operations like showing a ProgressBar, updating a TextView, populating a RecyclerView and so on.(這個翻譯起來有點尷尬 感覺大家應(yīng)該都能看懂)

對照MVC圖來看 我們發(fā)現(xiàn) View 中出現(xiàn)了<Interface> 而Presenter中也出現(xiàn)了<Interface> .什么意思呢恩沛? 我們看Presenter中的代碼實例:

View中的TicTacToeView示例

關(guān)于

  1. 怎么寫Model
  2. 如何理解View
  3. 如何寫Presenter
    參考 MVP詳解

關(guān)于MVP文字性的描述就這么多在扰。其實網(wǎng)上大部分講解都是套三者之間的關(guān)系交互圖來講的。只有理解了嘗試敲幾遍就差不多會了雷客。另外 符合項目需要的才是最好的芒珠。下面我嘗試著動手仿照 ONE 一個app將MVP模式套入其中練手(項目會不斷完善的 架構(gòu) 分包開始)

先截個圖 看一下目前大致的結(jié)構(gòu)。

aaa.png

沒用到Presenter之前切換Fragment MainActivity切換標(biāo)簽頁:
<code>

 FragmentUtils fragmentUtil = new FragmentUtils(this, R.id.view_container);
fragmentUtil.switchTo(OneFragment.class);
mBinding.radio.setOnCheckedChangeListener((group, checkedId) -> {
  switch (checkedId) {
    case R.id.home_one:
      fragmentUtil.switchTo(OneFragment.class);
      break;
    case R.id.home_reading:
      fragmentUtil.switchTo(ReadingFragment.class);
      break;
    case R.id.home_music:
      fragmentUtil.switchTo(MusicFragment.class);
      break;
    case R.id.home_movie:
      fragmentUtil.switchTo(MovieFragment.class);
      break;
    default:
      break;
  }
});

</code>
用到Presenter之后:

<code>
if(presenter==null)
presenter = new MainTabPresenter(this, mBinding.radio);
presenter.switchTo();
</code>

其中 HomeActivity 類:
<code>
public class HomeActivity extends BaseActivity<HomeActBinding> {
private MainTabPresenter presenter;
@Override
protected int getLayoutId() {
return R.layout.home_act;
}
@Override
protected void setupView() {
if(presenter==null)
presenter = new MainTabPresenter(this, mBinding.radio);
presenter.switchTo();
}
}
</code>

BaseActivity類:
<code>
public abstract class BaseActivity<T extends ViewDataBinding> extends AppCompatActivity{
protected T mBinding;
protected ApiInteractor api;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initLayout();
}
private void initLayout() {
AppComponent appComponent = ((App) getApplication()).getAppComponent();
api = appComponent.getApiInteractor();
ViewDataBinding inflate = DataBindingUtil.setContentView(this, getLayoutId());
mBinding = DataBindingUtil.bind(inflate.getRoot());
if (mBinding == null) {
if (getLayoutId() == 0) {
throw new InflateException("activity no source_ID");
} else {
throw new NullPointerException("mBinding==NULL");
}
}
setupView();
}
@LayoutRes
protected abstract int getLayoutId();
protected abstract void setupView();
}
</code>

Presenter類:
<code>
public class MainTabPresenter implements MainTabContract.Presenter {
private RadioGroup radioGroup;
private final FragmentActivity mContext;
public MainTabPresenter(@Nullable FragmentActivity mActivity, @Nullable RadioGroup group){
mContext = checkNotNull(mActivity, "FragmentActivity cannot be null!");
radioGroup = checkNotNull(group, "RadioGroup cannot be null!");
}
@Override
public void switchTo() {
FragmentUtils fragmentUtil = new FragmentUtils(mContext, R.id.view_container);
fragmentUtil.switchTo(OneFragment.class);
radioGroup.setOnCheckedChangeListener((group1, checkedId) -> {
switch (checkedId) {
case R.id.home_one:
fragmentUtil.switchTo(OneFragment.class);
break;
case R.id.home_reading:
fragmentUtil.switchTo(ReadingFragment.class);
break;
case R.id.home_music:
fragmentUtil.switchTo(MusicFragment.class);
break;
case R.id.home_movie:
fragmentUtil.switchTo(MovieFragment.class);
break;
default:
break;
}
});
}
@Override
public void start() {//有些地方 RxJava MediaPlayer Handler 等生命周期用得上
}
}
</code>
簡單的邏輯代碼交由Presenter 和Model協(xié)作實現(xiàn)搅裙≈遄浚可能表述 和理解的不是太好 歡迎指正。Demo架構(gòu)Dagger2+RxJava+Retrofit 雛形已經(jīng)大致出現(xiàn) 后面會陸續(xù)補充一些使用的小技巧 和 第三方的插入 譬如 微信熱修復(fù) 等等吧部逮。謝謝大家~

github demo地址

參考:
MVC vs. MVP vs. MVVM on Android
Android App的設(shè)計架構(gòu):MVC,MVP,MVVM與架構(gòu)經(jīng)驗談
官方MVP Dagger2

等等 分享幾個免費的api(侵刪 謝謝)
干貨Api
和風(fēng)天氣
one 抓包接口

歡迎加群:
QQ 群 521039620
原文博客地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末娜汁,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子兄朋,更是在濱河造成了極大的恐慌掐禁,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蜈漓,死亡現(xiàn)場離奇詭異穆桂,居然都是意外死亡,警方通過查閱死者的電腦和手機融虽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門享完,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人有额,你說我怎么就攤上這事钞翔。” “怎么了绊序?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵孔飒,是天一觀的道長。 經(jīng)常有香客問我萤衰,道長堕义,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任脆栋,我火速辦了婚禮倦卖,結(jié)果婚禮上洒擦,老公的妹妹穿的比我還像新娘。我一直安慰自己怕膛,他們只是感情好熟嫩,可當(dāng)我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著褐捻,像睡著了一般掸茅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上柠逞,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天昧狮,我揣著相機與錄音,去河邊找鬼边苹。 笑死陵且,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的个束。 我是一名探鬼主播慕购,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼茬底!你這毒婦竟也來了沪悲?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤阱表,失蹤者是張志新(化名)和其女友劉穎殿如,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體最爬,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡涉馁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了爱致。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片烤送。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖糠悯,靈堂內(nèi)的尸體忽然破棺而出帮坚,到底是詐尸還是另有隱情,我是刑警寧澤互艾,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布试和,位于F島的核電站,受9級特大地震影響纫普,放射性物質(zhì)發(fā)生泄漏阅悍。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望溉箕。 院中可真熱鬧晦墙,春花似錦、人聲如沸肴茄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寡痰。三九已至,卻和暖如春棋凳,著一層夾襖步出監(jiān)牢的瞬間拦坠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工剩岳, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留贞滨,地道東北人。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓拍棕,卻偏偏與公主長得像晓铆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子绰播,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,139評論 25 707
  • 轉(zhuǎn)載至:http://www.reibang.com/p/9a6845b26856 “Android MVP 詳解...
    SnowDragonYY閱讀 10,322評論 5 241
  • 作者:李旺成 時間:2016年4月3日 “Android MVP 詳解(下)”已經(jīng)發(fā)布骄噪,歡迎大家提建議。 MVP ...
    diygreen閱讀 128,873評論 86 1,321
  • 第一次月考來了蠢箩,以前都是我坐在下面链蕊,別人看著我,第一次我坐在上面谬泌,我看著別人滔韵。突然覺得學(xué)生們好傻,自以為在下...
    忘記了丶就不要再想起閱讀 174評論 0 0
  • 你有過這樣的經(jīng)歷嗎掌实?翻看朋友圈都是朋友發(fā)的旅行照片陪蜻,孩子照片,結(jié)婚照等潮峦,一遍遍看到空間里面自己的朋友動態(tài)里面五花八...
    風(fēng)帆正陽閱讀 226評論 0 0