Upgrade to Pro — share decks privately, control downloads, hide ads and more …

社内勉強会資料_Flux

RyoWATANABE
February 22, 2018

 社内勉強会資料_Flux

RyoWATANABE

February 22, 2018
Tweet

More Decks by RyoWATANABE

Other Decks in Technology

Transcript

  1. View class MainActivity : View(), HasSupportFragmentInjector { @Inject lateinit var

    androidInjector: DispatchingAndroidInjector<Fragment> @Inject lateinit var actionCreator: MainActionCreator @Inject lateinit var store: MainStore private val binding: ActivityGalleryBinding by contentViewBinding(R.layout.activity_gallery) private var adapter: PhotosAdapter? = null … override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) … store.photos .subscribe { // it : List<MaterialPhoto> adapter = PhotosAdapter( this@MainActivity, it.toMutableList(), object : PhotosAdapter.OnItemClickListener { override fun onItemClick(item: MaterialPhoto) { actionCreator.showPhoto(this@MainActivity, item.id) } }) binding.recyclerView.also { it.adapter = adapter } adapter?.notifyDataSetChanged() } .disposeWhenDestroy() actionCreator.fetchPopularPhotos(0) } } ޙ΄Ͳઆ໌
  2. Action sealed class MainAction<out T>(override val type: String) : Action<T>

    { class RefreshPhotos(override val data: List<MaterialPhoto>) : MainAction<List<MaterialPhoto>>(TYPE) { companion object { const val TYPE = "MainAction.RefreshPhotos" } } class ShowPhoto(override val data: MaterialPhoto) : MainAction<MaterialPhoto>(TYPE) { companion object { const val TYPE = "MainAction.ShowPhoto" } } } ޙ΄Ͳઆ໌
  3. ActionCreator @PerActivityScope class MainActionCreator @Inject constructor( private val dispatcher: Dispatcher,

    private val repository: ImageFlickrRepository ) { companion object { private const val SEARCH_TEXT = "owl" private const val PER_PAGE = 32 } fun fetchPopularPhotos(page: Int) { repository.findByText(SearchOrderType.POPULAR, SEARCH_TEXT, page, PER_PAGE) .subscribeOn(Schedulers.io()) .subscribeBy( onNext = { dispatcher.dispatch(MainAction.RefreshPhotos(it)) }, onError = { // Timber.e(it) } ) } fun showPhoto(activity: AppCompatActivity, materialPhotoId: MaterialPhotoId) { PhotoDialogFragment.newInstance(materialPhotoId) .show(activity.supportFragmentManager, "MainAction.PhotoDialog") } } ޙ΄Ͳઆ໌
  4. Pub/SubܕLibrary • EventBus(greenrobot) • Otto (square.inc) • RxJava(Subject and Processor)

    “Androidʹ͓͍ͯ͸DispacherͱͳΔΫϥεͷΠϯελϯε؅ཧʹ͸ؾΛ͚ͭΔඞཁ͕͋Γ·͢ɻ Applicationͱಉ͡ϥΠϑαΠΫϧΛ࣋ͭΫϥεɺ΋͘͠͸γϯάϧτϯʹͳΔ͜ͱ͕ଟ͍Ͱ͠ΐ͏ɻ”
  5. Dispatcher @Singleton class Dispatcher @Inject constructor() { private val dispatcherProcessor:

    FlowableProcessor<Action<*>> = PublishProcessor.create<Action<*>>() fun <T> dispatch(action: Action<T>) { dispatcherProcessor.onNext(action) } fun on(type: String) = dispatcherProcessor.filter { it.type == type } } ޙ΄Ͳઆ໌
  6. Store class MainStore @Inject constructor(private val dispatcher: Dispatcher) : Store()

    { private val _photos = BehaviorProcessor.create<List<MaterialPhoto>>() private val _photo = BehaviorProcessor.create<MaterialPhoto>() val photos: Flowable<List<MaterialPhoto>> = _photos val photo: Flowable<MaterialPhoto> = _photo init { dispatcher.on(MainAction.RefreshPhotos.TYPE) .map { (it as MainAction.RefreshPhotos).data } .observeOn(AndroidSchedulers.mainThread()) .subscribe(_photos) dispatcher.on(MainAction.ShowPhoto.TYPE) .map { (it as MainAction.ShowPhoto).data } .observeOn(AndroidSchedulers.mainThread()) .subscribe(_photo) } } ޙ΄Ͳઆ໌
  7. Api interface FlickrApiService { /** * https://www.flickr.com/services/api/flickr.photos.search.html */ @GET("/services/rest?method=flickr.photos.search&api_key=" +

    BuildConfig.FLICKR_API_KEY + "&format=json&nojsoncallback=1") fun photoSearch(@Query("text") text: String, @Query("page") page: Int?, @Query("per_page") perpage: Int?, @Query("sort") sort: String): Observable<FlickrPhotoResponse> }
  8. Repository interface ImageFlickrRepository { fun findByText(searchOrderType: SearchOrderType, text: String, page:

    Int, perPage: Int): Observable<List<MaterialPhoto>> fun findById(materialPhotoId: MaterialPhotoId): Observable<MaterialPhoto> fun clearCache(searchOrderType: SearchOrderType, text: String): Single<Int> }
  9. Repository Impl class ImageFlickrRepositoryImpl( private val remote: ImageFlickrDataSource, private val

    local: ImageFlickrDataSource ) : ImageFlickrRepository { override fun findByText(searchOrderType: SearchOrderType, text: String, page: Int, perPage: Int): Observable<List<MaterialPhoto>> { return remote.findByText(searchOrderType, text, page, perPage) .observeOn(Schedulers.newThread()) .doOnNext { p: List<FlickrPhoto> -> local.updateCache(searchOrderType, text, page, p) } .filter{ photos -> !photos.isEmpty()} .first(ArrayList()) .toObservable() .observeOn(AndroidSchedulers.mainThread()) .map { MaterialImageMapper.transform(it) } } override fun findById(materialPhotoId: MaterialPhotoId): Observable<MaterialPhoto> {} override fun clearCache(searchOrderType: SearchOrderType, text: String): Single<Int> {} }
  10. class ImageFlickrRepositoryImpl( private val remote: ImageFlickrDataSource, private val local: ImageFlickrDataSource

    ) : ImageFlickrRepository { override fun findByText(searchOrderType: SearchOrderType, text: String, page: Int, perPage: Int): Observable<List<MaterialPhoto>> { return remote.findByText(searchOrderType, text, page, perPage) .observeOn(Schedulers.newThread()) .doOnNext { p: List<FlickrPhoto> -> local.updateCache(searchOrderType, text, page, p) } .filter{ photos -> !photos.isEmpty()} .first(ArrayList()) .toObservable() .observeOn(AndroidSchedulers.mainThread()) .map { MaterialImageMapper.transform(it) } } override fun findById(materialPhotoId: MaterialPhotoId): Observable<MaterialPhoto> {} override fun clearCache(searchOrderType: SearchOrderType, text: String): Single<Int> {} } Repository Impl class ImageFlickrRepositoryImpl( private val remote: ImageFlickrDataSource, private val local: ImageFlickrDataSource ) : ImageFlickrRepository { override fun findByText(searchOrderType: SearchOrderType, text: String, page: Int, perPage: Int): Observable<List<MaterialPhoto>> { return remote.findByText(searchOrderType, text, page, perPage) .observeOn(Schedulers.newThread()) .doOnNext { p: List<FlickrPhoto> -> local.updateCache(searchOrderType, text, page, p) } .filter{ photos -> !photos.isEmpty()} .first(ArrayList()) .toObservable() .observeOn(AndroidSchedulers.mainThread()) .map { MaterialImageMapper.transform(it) } } override fun findById(materialPhotoId: MaterialPhotoId): Observable<MaterialPhoto> {} override fun clearCache(searchOrderType: SearchOrderType, text: String): Single<Int> {} }
  11. Repository Impl class ImageFlickrRepositoryImpl( private val remote: ImageFlickrDataSource, private val

    local: ImageFlickrDataSource ) : ImageFlickrRepository { override fun findByText(searchOrderType: SearchOrderType, text: String, page: Int, perPage: Int): Observable<List<MaterialPhoto>> { return remote.findByText(searchOrderType, text, page, perPage) .observeOn(Schedulers.newThread()) .doOnNext { p: List<FlickrPhoto> -> local.updateCache(searchOrderType, text, page, p) } .filter{ photos -> !photos.isEmpty()} .first(ArrayList()) .toObservable() .observeOn(AndroidSchedulers.mainThread()) .map { MaterialImageMapper.transform(it) } } override fun findById(materialPhotoId: MaterialPhotoId): Observable<MaterialPhoto> {} override fun clearCache(searchOrderType: SearchOrderType, text: String): Single<Int> {} }
  12. Repository Impl class ImageFlickrRepositoryImpl( private val remote: ImageFlickrDataSource, private val

    local: ImageFlickrDataSource ) : ImageFlickrRepository { override fun findByText(searchOrderType: SearchOrderType, text: String, page: Int, perPage: Int): Observable<List<MaterialPhoto>> { return remote.findByText(searchOrderType, text, page, perPage) .observeOn(Schedulers.newThread()) .doOnNext { p: List<FlickrPhoto> -> local.updateCache(searchOrderType, text, page, p) } .filter{ photos -> !photos.isEmpty()} .first(ArrayList()) .toObservable() .observeOn(AndroidSchedulers.mainThread()) .map { MaterialImageMapper.transform(it) } } override fun findById(materialPhotoId: MaterialPhotoId): Observable<MaterialPhoto> {} override fun clearCache(searchOrderType: SearchOrderType, text: String): Single<Int> {} }
  13. Repository Impl class ImageFlickrRepositoryImpl( private val remote: ImageFlickrDataSource, private val

    local: ImageFlickrDataSource ) : ImageFlickrRepository { override fun findByText(searchOrderType: SearchOrderType, text: String, page: Int, perPage: Int): Observable<List<MaterialPhoto>> { return remote.findByText(searchOrderType, text, page, perPage) .observeOn(Schedulers.newThread()) .doOnNext { p: List<FlickrPhoto> -> local.updateCache(searchOrderType, text, page, p) } .filter{ photos -> !photos.isEmpty()} .first(ArrayList()) .toObservable() .observeOn(AndroidSchedulers.mainThread()) .map { MaterialImageMapper.transform(it) } } override fun findById(materialPhotoId: MaterialPhotoId): Observable<MaterialPhoto> {} override fun clearCache(searchOrderType: SearchOrderType, text: String): Single<Int> {} }
  14. Repository Impl class ImageFlickrRepositoryImpl( private val remote: ImageFlickrDataSource, private val

    local: ImageFlickrDataSource ) : ImageFlickrRepository { override fun findByText(searchOrderType: SearchOrderType, text: String, page: Int, perPage: Int): Observable<List<MaterialPhoto>> { return remote.findByText(searchOrderType, text, page, perPage) .observeOn(Schedulers.newThread()) .doOnNext { p: List<FlickrPhoto> -> local.updateCache(searchOrderType, text, page, p) } .filter{ photos -> !photos.isEmpty()} .first(ArrayList()) .toObservable() .observeOn(AndroidSchedulers.mainThread()) .map { MaterialImageMapper.transform(it) } } override fun findById(materialPhotoId: MaterialPhotoId): Observable<MaterialPhoto> {} override fun clearCache(searchOrderType: SearchOrderType, text: String): Single<Int> {} }
  15. Action sealed class MainAction<out T>(override val type: String) : Action<T>

    { class RefreshPhotos(override val data: List<MaterialPhoto>) : MainAction<List<MaterialPhoto>>(TYPE) { companion object { const val TYPE = "MainAction.RefreshPhotos" } } class ShowPhoto(override val data: MaterialPhoto) : MainAction<MaterialPhoto>(TYPE) { companion object { const val TYPE = "MainAction.ShowPhoto" } } }
  16. Action sealed class MainAction<out T>(override val type: String) : Action<T>

    { class RefreshPhotos(override val data: List<MaterialPhoto>) : MainAction<List<MaterialPhoto>>(TYPE) { companion object { const val TYPE = "MainAction.RefreshPhotos" } } class ShowPhoto(override val data: MaterialPhoto) : MainAction<MaterialPhoto>(TYPE) { companion object { const val TYPE = "MainAction.ShowPhoto" } } }
  17. Action sealed class MainAction<out T>(override val type: String) : Action<T>

    { class RefreshPhotos(override val data: List<MaterialPhoto>) : MainAction<List<MaterialPhoto>>(TYPE) { companion object { const val TYPE = "MainAction.RefreshPhotos" } } class ShowPhoto(override val data: MaterialPhoto) : MainAction<MaterialPhoto>(TYPE) { companion object { const val TYPE = "MainAction.ShowPhoto" } } }
  18. ActionCreator @PerActivityScope class MainActionCreator @Inject constructor( private val dispatcher: Dispatcher,

    private val repository: ImageFlickrRepository ) { companion object { private const val SEARCH_TEXT = "owl" private const val PER_PAGE = 32 } fun fetchPopularPhotos(page: Int) { repository.findByText(SearchOrderType.POPULAR, SEARCH_TEXT, page, PER_PAGE) .subscribeOn(Schedulers.io()) .subscribeBy( onNext = { dispatcher.dispatch(MainAction.RefreshPhotos(it)) }, onError = { // Timber.e(it) } ) } fun showPhoto(activity: AppCompatActivity, materialPhotoId: MaterialPhotoId) { PhotoDialogFragment.newInstance(materialPhotoId) .show(activity.supportFragmentManager, "MainAction.PhotoDialog") } }
  19. ActionCreator @PerActivityScope class MainActionCreator @Inject constructor( private val dispatcher: Dispatcher,

    private val repository: ImageFlickrRepository ) { companion object { private const val SEARCH_TEXT = "owl" private const val PER_PAGE = 32 } fun fetchPopularPhotos(page: Int) { repository.findByText(SearchOrderType.POPULAR, SEARCH_TEXT, page, PER_PAGE) .subscribeOn(Schedulers.io()) .subscribeBy( onNext = { dispatcher.dispatch(MainAction.RefreshPhotos(it)) }, onError = { // Timber.e(it) } ) } fun showPhoto(activity: AppCompatActivity, materialPhotoId: MaterialPhotoId) { PhotoDialogFragment.newInstance(materialPhotoId) .show(activity.supportFragmentManager, "MainAction.PhotoDialog") } }
  20. ActionCreator @PerActivityScope class MainActionCreator @Inject constructor( private val dispatcher: Dispatcher,

    private val repository: ImageFlickrRepository ) { companion object { private const val SEARCH_TEXT = "owl" private const val PER_PAGE = 32 } fun fetchPopularPhotos(page: Int) { repository.findByText(SearchOrderType.POPULAR, SEARCH_TEXT, page, PER_PAGE) .subscribeOn(Schedulers.io()) .subscribeBy( onNext = { dispatcher.dispatch(MainAction.RefreshPhotos(it)) }, onError = { // Timber.e(it) } ) } fun showPhoto(activity: AppCompatActivity, materialPhotoId: MaterialPhotoId) { PhotoDialogFragment.newInstance(materialPhotoId) .show(activity.supportFragmentManager, "MainAction.PhotoDialog") } }
  21. ActionCreator @PerActivityScope class MainActionCreator @Inject constructor( private val dispatcher: Dispatcher,

    private val repository: ImageFlickrRepository ) { companion object { private const val SEARCH_TEXT = "owl" private const val PER_PAGE = 32 } fun fetchPopularPhotos(page: Int) { repository.findByText(SearchOrderType.POPULAR, SEARCH_TEXT, page, PER_PAGE) .subscribeOn(Schedulers.io()) .subscribeBy( onNext = { dispatcher.dispatch(MainAction.RefreshPhotos(it)) }, onError = { // dispatcher.dispatch(ErrorAction()) } ) } fun showPhoto(activity: AppCompatActivity, materialPhotoId: MaterialPhotoId) { PhotoDialogFragment.newInstance(materialPhotoId) .show(activity.supportFragmentManager, "MainAction.PhotoDialog") } }
  22. ActionCreator @PerActivityScope class MainActionCreator @Inject constructor( private val dispatcher: Dispatcher,

    private val repository: ImageFlickrRepository ) { companion object { private const val SEARCH_TEXT = "owl" private const val PER_PAGE = 32 } fun fetchPopularPhotos(page: Int) { repository.findByText(SearchOrderType.POPULAR, SEARCH_TEXT, page, PER_PAGE) .subscribeOn(Schedulers.io()) .subscribeBy( onNext = { dispatcher.dispatch(MainAction.RefreshPhotos(it)) }, onError = { // Timber.e(it) } ) } fun showPhoto(activity: AppCompatActivity, materialPhotoId: MaterialPhotoId) { PhotoDialogFragment.newInstance(materialPhotoId) .show(activity.supportFragmentManager, "MainAction.PhotoDialog") } } implementation 'io.reactivex:rxkotlin:2.0.0-RC1'
  23. ActionCreator @PerActivityScope class MainActionCreator @Inject constructor( private val dispatcher: Dispatcher,

    private val repository: ImageFlickrRepository ) { companion object { private const val SEARCH_TEXT = "owl" private const val PER_PAGE = 32 } fun fetchPopularPhotos(page: Int) { repository.findByText(SearchOrderType.POPULAR, SEARCH_TEXT, page, PER_PAGE) .subscribeOn(Schedulers.io()) .subscribeBy( onNext = { dispatcher.dispatch(MainAction.RefreshPhotos(it)) }, onError = { // Timber.e(it) } ) } fun showPhoto(activity: AppCompatActivity, materialPhotoId: MaterialPhotoId) { PhotoDialogFragment.newInstance(materialPhotoId) .show(activity.supportFragmentManager, "MainAction.PhotoDialog") } }
  24. Dispatcher @Singleton class Dispatcher @Inject constructor() { private val dispatcherProcessor:

    FlowableProcessor<Action<*>> = PublishProcessor.create<Action<*>>() fun <T> dispatch(action: Action<T>) { dispatcherProcessor.onNext(action) } fun on(type: String) = dispatcherProcessor.filter { it.type == type } }
  25. Dispatcher @Singleton class Dispatcher @Inject constructor() { private val dispatcherProcessor:

    FlowableProcessor<Action<*>> = PublishProcessor.create<Action<*>>() fun <T> dispatch(action: Action<T>) { dispatcherProcessor.onNext(action) } fun on(type: String) = dispatcherProcessor.filter { it.type == type } }
  26. Dispatcher @Singleton class Dispatcher @Inject constructor() { private val dispatcherProcessor:

    FlowableProcessor<Action<*>> = PublishProcessor.create<Action<*>>() fun <T> dispatch(action: Action<T>) { dispatcherProcessor.onNext(action) } fun on(type: String) = dispatcherProcessor.filter { it.type == type } }
  27. Dispatcher @Singleton class Dispatcher @Inject constructor() { private val dispatcherProcessor:

    FlowableProcessor<Action<*>> = PublishProcessor.create<Action<*>>() fun <T> dispatch(action: Action<T>) { dispatcherProcessor.onNext(action) } fun on(type: String) = dispatcherProcessor.filter { it.type == type } }
  28. Store class MainStore @Inject constructor(private val dispatcher: Dispatcher) : Store()

    { private val _photos = BehaviorProcessor.create<List<MaterialPhoto>>() private val _photo = BehaviorProcessor.create<MaterialPhoto>() val photos: Flowable<List<MaterialPhoto>> = _photos val photo: Flowable<MaterialPhoto> = _photo init { dispatcher.on(MainAction.RefreshPhotos.TYPE) .map { (it as MainAction.RefreshPhotos).data } .observeOn(AndroidSchedulers.mainThread()) .subscribe(_photos) dispatcher.on(MainAction.ShowPhoto.TYPE) .map { (it as MainAction.ShowPhoto).data } .observeOn(AndroidSchedulers.mainThread()) .subscribe(_photo) } }
  29. Store class MainStore @Inject constructor(private val dispatcher: Dispatcher) : Store()

    { private val _photos = BehaviorProcessor.create<List<MaterialPhoto>>() private val _photo = BehaviorProcessor.create<MaterialPhoto>() val photos: Flowable<List<MaterialPhoto>> = _photos val photo: Flowable<MaterialPhoto> = _photo init { dispatcher.on(MainAction.RefreshPhotos.TYPE) .map { (it as MainAction.RefreshPhotos).data } .observeOn(AndroidSchedulers.mainThread()) .subscribe(_photos) dispatcher.on(MainAction.ShowPhoto.TYPE) .map { (it as MainAction.ShowPhoto).data } .observeOn(AndroidSchedulers.mainThread()) .subscribe(_photo) } }
  30. Store class MainStore @Inject constructor(private val dispatcher: Dispatcher) : Store()

    { private val _photos = BehaviorProcessor.create<List<MaterialPhoto>>() private val _photo = BehaviorProcessor.create<MaterialPhoto>() val photos: Flowable<List<MaterialPhoto>> = _photos val photo: Flowable<MaterialPhoto> = _photo init { dispatcher.on(MainAction.RefreshPhotos.TYPE) .map { (it as MainAction.RefreshPhotos).data } .observeOn(AndroidSchedulers.mainThread()) .subscribe(_photos) dispatcher.on(MainAction.ShowPhoto.TYPE) .map { (it as MainAction.ShowPhoto).data } .observeOn(AndroidSchedulers.mainThread()) .subscribe(_photo) } } ड͚औΔActionͷܕ͸<Action<*>>
  31. Store class MainStore @Inject constructor(private val dispatcher: Dispatcher) : Store()

    { private val _photos = BehaviorProcessor.create<List<MaterialPhoto>>() private val _photo = BehaviorProcessor.create<MaterialPhoto>() val photos: Flowable<List<MaterialPhoto>> = _photos val photo: Flowable<MaterialPhoto> = _photo init { dispatcher.on(MainAction.RefreshPhotos.TYPE) .map { (it as MainAction.RefreshPhotos).data } .observeOn(AndroidSchedulers.mainThread()) .subscribe(_photos) dispatcher.on(MainAction.ShowPhoto.TYPE) .map { (it as MainAction.ShowPhoto).data } .observeOn(AndroidSchedulers.mainThread()) .subscribe(_photo) } } View͕ࢀর͢Δσʔλ
  32. Store class MainStore @Inject constructor(private val dispatcher: Dispatcher) : Store()

    { private val _photos = BehaviorProcessor.create<List<MaterialPhoto>>() private val _photo = BehaviorProcessor.create<MaterialPhoto>() val photos: Flowable<List<MaterialPhoto>> = _photos val photo: Flowable<MaterialPhoto> = _photo init { dispatcher.on(MainAction.RefreshPhotos.TYPE) .map { (it as MainAction.RefreshPhotos).data } .observeOn(AndroidSchedulers.mainThread()) .subscribe(_photos) dispatcher.on(MainAction.ShowPhoto.TYPE) .map { (it as MainAction.ShowPhoto).data } .observeOn(AndroidSchedulers.mainThread()) .subscribe(_photo) } } ௚લͷ஋Λอ͓࣋ͯ͘͜͠ͱ͕Ͱ͖ΔFlowable
  33. View class MainActivity : View(), HasSupportFragmentInjector { @Inject lateinit var

    androidInjector: DispatchingAndroidInjector<Fragment> @Inject lateinit var actionCreator: MainActionCreator @Inject lateinit var store: MainStore private val binding: ActivityGalleryBinding by contentViewBinding(R.layout.activity_gallery) private var adapter: PhotosAdapter? = null … override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) … store.photos .subscribe { // it : List<MaterialPhoto> adapter = PhotosAdapter( this@MainActivity, it.toMutableList(), object : PhotosAdapter.OnItemClickListener { override fun onItemClick(item: MaterialPhoto) { actionCreator.showPhoto(this@MainActivity, item.id) } }) binding.recyclerView.also { it.adapter = adapter } adapter?.notifyDataSetChanged() } .disposeWhenDestroy() actionCreator.fetchPopularPhotos(0) } }
  34. View class MainActivity : View(), HasSupportFragmentInjector { @Inject lateinit var

    androidInjector: DispatchingAndroidInjector<Fragment> @Inject lateinit var actionCreator: MainActionCreator @Inject lateinit var store: MainStore private val binding: ActivityGalleryBinding by contentViewBinding(R.layout.activity_gallery) private var adapter: PhotosAdapter? = null … override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) … store.photos .subscribe { // it : List<MaterialPhoto> adapter = PhotosAdapter( this@MainActivity, it.toMutableList(), object : PhotosAdapter.OnItemClickListener { override fun onItemClick(item: MaterialPhoto) { actionCreator.showPhoto(this@MainActivity, item.id) } }) binding.recyclerView.also { it.adapter = adapter } adapter?.notifyDataSetChanged() } .disposeWhenDestroy() actionCreator.fetchPopularPhotos(0) } }
  35. View class MainActivity : View(), HasSupportFragmentInjector { @Inject lateinit var

    androidInjector: DispatchingAndroidInjector<Fragment> @Inject lateinit var actionCreator: MainActionCreator @Inject lateinit var store: MainStore private val binding: ActivityGalleryBinding by contentViewBinding(R.layout.activity_gallery) private var adapter: PhotosAdapter? = null … override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) … store.photos .subscribe { // it : List<MaterialPhoto> adapter = PhotosAdapter( this@MainActivity, it.toMutableList(), object : PhotosAdapter.OnItemClickListener { override fun onItemClick(item: MaterialPhoto) { actionCreator.showPhoto(this@MainActivity, item.id) } }) binding.recyclerView.also { it.adapter = adapter } adapter?.notifyDataSetChanged() } .disposeWhenDestroy() actionCreator.fetchPopularPhotos(0) } }
  36. View class MainActivity : View(), HasSupportFragmentInjector { @Inject lateinit var

    androidInjector: DispatchingAndroidInjector<Fragment> @Inject lateinit var actionCreator: MainActionCreator @Inject lateinit var store: MainStore private val binding: ActivityGalleryBinding by contentViewBinding(R.layout.activity_gallery) private var adapter: PhotosAdapter? = null … override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) … store.photos .subscribe { // it : List<MaterialPhoto> adapter = PhotosAdapter( this@MainActivity, it.toMutableList(), object : PhotosAdapter.OnItemClickListener { override fun onItemClick(item: MaterialPhoto) { actionCreator.showPhoto(this@MainActivity, item.id) } }) binding.recyclerView.also { it.adapter = adapter } adapter?.notifyDataSetChanged() } .disposeWhenDestroy() actionCreator.fetchPopularPhotos(0) } }
  37. ·ͱΊ • σʔλϑϩʔΛ୯Ұํ޲ʹ͢Δ͜ͱ • Store͕ঢ়ଶΛ؅ཧ͢Δ͜ͱͰViewίϯϙʔωϯ τ͔Βঢ়ଶ؅ཧΛ෼཭Ͱ͖Δ • Action, Store, Viewͱؔ৺͕෼཭͞Ε͍ͯΔͷͰ

    Ͳ͜ʹԿΛॻ͚͹͍͍͔Θ͔Γ΍͍͢ • ΞϓϦͷن໛͕େ͖͘ͳͬͯ΋଱͑͏Δεέʔϥ ϏϦςΟ • StoreʹΑΔঢ়ଶ؅ཧ͕࣮૷ͷ؊ͱͳΓϨϏϡʔ ͷ؍఺͕Θ͔Γ΍͍͢ • ࠷৽ϥΠϒϥϦͱͷ૬ੑ͕͍͍ • ͋ΒΏΔσʔλϑϩʔΛFluxͷϑϩʔʹࡌͤΔͨΊ খن໛ΞϓϦέʔγϣϯʹ͸൥Θ͍͠ • ActivityͷϥΠϑαΠΫϧ΍onActivityResult,Τϥʔͳ ͲͷಛघͳActionͷѻ͍ʹ՝୊͕͋Δ