Android架構(gòu):RxJava+MVVM

MVP的一些小問題

說(shuō)到Android應(yīng)用開發(fā)的架構(gòu),大多數(shù)人可能都會(huì)說(shuō)出MVP。

的確,MVP架構(gòu)的出現(xiàn)為我們的Activity和Fragment的減肥瘦身做出的很大的貢獻(xiàn)。但是基于一些原因,我和小伙伴們決定無(wú)情的將他拋棄,尋求更好的方案。

起因是這樣的,在一次迭代中,我們決定將DI(dagger2)引入到項(xiàng)目中,而且我們順理成章的認(rèn)為,MVP也可以通過(guò)注入方式初始化,想象的代碼能變成這樣:

class MainActivity implement MainView{
  @Inject MainPresenter presenter;
  ...
}

class MainPresenter {
  @Inject MainView view;
  @Inject MainModel model;
  ...
}

但在后來(lái)接入的過(guò)程中,我們發(fā)現(xiàn)這個(gè)方案沒有辦法直接走通。因?yàn)樵?code>MainPresenter中注入view時(shí),dagger并不知道view的實(shí)例從何而來(lái),因此我們需要借助一個(gè)Module來(lái)把view的實(shí)例provide出來(lái):

@Module
class MainModule {
  MainActivity activity;
  MainMoudle(MainActivity activity) { this.activity = activity; }
  @Provide MainView mainView(){ return activity; }
}

這意味著,每個(gè)Activity都需要建立一個(gè)對(duì)應(yīng)的Module,這樣每次初始化Component的成本,和我們用傳統(tǒng)方式在Presenter里綁定View的成本沒有什么區(qū)別。

傳統(tǒng)方式綁定:

class MainActivity implement MainView {
  MainPresenter presenter;
  void onCreate(){
    presenter = new MainPresenter(this);
  }
}

的確,對(duì)于DI的使用來(lái)說(shuō),這種綁定方式理所應(yīng)當(dāng)。究其原因,是因?yàn)樵贛VP中,View和Presenter互相引用了。

除此之外,相互引用還會(huì)造成很多問題。比如異步操作可能會(huì)造成View無(wú)法回收;比如Presenter大多時(shí)候無(wú)法重用。。

結(jié)合J2EE成熟的后端架構(gòu)來(lái)看。MVP做到了分離界面和業(yè)務(wù)代碼,但是模塊化,分層,可復(fù)用等等的功能都比較難使用。所以與其說(shuō)是一種“架構(gòu)”,不如稱之為一種“代碼優(yōu)化方式”更為恰當(dāng)。

MVVM怎么做

假設(shè)需求是讀取手機(jī)聯(lián)系人并顯示,MVP的做法是:

class Presenter {
  void loadContacts(){
    new Thread(()->{
      // .... 加載聯(lián)系人
      view.showContacts(contactsList);
    }).start();
  }
}

interface View {
  void showContacts(List<Contacts> contactsList);
}

MVVM也類似,但是他不直接把列表傳給view,而是傳給一個(gè)可訂閱對(duì)象,在RxJava里我們使用Subject:

class ViewModel {
  Subject<List<Contacts>,List<Contacts>> loadContactsObs = PublishSubject.create();
  void loadContacts() {
    new Thread(()->{
      // .... 加載聯(lián)系人
      loadContactsObs.onNext(contactsList); // 讓subject接收聯(lián)系人列表
    }).start();
  }
}

class Activity {
  ViewModel viewModel;
  void onCreate(){
    viewMode.loadContactsObs.subscribe(list ->
        this.showContacts(list));
    viewMode.loadContacts();
  }
}

這樣一來(lái),Actvity持有ViewModel,ViewModel進(jìn)一步持有處理業(yè)務(wù)關(guān)系的模塊。每個(gè)模塊之間不會(huì)有互相的引用。這樣帶來(lái)的好處有:

首先,我們的注入代碼變成了類似:

class MainActivity {
  @Inject MainViewModel viewModel;
  ...
}

class MainViewModel {
  @Inject MainModel model;
  ...
}

其次,ViewModel真正實(shí)現(xiàn)了可重用。不像實(shí)現(xiàn)Presenter必須實(shí)現(xiàn)對(duì)應(yīng)的View,使用ViewModel我們可以靈活選擇訂閱/不訂閱相應(yīng)的返回事件。

還有,由于訂閱的是Rx的Subject,我們可以使用Rx帶的強(qiáng)大的api直接進(jìn)行邏輯優(yōu)化~

大概的介紹就是這樣,實(shí)際開發(fā)過(guò)程中也出現(xiàn)了不少的問題和可優(yōu)化的地方,例如MVP面向接口編程的思想,同樣可以應(yīng)用到MVVM中;例如MVVM結(jié)合DI的進(jìn)一步優(yōu)化等等,需要之后好好整理一下。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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