é·ãéãç§ã¯RxPMãã¿ãŒã³ã«ã€ããŠèããŠãããããããã¯ã·ã§ã³ãã§ãããããŸãé©çšãããããŠããŸããã ç§ã¯ãã®ãããã¯ã«ã€ããŠæåã«Mobiusãšè©±ãäºå®ã§ããããããã°ã©ã å§å¡äŒã¯æåŠããã®ã§ãAndroidã³ãã¥ããã£ãšæ°ãããã¿ãŒã³ã®ããžã§ã³ãå
±æããããã®èšäºãä»å
¬éããŠããŸãã
誰ããMVPãšMVVMã«ç²ŸéããŠããŸãããMVVMããã¬ãŒã³ããŒã·ã§ã³ã¢ãã«ãã¿ãŒã³ã®è«ççãªéçºã§ããããšãç¥ã£ãŠãã人ã¯ã»ãšãã©ããŸããã çµå±ãMVVMãšPMã®å¯äžã®éãã¯ãèªåããŒã¿ãã€ã³ãã£ã³ã°ïŒ databinding ïŒã§ãã
ãã®èšäºã§ã¯ããªã¢ã¯ãã£ãããã³ã°ã䜿çšãããã¬ãŒã³ããŒã·ã§ã³ã¢ãã«ãã¿ãŒã³ã«çŠç¹ãåœãŠãŸãã 誀ã£ãŠRxMVVMãšåŒã¶äººãããŸãããããã¯ãã¬ãŒã³ããŒã·ã§ã³ã¢ãã«ãã³ãã¬ãŒãã®ä¿®æ£ã§ãããããRxPMãšåŒã¶ã®ãæ£ããã§ãããã
ãã®ãã¿ãŒã³ã¯ã Rxã䜿çšãããããžã§ã¯ãã§äœ¿çšãããšäŸ¿å©ã§ããããã«ãããã¢ããªã±ãŒã·ã§ã³ã®å¿çæ§ãåäžããããã§ãã ãŸããä»ã®ãã¿ãŒã³ã®åé¡ã¯å€ããããŸããã 次ã®å³ã¯ããã¬ãŒã³ããŒã·ã§ã³ãã³ãã¬ãŒãã®ããŸããŸãªãªãã·ã§ã³ãšåé¡ã瀺ããŠããŸãã
RxPMãã¿ãŒã³ã®èª¬æã«é²ãåã«ãæã人æ°ã®ããMVPïŒããã·ããã¥ãŒïŒãšMVVMãèŠãŠã¿ãŸãããã ãã¹ãŠã®ãã¿ãŒã³ãšãã®éãã®è©³çŽ°ãªèª¬æã¯ãåã®èšäºã«èšèŒãããŠããŸã ã
MVP vs PM vs MVVM
ãã¿ãŒã³ã®äžè¬çãªãã¿ãŒã³ã¯ããã€ã¢ã°ã©ã ã®åœ¢åŒã§è¡šãããšãã§ããŸãã
äžèŠãããšãããåºæ¬çãªéãã¯ãªãããã«æãããããããŸããã ããããããã¯äžèŠããã ãã§ãã éãã¯ãå販æ¥è
ã®è²¬ä»»ãšããã¥ãŒãšã®éä¿¡æ¹æ³ã«ãããŸãã ã¢ãã«ã¯ãã¹ãŠã®ãã¿ãŒã³ã§åãã«èŠããŸãã ãã®èšèšã¯è€éã§åºç¯ãªãããã¯ã§ãããããããã§ã¯èª¬æããŸããã æãäžè¬çãªãã¿ãŒã³ã§ããããã·ããã¥ãŒã®MVPããå§ããŸãããã ãã®äž»ãªåé¡ãèæ
®ããŠãã ããã
MVP
åŸæ¥ã®MVPã§ã¯ãUIã®ç¶æ
ãç¶æããã³åŸ©å
ãã責任ã¯Viewã«ãããŸãã Presenterã¯ã¢ãã«ã®å€æŽã®ã¿ãç£èŠããã€ã³ã¿ãŒãã§ã€ã¹ãä»ããŠãã¥ãŒãæŽæ°ããŸããå察ã«ãViewããã³ãã³ããåãåããã¢ãã«ãå€æŽããŸãã
ãã ããã¢ãã«ã®ããŒã¿ç¶æ
ã«å ããŠãè€éãªã€ã³ã¿ãŒãã§ã€ã¹ãå®è£
ããå ŽåãããŒã¿ã«é¢é£ããªãè¿œå ã®UIç¶æ
ããããŸãã ããšãã°ãç»é¢ã§åŒ·èª¿è¡šç€ºãããŠãããªã¹ãã¢ã€ãã ããå
¥åãã©ãŒã ã«å
¥åãããŠããããŒã¿ãããŠã³ããŒãããã»ã¹ã®é²è¡ç¶æ³ã«é¢ããæ
å ±ããããã¯ãŒã¯ãžã®èŠæ±ãªã©ã§ãã ãã¥ãŒã®UIç¶æ
ã®åŸ©å
ãšä¿åã¯ããã¥ãŒããæ»ã¬ãåŸåãããããã倧ããªåé¡ã§ãã ãŸãããããã¯ãŒã¯èŠæ±ã«é¢ããæ
å ±ã®è¡šç€ºã¯ãåºæ¬çã«ä¿åã§ããŸããã ãã¥ãŒããã¬ãŒã³ã¿ãŒããåæãããŠããéãããªã¯ãšã¹ãã¯ããããäœããã®çµæã§çµäºããŸãã
ãããã£ãŠãUIã®ç¶æ
ã埩å
ããäœæ¥ã¯ãã¬ãŒã³ã¿ãŒã«éä¿¡ãããŸãã ããã«ã¯ããã¬ãŒã³ã¿ãŒã®çŸåšã®ç¶æ
ã«è¿œå ã®ããŒã¿ãšãã©ã°ãä¿åãããã¥ãŒãã¢ã¿ããããããã³ã«ãããåçããå¿
èŠããããŸãã
2çªç®ã®åé¡ã¯ãããšãã°ç»é¢ãå転ããŠãããšããªã©ãViewããã¬ãŒã³ã¿ãŒãããã€ã§ãåæã§ãããšããåãæ¡ä»¶ã«èµ·å ããŸãã ãããã£ãŠããã¬ãŒã³ã¿ãŒã®Viewã€ã³ã¿ãŒãã§ã€ã¹ãžã®ãªã³ã¯ã¯ãªã»ãããããŸãã ãããã£ãŠããã¥ãŒãæŽæ°ããå¿
èŠãããå Žåã¯ãåžžã«null
ãã§ãã¯ãå®è¡ããå¿
èŠããããŸãã ããã¯éåžžã«é¢åã§ãã³ãŒããç
©éã«ãªããŸãã
3çªç®ã®åé¡ïŒViewã€ã³ã¿ãŒãã§ãŒã¹ã¯ã§ããã ã銬鹿ããŠããã¯ããªã®ã§ãViewã€ã³ã¿ãŒãã§ãŒã¹ãããçšåºŠè©³çŽ°ã«èšè¿°ããå¿
èŠããããŸãã ãŸãããã¬ãŒã³ã¿ãŒã¯ããã¥ãŒãç®çã®ç¶æ
ã«ããããã«å€ãã®ã¡ãœãããåŒã³åºãå¿
èŠããããŸãã ããã«ãããã³ãŒãã®éãå¢ããŸãã
ååŸ
Martin Fowlerã説æãã Presentation ModelãšåŒã°ããå¥ã®ãã¿ãŒã³ããããŸãã ãã®ãã¿ãŒã³ã®æ¬è³ªã¯ãããã¬ãŒã³ããŒã·ã§ã³ã¢ãã«ããšåŒã°ãããUIã®ç¶æ
ãæ ŒçŽããUIããžãã¯ãå«ãç¹å¥ãªã¢ãã«ãå°å
¥ãããããšã§ãã PresentationModelã¯ãGUIãã¬ãŒã ã¯ãŒã¯ã«äŸåããªãæœè±¡çãªãã¬ãŒã³ããŒã·ã§ã³ãšèŠãªãããå¿
èŠããããŸãã PresentationModelã¯ç¶æ
ãããããã£ãšããŠä¿åããViewã«ãã£ãŠèªã¿åãããŠç»é¢ã«è¡šç€ºãããŸãã ãã®ãã¿ãŒã³ã®äž»ãªåé¡ã¯ãPresentationModelãšViewç¶æ
ã®åæã§ãã ãObserverããã¿ãŒã³ãé©çšããããšã§ããããèªåã§åŠçããå¿
èŠããããŸãã ã»ãšãã©ã®å ŽåãUIå
šäœãæŽæ°ããªãããã«ãåããããã£ã®å€æŽã远跡ããå¿
èŠããããŸãã éå±ã§ç¹°ãè¿ãã®å€ãã³ãŒãããããããããŸãã
MVVM
ãæ°ã¥ããããããŸããããMVVMã¯ãã¬ãŒã³ããŒã·ã§ã³ã¢ãã«ã«éåžžã«ãã䌌ãŠããŸãã é©ãã¹ãããšã§ã¯ãããŸãããããã¯ãã®éçºã ããã§ãã PresentationModelã®ã¿ãViewModelãšåŒã°ããViewModelãšViewç¶æ
ã®åæã¯ãèªåããŒã¿ãã€ã³ãã£ã³ã°ãã€ãŸãããŒã¿åã«ãã£ãŠå®è¡ãããŸãã ãããããã®ãã¿ãŒã³ã«ã¯æ¬ é¥ããªãããã§ã¯ãããŸããã ããšãã°ãã¢ãã¡ãŒã·ã§ã³ããçŽç²ã«ãå®è£
ããããã³ãŒããããã¥ãŒã䜿çšããŠäœããå®è¡ãããããã®ã¯åé¡ã§ãã ãã®ããšã«ã€ããŠã¯ ãååã®Jeevuzã® èšäºã ã芧ãã ãã ã
MVVMãšRxPMã®è°è«ããã®åœŒã®ã³ã¡ã³ããå°ãèŠãŠã¿ãŸããããRxPMã«ã€ããŠè°è«ããçèãå§ãããšãããã®ãã¿ãŒã³ã¯MVVMã«ã€ããŠå¥œããªããšãã€ãŸãViewã®ã€ã³ã¿ãŒãã§ãŒã¹ãšããŠã®ViewModelã®æŠå¿µãå
ŒãåããŠããããåæã«äž»ãªæ¬ ç¹ã§ããå察æ§ãå«ãã§ããªãããšã«æ°ä»ããŸããã ããŒã¿ãã€ã³ãã£ã³ã°ããªããããããã¯è«ççã§ãã ããããåæã«ãRxã䜿çšãããã€ã³ãã¯ãDatabinding Libraryã䜿çšããèªåãã€ã³ããããããã»ã©è€éã§ã¯ãªããåæã«ãªã¢ã¯ãã£ãã¢ããªã±ãŒã·ã§ã³ã§ã®äœ¿çšã«ãéåžžã«é©ããŠããŸãã
ãã®çµæãRxPMã¯ç¶æ
ã®åé¡ã解決ããŸãã ç§ã®èšäºã®ã«ãŒããã¯ãã¥ãŒããèŠããŠããŸããïŒ ç¶æ
ã¯ãã£ãŒã«ãã®ã»ãããŸãã¯ã¢ã¯ã·ã§ã³ã®ã»ããã®ããããã§èšè¿°ã§ããããšã説æããŸããããããã£ãŠãRxPMã¯ããã2ã€ã®ã¡ãœãããèå³æ·±ãæ¹æ³ã§çµã¿åãããŸãããµãã¹ã¯ãªãã·ã§ã³ã§ïŒããããã¯åæã«ãã¢ã¯ã·ã§ã³ãã§ãã ãããŠãããã¯ã°ã©ãŠã³ãã§ïŒãã¥ãŒãååšããªãéã«ïŒçºçããã€ãã³ãã¯ããµãã¹ã¯ãªãã·ã§ã³äžã«å°çããããšãããããŸããã ãããïŒ
ããããäžèšã®ãã¹ãŠã®ãã¿ãŒã³ã®æãéèŠã§æ±ºå®çãªæ¬ ç¹ã¯ãViewãšä»²ä»è
ã®çžäºäœçšãåœä»€çãªã¹ã¿ã€ã«ã§å®è¡ãããããšã§ãã äžæ¹ãç®æšã¯ãªã¢ã¯ãã£ãã¢ããªã±ãŒã·ã§ã³ãäœæããããšã§ãã UIã¬ã€ã€ãŒã¯ãç¹ã«åçã€ã³ã¿ãŒãã§ã€ã¹ã§ã¯ãããŒã¿ãããŒã®ããªã倧ããªãœãŒã¹ã§ãããã¢ãã«ã§ã®éåæäœæ¥ã«ã®ã¿Rxã䜿çšããã®ã¯ç¡æå³ã§ãã
ãªã¢ã¯ãã£ããã¬ãŒã³ããŒã·ã§ã³ã¢ãã«
ãã¬ãŒã³ããŒã·ã§ã³ã¢ãã«ãã¿ãŒã³ã®äž»ãªåé¡ã¯ããã¬ãŒã³ããŒã·ã§ã³ã¢ãã«ãšãã¥ãŒã®éã®ç¶æ
ã®åæã§ããããšã¯æ¢ã«ããã£ãŠããŸãã æããã«ãå€æŽå¯èœãªããšãéç¥ã§ããããããã£ã§ããç£èŠå¯èœãªããããã£ã䜿çšããå¿
èŠããããŸãã RxJavaã¯ãã®åé¡ã解決ããã®ã«åœ¹ç«ã¡ãåæã«ãªã¢ã¯ãã£ãã¢ãããŒãã®ãã¹ãŠã®å©ç¹ãåŸãããšãã§ããŸãã
ãŸãããã¿ãŒã³ã¹ããŒã ãèŠãŠã¿ãŸãããã次ã«ãå®è£
ã®è©³çŽ°ãç解ããŸãã
ãããã£ãŠãRxPMã®éèŠãªèŠçŽ ã¯ãªã¢ã¯ãã£ãããããã£ã§ãã Rx-propertyã®åœ¹å²ã®æåã®åè£ã¯BehaviorSubjectã§ãã æåŸã®å€ãä¿åãããµãã¹ã¯ã©ã€ããããã³ã«å€ãæž¡ããŸãã
äžè¬ã«ã ãµããžã§ã¯ãã¯æ¬è³ªçã«äžæã§ããäžæ¹ã§ããããã¯Observableã®æ¡åŒµã§ãããä»æ¹ã§ã¯ãObserverã€ã³ã¿ãŒãã§ã€ã¹ãå®è£
ããŸãã ã€ãŸãã ãµããžã§ã¯ãããã¥ãŒã®çºä¿¡ããŒã¿ã¹ããªãŒã ãšããŠäœ¿çšã§ããPresentationModelã§ã¯çä¿¡ããŒã¿ã¹ããªãŒã ã®ã³ã³ã·ã¥ãŒãã«ãªããŸãã
ãããã 被éšè
ã«ã¯ç§ãã¡ã«åãå
¥ããããªãæ¬ é¥ããããŸãã Observableã³ã³ãã©ã¯ãã§ã¯ã onCompleteããã³onErrorã€ãã³ãã§çµäºã§ããŸã ã ãããã£ãŠã ãµããžã§ã¯ãã倱æããäœãã«ãµãã¹ã¯ã©ã€ããããå Žåããã§ãŒã³å
šäœãåæ¢ããŸãã ãã¥ãŒã¯ã€ãã³ãã®åä¿¡ãåæ¢ããå床ãµãã¹ã¯ã©ã€ãããå¿
èŠããããŸãã ããã«ãRxããããã£ã¯å®çŸ©äžã onCompleteããã³onErrorã€ãã³ããéä¿¡ã§ããŸãããããã¯ããã¥ãŒã®åãªãããŒã¿ïŒç¶æ
ïŒãœãŒã¹ã§ããããã§ãã ããã§ãJake Whartonã圌ã®RxRelayã©ã€ãã©ãªã§æå©ã«æ¥ãŸãã 圌ãªãã§ç§ãã¡ã¯äœãããŸããïŒ ãªã¬ãŒ ããšèšèŒãããæ¬ é¥ãæ¬ ããŠããŸãã
æŠåšåº«ã«ã¯ãããã€ãã®ãµãã¯ã©ã¹ããããŸãã
BehaviorRelay-æåŸã«åä¿¡ããå€ãä¿åãããµãã¹ã¯ã©ã€ããããã³ã«éä¿¡ããŸãã ç¶æ
ã®ä¿åãšå€æŽã«æé©ã§ãã
PublishRelayã¯åãªã泚ç®ã«å€ãããã®ã§ãã Viewã®ã³ãã³ããŸãã¯ã€ãã³ãã«é©ããŠããŸãã ããšãã°ããã€ã¢ãã°ã衚瀺ããããã¢ãã¡ãŒã·ã§ã³ãéå§ãããããŸãã Viewããã®ã³ãã³ãïŒã€ãã³ãïŒã®åä¿¡ã«ã䜿çšãããŸãã
- ReplayRelay-åä¿¡ãããã¹ãŠã®ã¢ã€ãã ããããã¡ã«ä¿åãã賌èªæã«ãã¹ãŠåçããŸãã éåžžã«ãŸãã«ãã䜿çšãããŸããããè€åæ¡ä»¶ã«åœ¹ç«ã€å ŽåããããŸãã æç»ã®äŸãæãæµ®ãã³ãŸãïŒç·ãåŒãã次ã«åãåŒããŸãã
ãã ãã Relayã®è¡šç€ºã¢ã¯ã»ã¹ãçŽæ¥æäŸããããšã¯ã§ããŸããã 誀ã£ãŠããããã£ã«å€ãå
¥åããããViewããã³ãã³ããåä¿¡ããããã«èšèšãããRelayããµãã¹ã¯ã©ã€ããããããå¯èœæ§ãããããã§ãã ãããã£ãŠãããããã£ãObservableãšããŠæ瀺ããViewããã®ã€ãã³ããªã¹ããŒãConsumerãšããŠæ瀺ããå¿
èŠããããŸãã ã¯ããã«ãã»ã«åã«ã¯ããã«å€ãã®ã³ãŒããå¿
èŠã«ãªããŸãããäžæ¹ã§ãããããã£ã®å Žæãšã³ãã³ãã®å Žæã¯ããã«ããããŸãã PresentationModelïŒpmïŒã®ããŠã³ããŒãã®é²è¡ç¶æ³ã®äŸïŒ
//State private val progress = BehaviorRelay.create<Int>() // property val progressState: Observable<Int> = progress.hide() // , fun progress(): Observable<Int> = progress.hide() //Action private val downloadClicks = PublishRelay.create<Unit>() // property val downloadClicksConsumer: Consumer<Unit> = downloadClicks // , fun downloadClicks(): Consumer<Unit> = downloadClicks
ç¶æ
ãšã¢ã¯ã·ã§ã³ãå®çŸ©ããã®ã§ããã¥ãŒã§ã®ã¿ãããã«ã¢ã¿ããã§ããŸãã ãããè¡ãã«ã¯ãå¥ã®Jake Wortonã©ã€ãã©ãª-RxBindingãå¿
èŠã§ã ã 圌ã¯ãã€å¯ãŸããïŒ
pm.progressState.subscribe { progressBar.progress() }
é©åãªObservableããªãå Žåã¯ã consumer.accept()
åŒã³åºãããšãã§ããŸã-ãŠã£ãžã§ãããªã¹ããŒããçŽæ¥ã
pm.downloadClicksConsumer.accept(Unit)
ãããŠä»ãå®éã«
次ã«ãäžèšã®ãã¹ãŠãããŒãã«åéããäŸã䜿çšããŠåæããŸãã PresentationModelã®èšèšã¯ã次ã®æé ã«åé¡ã§ããŸãã
- ãã¥ãŒã«ä¿åããå¿
èŠãããPresentationModelã®ç¶æ
ïŒããŒã¿ãããŒãã¹ããŒã¿ã¹ã衚瀺ããå¿
èŠããããšã©ãŒãªã©ïŒã決å®ããŸãã
- ãã¥ãŒã§çºçããå¯èœæ§ã®ããã€ãã³ããå€å¥ããŸãããã¿ã³ã®ã¯ãªãã¯ãå
¥åãã£ãŒã«ããžã®å
¥åãªã©ã
- PresentationModelãäœæããå ŽåãRxãèš±å¯ããããã«ã宣èšåã¹ã¿ã€ã«ã§ç¶æ
ãã³ãã³ããããã³ã¢ãã«ãé¢é£ä»ããŸãã
- ãã¥ãŒãPresentationModelã«ãã€ã³ãããŸãã
ããšãã°ãããã¹ãå
ã®åèªãèŠã€ããã¿ã¹ã¯ãèããŠã¿ãŸãããã
- æ€çŽ¢ããããã¹ãã®å
¥åãã£ãŒã«ãããããŸãã
- æ€çŽ¢ããåèª/éšåã®å
¥åãã£ãŒã«ãããããŸãã
- ãã¿ã³ãã¯ãªãã¯ããŠãæ€çŽ¢ãéå§ããŸãã
- æ€çŽ¢äžã«é²è¡ç¶æ³ã衚瀺ããŸããä»åã¯ãã¿ã³ããããã¯ããŸãã
- åçãåãåã£ãåŸãèŠã€ãã£ãåèªã®ãªã¹ãã衚瀺ããŸãã
ã€ã³ã¿ã©ã¯ã¿ãŒã®ãã¡ãµãŒãã®èåŸã«æ€çŽ¢ã¢ã«ãŽãªãºã ãé衚瀺ã«ããŸãã
data class SearchParams(val text: String, val query: String) interface Interactor { fun findWords(params: SearchParams): Single<List<String>> } class InteractorImpl : Interactor { override fun findWords(params: SearchParams): Single<List<String>> { return Single .just(params) .map { (text, query) -> text .split(" ", ",", ".", "?", "!", ignoreCase = true) .filter { it.contains(query, ignoreCase = true) } } .subscribeOn(Schedulers.computation()) } }
å
·äœçãªäŸã§ã¯ãSingleãšRxããŸã£ãããªããŠãããŸããŸããããã€ã³ã¿ãŒãã§ã€ã¹ã¯åäžã«ä¿ã¡ãŸãã ç¹ã«å®éã®ã¢ããªã±ãŒã·ã§ã³ã§ã¯ã Retrofitãä»ãããããã¯ãŒã¯ãžã®èŠæ±ããããŸãã
次ã«ãPresentationModelãèšèšããŸãã
ãã¥ãŒã®ç¶æ
ïŒèŠã€ãã£ãåèªã®ãªã¹ããèªã¿èŸŒã¿ã¹ããŒã¿ã¹ãæ€çŽ¢ãã¿ã³ã®ã¢ã¯ãã£ããã£ãã©ã°ã ãã¿ã³ã®æå¹ç¶æ
ã¯PresentationModelã®ããŒããã©ã°ã«ãã€ã³ãã§ããŸããããã¥ãŒã®å Žåã¯åå¥ã®ããããã£ãæäŸããå¿
èŠããããŸãã ãã¥ãŒã®ããŒããã©ã°ã«ã¹ãããããã ãã§ã¯ã©ãã§ããïŒ ããã§ã¯ãããŒããšæå¹åãšãã2ã€ã®ç¶æ
ãããããšã確èªããå¿
èŠããããŸããããã®å ŽåãPresentationModelãããããæ¥ç¶ããŠããããšãäžèŽããŸããã äžè¬çãªå Žåããããã¯ç¬ç«ããŠããå ŽåããããŸãã ããšãã°ããŠãŒã¶ãŒãæå°æåæ°ãå
¥åãããŸã§ãã¿ã³ãããã¯ããå Žåã
ãã¥ãŒããã®ã€ãã³ãïŒããã¹ãã®å
¥åãæ€çŽ¢ã¯ãšãªã®å
¥åããã¿ã³ã®ã¯ãªãã¯ã ããã§ã¯ãã¹ãŠãç°¡åã§ããããã¹ãããã£ã«ã¿ãŒåŠçããããã¹ããšæ€çŽ¢æååã1ã€ã®ãªããžã§ã¯ãSearchParamsã«çµåããŸãã ãã¿ã³ãã¯ãªãã¯ããŠãæ€çŽ¢ã¯ãšãªãäœæããŸãã
ã³ãŒãã§ã¯æ¬¡ã®ããã«ãªããŸãã
class TextSearchPresentationModel { private val interactor: Interactor = InteractorImpl() // --- States --- private val foundWords = BehaviorRelay.create<List<String>>() val foundWordState: Observable<List<String>> = foundWords.hide() private val loading = BehaviorRelay.createDefault<Boolean>(false) val loadingState: Observable<Boolean> = loading.hide() val searchButtonEnabledState: Observable<Boolean> = loading.map { !it }.hide() // -------------- // --- UI-events --- private val searchQuery = PublishRelay.create<String>() val searchQueryConsumer: Consumer<String> = searchQuery private val inputTextChanges = PublishRelay.create<String>() val inputTextChangesConsumer: Consumer<String> = inputTextChanges private val searchButtonClicks = PublishRelay.create<Unit>() val searchButtonClicksConsumer: Consumer<Unit> = searchButtonClicks // --------------- private var disposable: Disposable? = null fun onCreate() { val filteredText = inputTextChanges.filter(String::isNotEmpty) val filteredQuery = searchQuery.filter(String::isNotEmpty) val combine = Observable.combineLatest(filteredText, filteredQuery, BiFunction(::SearchParams)) val requestByClick = searchButtonClicks.withLatestFrom(combine, BiFunction<Unit, SearchParams, SearchParams> { _, params: SearchParams -> params }) disposable = requestByClick .filter { !isLoading() } .doOnNext { showProgress() } .delay(3, TimeUnit.SECONDS) // .flatMap { interactor.findWords(it).toObservable() } .observeOn(AndroidSchedulers.mainThread()) .doOnEach { hideProgress() } .subscribe(foundWords) } fun onDestroy() { disposable?.dispose() } private fun isLoading() = loading.value private fun showProgress() = loading.accept(true) private fun hideProgress() = loading.accept(false) }
ãã¥ãŒã®åœ¹å²ã§ã¯ããã©ã°ã¡ã³ãããããŸãã
class TextSearchFragment : Fragment() { private val pm = TextSearchPresentationModel() private var composite = CompositeDisposable() private lateinit var inputText: EditText private lateinit var queryEditText: EditText private lateinit var searchButton: Button private lateinit var progressBar: ProgressBar private lateinit var resultText: TextView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) retainInstance = true
GitHubã§å®å
šãªäŸãèŠãããšãã§ããŸãã
ãŸãšãããš
æ°ããRxPMãã¿ãŒã³ã«åºäŒããä»ã®ãã¬ãŒã³ããŒã·ã§ã³ãã³ãã¬ãŒãã®æ¬ ç¹ã調ã¹ãŸããã ããããMVPãšMVVMãRxPMãããæªããŸãã¯åªããŠãããšã¯ã£ãããšèšãããã¯ãããŸããã ç§ã¯ãå€ãã®äººãšåæ§ã«ããã®ã·ã³ãã«ããšççŽãããMVPã倧奜ãã§ãã ãŸããã¬ã€ã¢ãŠãå
ã®ã³ãŒãã¯ã¢ããã¥ã¢ã§ãããMVVMã¯èªåããŒã¿ãã€ã³ãã£ã³ã°ã«é©ããŠããŸãã
ããããåçãªUIãåããææ°ã®ã¢ããªã±ãŒã·ã§ã³ã«ã¯ãå€ãã®ã€ãã³ãã³ãŒããšéåæã³ãŒãããããŸãã ãããã£ãŠãç§ã®éžæã¯ããªã¢ã¯ãã£ãã¢ãããŒããšRxPMã«åŸããŠããŸãã Jake Wortonã®ãã¬ãŒã³ããŒã·ã§ã³ããã®èšèãåŒçšããŸãããªãç§ãã¡ã®ã¢ããªã±ãŒã·ã§ã³ã¯ãªã¢ã¯ãã£ãã§ãªããã°ãªããªãã®ã§ããããã
ã·ã¹ãã å
šäœãåæçã«ã¢ãã«åã§ããªãéããåäžã®éåæãœãŒã¹ã¯åœä»€åããã°ã©ãã³ã°ãäžæããŸãã
ã·ã¹ãã å
šäœãåæçã«ã·ãã¥ã¬ãŒãã§ããªãå ŽåãéåæãœãŒã¹ã1ã€ã§ãåœä»€åããã°ã©ãã³ã°ãäžæããŸãã
ãã¡ãããRxPMã«ã¯é·æãšçæã®äž¡æ¹ããããŸãã
é·æïŒ
- Observableã®ãªã¢ã¯ãã£ããã§ãŒã³ãå£ãããã¢ãã«ãããã¥ãŒãžããŸãã¯ãã®éã«ã¹ãã¬ããããããšã¯ã§ããŸããã ããã«ãããViewãšã®å¿
é ã®çžäºäœçšããªããªããŸãã
- PresentationModelã®ããžãã¯ã®å®£èšçãªèª¬æã
- PresentationModelã¯Viewã®æœè±¡åã§ãããç¹å®ã®ãŠã£ãžã§ããã«é¢é£ä»ããããŠããŸããã
- ãã¥ãŒãæ·»ä»ãããŠãããã©ãããå¿é
ããå¿
èŠã¯ãããŸããã Rx-propertyã®å€ãå€æŽããã ãã§ãã ãã¥ãŒã¯ããµãã¹ã¯ã©ã€ããããšèªåçã«ç¶æ
ãåãåããŸãã
- ãã¥ãŒããã€ãã³ãããªã¢ã¯ãã£ãã¹ã¿ã€ã«ã§ååŸããŸããRxæŒç®åã䜿çšããŠãã£ã«ã¿ãªã³ã°ãçµåãªã©ãè¡ããšäŸ¿å©ã§ãã
çæïŒ
- ãã€ã³ãã£ã³ã°ã³ãŒããèšè¿°ããå¿
èŠããããŸãããRxã§ã¯ç°¡åã§ãã
- Relayãã«ãã»ã«åããView as Observable and ConsumerãšããŠè¡šç€ºããå¿
èŠããããŸãã ããã¯ä»ã®ãšããç§ãæ©ãŸãå¯äžã®ãã®ã§ãã
- Rxã®è±å¯ãã ãã€ãã¹ãšãã©ã¹ã®äž¡æ¹ãšèããããšãã§ããŸãã åå¿æ§ã¯å¥ã®ãã©ãã€ã ã§ãããããRxã®äœ¿çšãéå§ãããšãã«ããããããããå Žæã§äœ¿çšããªããã°ãªããªãããšã¯é©ãããšã§ã¯ãããŸããã Javaã§ããã°ã©ãã³ã°ããå Žåãå€ãã®ãªããžã§ã¯ããã ãŸã人ã¯ããŸããããããOOPãã©ãã€ã ã§ãã
ããã¯ããããå®å
šãªãªã¹ãã§ã¯ãããŸããã ããªããèŠãè³åŠäž¡è«ãã³ã¡ã³ãã«æžããŠãã ãããããªãã®æèŠãç¥ãããšã¯èå³æ·±ãã§ãããã
ãããã£ãŠãRxã«èªä¿¡ãããããªã¢ã¯ãã£ãã¢ããªã±ãŒã·ã§ã³ãäœæããå Žåãdatabindingã䜿çšããMVPããã³MVVMã«ããããããŠããå Žåã¯ãRxPMãè©ŠããŠãã ããã ãŸããããªãããã§ã«å¿«é©ã§ããã°ãç§ã¯ããªãã説åŸããŸãã;ïŒ
PS
æŽç·ŽãããAndroidéçºè
ã¯ãã©ã€ããµã€ã¯ã«ã«ã€ããŠãããã³ããŒããŒã·ã§ã³äžã®PresentationModelã®ä¿åã«ã€ããŠã¯äœãèšããªãã£ãããšã«æãæ°ã¥ããã§ãããã ãã®åé¡ã¯ãã®ãã¿ãŒã³ã«åºæã®ãã®ã§ã¯ãªããåå¥ã«èæ
®ããå¿
èŠããããŸãã ç§ã®èšäºã§ã¯ããã¿ãŒã³ã®æ¬è³ªã«çŠç¹ãåœãŠãããšæããŸãããMVPãMVVMãšæ¯èŒããå Žåã®é·æãšçæã§ãã ãŸãã åæ¹åã®ããŒã¿ãã€ã³ãã£ã³ã° ãRxPMã®ã³ã³ããã¹ãã§ã®ç»é¢éã®ããã²ãŒã·ã§ã³ãªã©ãéèŠãªãããã¯ã¯ã«ããŒãããŠããŸããã§ããã 次ã®èšäºã§ã¯ã Jeevuzãšäžç·ã«ãå®éã®ãããžã§ã¯ãã§RxPMã®äœ¿çšãéå§ããæ¹æ³ã«ã€ããŠèª¬æããã¢ããªã±ãŒã·ã§ã³ãç°¡çŽ åããã©ã€ãã©ãªãœãªã¥ãŒã·ã§ã³ã玹ä»ããŸãã