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

💪🏻Activityを改善した話 at DroidKaigi 2017

💪🏻Activityを改善した話 at DroidKaigi 2017

DroidKaigi2017

TwitterID変えました。@lvla0805 -> @MoyuruAizawa

Moyuru Aizawa

March 10, 2017
Tweet

More Decks by Moyuru Aizawa

Other Decks in Programming

Transcript

  1. Instanceੜ੒ final Serval serval = new Serval(); Kaban kaban =

    new Kaban(); val serval = Serval() var kaban = Kaban()
  2. Instanceੜ੒ final Serval serval = new Serval(); Kaban kaban =

    new Kaban(); val serval = Serval() var kaban = Kaban()
  3. Instanceੜ੒ final Serval serval = new Serval(); Kaban kaban =

    new Kaban(); val serval = Serval() var kaban = Kaban()
  4. Instanceੜ੒ final Serval serval = new Serval(); Kaban kaban =

    new Kaban(); val serval = Serval() var kaban = Kaban()
  5. Class public class JapariBus { private final Trailer trailer; private

    final Container container; public JapariBus(Trailer trailer, Container container) { this.trailer = trailer; this.container = container; } } class JapariBus(private val trailer: Trailer, private val container: Container) Έ͔͡ʔ͍
  6. Class public class JapariBus { private final Trailer trailer; private

    final Container container; public JapariBus(Trailer trailer, Container container) { this.trailer = trailer; this.container = container; } } class JapariBus(private val trailer: Trailer, private val container: Container) Έ͔͡ʔ͍
  7. Class public class JapariBus { private final Trailer trailer; private

    final Container container; public JapariBus(Trailer trailer, Container container) { this.trailer = trailer; this.container = container; } } class JapariBus(private val trailer: Trailer, private val container: Container) Έ͔͡ʔ͍
  8. Lambda observable.map(new Func1<Foo, Bar>() { @Override public Bar call(Foo foo)

    { return foo.toBar(); } }); observable.map(foo -> foo.toBar()); observable.map { foo -> foo.toBar() }
  9. Lambda observable.map(new Func1<Foo, Bar>() { @Override public Bar call(Foo foo)

    { return foo.toBar(); } }); observable.map(foo -> foo.toBar()); observable.map { foo -> foo.toBar() }
  10. Lambda observable.map(new Func1<Foo, Bar>() { @Override public Bar call(Foo foo)

    { return foo.toBar(); } }); observable.map(foo -> foo.toBar()); observable.map { foo -> foo.toBar() }
  11. Lambda observable.map(new Func1<Foo, Bar>() { @Override public Bar call(Foo foo)

    { return foo.toBar(); } }); observable.map(foo -> foo.toBar()); observable.map { foo -> foo.toBar() }
  12. ϏδωεϩδοΫ if (isLikedByPartner) { // ͓૬ख͔Β͍͍Ͷ!Λ΋Β͍ͬͯΔঢ়ଶ } else if (isLikedByMe)

    { // ͍͍Ͷ!Λ͍ͯ͠Δঢ়ଶ } else if (isLikedWithMessage) { // ϝοηʔδ෇͖͍͍Ͷ!Λ͍ͯ͠Δঢ়ଶ } else if (isLooked) { // ΈͯͶ!Λ͍ͯ͠Δঢ়ଶ } else if (isLookedWithMessage) { // ϝοηʔδ෇͖ΈͯͶ!Λ͍ͯ͠Δঢ়ଶ } else if (isHidden) { // ඇදࣔઃఆΛͨ͠௚ޙ } else if (isBlocked) { // ϒϩοΫઃఆΛͨ͠௚ޙ } else if (...) { ... }
  13. IO

  14. IO userClient.fetchMathingUsers() .subscribeOnIo() .doOnNex { users -> userDao.insertAll(users) } .onError

    { userDao.findAll() } .observeOnMain() .subscribe( { users -> showUsers(users) }, { ... })
  15. ‣ Converter ‣ JsonΛϚοϐϯάͨ͠Ϋϥε͔ΒɺΞϓϦ಺Ͱ࢖ ͍΍͍͢σʔλΫϥεʹม׵Λߦ͏Ϋϥε ‣ ม׵Λߦ͏͜ͱͷΈ͕੹຿ͷ͸ͣ ΊͪΌͪ͘Όͳ੹຿ class UserConverter

    { fun convert(res: MatchingUsersResponse): List<User> { return res.users.map { resUser -> User(resUser.name, …) } } }
  16. ‣ Convert͢ΔաఔͰϢʔβʔͷϑΟϧλϦϯάΛߦ͏ Converter ΊͪΌͪ͘Όͳ੹຿ class UserConverter { fun convert(res: MatchingUsersResponse):

    List<User> { return res.users.map { user -> User(user.name, user.age, ...) } .filter { … } } }
  17. After Dao Client Repository UseCase Presenter Activity / Fragment Observable

    Observable Observable Observable Observable Observable Database API Service
  18. Client class UserClient(private val service: UserService) { fun fetchMatchingUsers(offset: Int):Observable<List<User>>

    { return service.fetchMatchingUsers(offset) .map { response -> UserConverter.convert(response) } } }
  19. Client class UserClient(private val service: UserService) { fun fetchMatchingUsers(offset: Int):Observable<List<User>>

    { return service.fetchMatchingUsers(offset) .map { response -> UserConverter.convert(response) } } }
  20. Client class UserClient(private val service: UserService) { fun fetchMatchingUsers(offset: Int):Observable<List<User>>

    { return service.fetchMatchingUsers(offset) .map { response -> UserConverter.convert(response) } } }
  21. Client Test val userService = mock<UserService>() val client = UserClient(userService)

    userService.invoked.thenReturn(...) client.fetchMathingUsers().test().run { ... }
  22. Dao class UserDao(private val orma: OrmaDatabase) { fun insert(users: List<User>)

    { orma.transactionSync { orma.prepareInsertIntoUser(OnConflict.REPLACE) .executeAll(contributors) } } fun findAll(): Observable<List<User>> { return orma.selectFromUser() .executeAsObservable() .toList() } }
  23. Dao class UserDao(private val orma: OrmaDatabase) { fun insert(users: List<User>)

    { orma.transactionSync { orma.prepareInsertIntoUser(OnConflict.REPLACE) .executeAll(contributors) } } fun findAll(): Observable<List<User>> { return orma.selectFromUser() .executeAsObservable() .toList() } }
  24. Dao class UserDao(private val orma: OrmaDatabase) { fun insert(users: List<User>)

    { orma.transactionSync { orma.prepareInsertIntoUser(OnConflict.REPLACE) .executeAll(contributors) } } fun findAll(): Observable<List<User>> { return orma.selectFromUser() .executeAsObservable() .toList() } }
  25. Dao class UserDao(private val orma: OrmaDatabase) { fun insert(users: List<User>)

    { orma.transactionSync { orma.prepareInsertIntoUser(OnConflict.REPLACE) .executeAll(contributors) } } fun findAll(): Observable<List<User>> { return orma.selectFromUser() .executeAsObservable() .toList() } }
  26. Dao Test val dao = UserDao(orma) dao.insert(...) orma.selectFromUser() .executeAsObservable() .toList()

    .test() .run { ... } orma.insertIntoUser()… dao.findAll().test().run { ... }
  27. UserRepository class UserRepository( private val dao: UserDao, private val userClient:

    UserClient) { fun getMatchingUsers(offset: Int):Observable<List<User>> { return userClient.fetchMatchingUsers(offset) .doOnNext { users -> dao.insert(users) } .onErrorResumeNext { dao.findAll() } } }
  28. UserRepository class UserRepository( private val dao: UserDao, private val userClient:

    UserClient) { fun getMatchingUsers(offset: Int):Observable<List<User>> { return userClient.fetchMatchingUsers(offset) .doOnNext { users -> dao.insert(users) } .onErrorResumeNext { dao.findAll() } } }
  29. UserRepository class UserRepository( private val dao: UserDao, private val userClient:

    UserClient) { fun getMatchingUsers(offset: Int):Observable<List<User>> { return userClient.fetchMatchingUsers(offset) .doOnNext { users -> dao.insert(users) } .onErrorResumeNext { dao.findAll() } } }
  30. UserRepository class UserRepository( private val dao: UserDao, private val userClient:

    UserClient) { fun getMatchingUsers(offset: Int):Observable<List<User>> { return userClient.fetchMatchingUsers(offset) .doOnNext { users -> dao.insert(users) } .onErrorResumeNext { dao.findAll() } } }
  31. UserRepository class UserRepository( private val dao: UserDao, private val userClient:

    UserClient) { fun getMatchingUsers(offset: Int):Observable<List<User>> { return userClient.fetchMatchingUsers(offset) .doOnNext { users -> dao.insert(users) } .onErrorResumeNext { dao.findAll() } } }
  32. UserRepository class UserRepository( private val dao: UserDao, private val userClient:

    UserClient) { fun getMatchingUsers(offset: Int):Observable<List<User>> { return userClient.fetchMatchingUsers(offset) .doOnNext { users -> dao.insert(users) } .onErrorResumeNext { dao.findAll() } } }
  33. UserRepository class UserRepository( private val dao: UserDao, private val userClient:

    UserClient) { fun getMatchingUsers(offset: Int):Observable<List<User>> { return userClient.fetchMatchingUsers(offset) .doOnNext { users -> dao.insert(users) } .onErrorResumeNext { dao.findAll() } } }
  34. MatchingUserUseCase class MatchingUserUseCase(private val repo: UserRepository) { fun getUsers(offset: Int)

    = repo.getMatchingUsers(offset) fun getFacebookPublicSetting( me: Me, user: User): FacebookPublicSetting { return if (shouldShowMeFacebook(me, user)) { if (shouldShowPartnerFacebook(user)) { FacebookPublicSetting.BOTH } else { FacebookPublicSetting.ONLY_ME } } else { if (shouldShowPartnerFacebook(user)) { FacebookPublicSetting.ONLY_USER } else { FacebookPublicSetting.NEITHER } } } }
  35. MatchingUserUseCase class MatchingUserUseCase(private val repo: UserRepository) { fun getUsers(offset: Int)

    = repo.getMatchingUsers(offset) fun getFacebookPublicSetting( me: Me, user: User): FacebookPublicSetting { return if (shouldShowMeFacebook(me, user)) { if (shouldShowPartnerFacebook(user)) { FacebookPublicSetting.BOTH } else { FacebookPublicSetting.ONLY_ME } } else { if (shouldShowPartnerFacebook(user)) { FacebookPublicSetting.ONLY_USER } else { FacebookPublicSetting.NEITHER } } } }
  36. MatchingUserUseCase class MatchingUserUseCase(private val repo: UserRepository) { fun getUsers(offset: Int)

    = repo.getMatchingUsers(offset) fun getFacebookPublicSetting( me: Me, user: User): FacebookPublicSetting { return if (shouldShowMeFacebook(me, user)) { if (shouldShowPartnerFacebook(user)) { FacebookPublicSetting.BOTH } else { FacebookPublicSetting.ONLY_ME } } else { if (shouldShowPartnerFacebook(user)) { FacebookPublicSetting.ONLY_USER } else { FacebookPublicSetting.NEITHER } } } }
  37. MatchingUserUseCase class MatchingUserUseCase(private val repo: UserRepository) { fun getUsers(offset: Int)

    = repo.getMatchingUsers(offset) fun getFacebookPublicSetting( me: Me, user: User): FacebookPublicSetting { return if (shouldShowMeFacebook(me, user)) { if (shouldShowPartnerFacebook(user)) { FacebookPublicSetting.BOTH } else { FacebookPublicSetting.ONLY_ME } } else { if (shouldShowPartnerFacebook(user)) { FacebookPublicSetting.ONLY_USER } else { FacebookPublicSetting.NEITHER } } } }
  38. MatchingUserUseCase class MatchingUserUseCase(private val repo: UserRepository) { fun getUsers(offset: Int)

    = repo.getMatchingUsers(offset) fun getFacebookPublicSetting( me: Me, user: User): FacebookPublicSetting { return if (shouldShowMeFacebook(me, user)) { if (shouldShowPartnerFacebook(user)) { FacebookPublicSetting.BOTH } else { FacebookPublicSetting.ONLY_ME } } else { if (shouldShowPartnerFacebook(user)) { FacebookPublicSetting.ONLYE_USER } else { FacebookPublicSetting.NEITHER } } } }
  39. MatchingUserUseCase class MatchingUserUseCase(private val repo: UserRepository) { fun getUsers(offset: Int)

    = repo.getMatchingUsers(offset) fun getFacebookPublicSetting( me: Me, user: User): FacebookPublicSetting { return if (shouldShowMeFacebook(me, user)) { if (shouldShowPartnerFacebook(user)) { FacebookPublicSetting.BOTH } else { FacebookPublicSetting.ONLY_ME } } else { if (shouldShowPartnerFacebook(user)) { FacebookPublicSetting.ONLY_PARTNER } else { FacebookPublicSetting.NEITHER } } } }
  40. MatchingUserUseCase class MatchingUserUseCase(private val repo: UserRepository) { fun getUsers(offset: Int)

    = repo.getMatchingUsers(offset) fun getFacebookPublicSetting( me: Me, user: User): FacebookPublicSetting { return if (shouldShowMeFacebook(me, user)) { if (shouldShowPartnerFacebook(user)) { FacebookPublicSetting.BOTH } else { FacebookPublicSetting.ONLY_ME } } else { if (shouldShowPartnerFacebook(user)) { FacebookPublicSetting.ONLY_PARTNER } else { FacebookPublicSetting.NEITHER } } } }
  41. Presenter class MatchingPresenter( private val contract: Contract, private val useCase:

    MatchingUserUseCase) { fun init() { useCase.getUsers().applySchedulers() .doOnSubscribe { contract.showProgress() } .doOnUnsubscribe { contract.hideProgress() } .subscribe( { users -> contract.showMatchingUsers(users) }, { ... } ) } interface Contract { fun showMatchingUsers(users: List<User>) fun showProgress() fun hideProgress() } }
  42. Presenter class MatchingPresenter( private val contract: Contract, private val useCase:

    MatchingUserUseCase) { fun init() { useCase.getUsers().applySchedulers() .doOnSubscribe { contract.showProgress() } .doOnUnsubscribe { contract.hideProgress() } .subscribe( { users -> contract.showMatchingUsers(users) }, { ... } ) } interface Contract { fun showMatchingUsers(users: List<User>) fun showProgress() fun hideProgress() } }
  43. Presenter class MatchingPresenter( private val contract: Contract, private val useCase:

    MatchingUserUseCase) { fun init() { useCase.getUsers().applySchedulers() .doOnSubscribe { contract.showProgress() } .doOnUnsubscribe { contract.hideProgress() } .subscribe( { users -> contract.showMatchingUsers(users) }, { ... } ) } interface Contract { fun showMatchingUsers(users: List<User>) fun showProgress() fun hideProgress() } }
  44. Presenter class MatchingPresenter( private val contract: Contract, private val useCase:

    MatchingUserUseCase) { fun init() { useCase.getUsers().applySchedulers() .doOnSubscribe { contract.showProgress() } .doOnUnsubscribe { contract.hideProgress() } .subscribe( { users -> contract.showMatchingUsers(users) }, { ... } ) } interface Contract { fun showMatchingUsers(users: List<User>) fun showProgress() fun hideProgress() } }
  45. Presenter class MatchingPresenter( private val contract: Contract, private val useCase:

    MatchingUserUseCase) { fun init() { useCase.getUsers().applySchedulers() .doOnSubscribe { contract.showProgress() } .doOnUnsubscribe { contract.hideProgress() } .subscribe( { users -> contract.showMatchingUsers(users) }, { ... } ) } interface Contract { fun showMatchingUsers(users: List<User>) fun showProgress() fun hideProgress() } }
  46. Presenter class MatchingPresenter( private val contract: Contract, private val useCase:

    MatchingUserUseCase) { fun init() { useCase.getUsers().applySchedulers() .doOnSubscribe { contract.showProgress() } .doOnUnsubscribe { contract.hideProgress() } .subscribe( { users -> contract.showMatchingUsers(users) }, { ... } ) } interface Contract { fun showMatchingUsers(users: List<User>) fun showProgress() fun hideProgress() } }
  47. Presenter class MatchingPresenter( private val contract: Contract, private val useCase:

    MatchingUserUseCase) { fun init() { useCase.getUsers().applySchedulers() .doOnSubscribe { contract.showProgress() } .doOnUnsubscribe { contract.hideProgress() } .subscribe( { users -> contract.showMatchingUsers(users) }, { ... } ) } interface Contract { fun showMatchingUsers(users: List<User>) fun showProgress() fun hideProgress() } }
  48. Presenter class MatchingPresenter( private val contract: Contract, private val useCase:

    MatchingUserUseCase) { fun init() { useCase.getUsers().applySchedulers() .doOnSubscribe { contract.showProgress() } .doOnUnsubscribe { contract.hideProgress() } .subscribe( { users -> contract.showMatchingUsers(users) }, { ... } ) } interface Contract { fun showMatchingUsers(users: List<User>) fun showProgress() fun hideProgress() } }
  49. Activity/Fragment class MatchingFragment: Fragment(), MatchingPresenter.Contract { … override fun onViewCreated(...)

    { … presenter.init() } override fun showMatchingUsers(users: List<User>) { listView.adapter = MatchingUsersAdapter(activity, users) } override fun showProgress() { progress.toVisible() } override fun hideProgress() { progress.toGone() } }
  50. Activity/Fragment class MatchingFragment: Fragment(), MatchingPresenter.Contract { … override fun onViewCreated(...)

    { … presenter.init() } override fun showMatchingUsers(users: List<User>) { listView.adapter = MatchingUsersAdapter(activity, users) } override fun showProgress() { progress.toVisible() } override fun hideProgress() { progress.toGone() } }
  51. Activity/Fragment class MatchingFragment: Fragment(), MatchingPresenter.Contract { … override fun onViewCreated(...)

    { … presenter.init() } override fun showMatchingUsers(users: List<User>) { listView.adapter = MatchingUsersAdapter(activity, users) } override fun showProgress() { progress.toVisible() } override fun hideProgress() { progress.toGone() } }
  52. ‣ Pairs JP AndroidνʔϜ͸౰࣌3ਓ ‣ 2ਓ͸ͦͷ··ࢪࡦͷ࣮૷ ‣ ࢲ͕୲౰ ‣ Pairs

    Globalͷ@yuyakaidoʹ΋ख఻ͬͯ΋Β͏ ‣ ܭ 1.5ਓ͘Β͍Ͱ࣮૷ Ͳ͏ਐΊ͍ͯͬͨͷ͔
  53. ‣ σʔλιʔε͝ͱʹDao, Client, RepositoryΛ࣮૷ ‣ UserDao, UserClient, UserRepository ‣ MeDao,

    MeClient, MeRepository ‣ … ‣ σʔλιʔε͝ͱʹɺRepository͕࣮૷׬ྃ࣍ୈ UseCaseΛ࣮૷ ‣ Activity/FragmentʹมߋΛՃ͑Δ Ͳ͏ਐΊ͍ͯͬͨͷ͔ ‘͓૬ख’ͷσʔλΫϥε ‘ࣗ෼’ͷσʔλΫϥε
  54. ‣ Dao, Client, Repository, UseCaseͳͲ੹຿͝ͱʹϨΠ ϠʔΛ෼͚ͨ ‣ ModelͱViewͷؒʹPresenterΛઃ͚ͯViewͱModelΛ ໌֬ʹ෼͚Δ ‣

    Dagger2ʹґଘੑͷղܾΛҕৡ͢Δ ‣ σʔλιʔε͝ͱʹԼͷϨΠϠʔ͔Βॱʹ࣮૷͍ͯ͠ ͘ ‣ ϝϯόʔ΁ͷϨΫνϟʔ͸͔ܽ͞ͳ͍ ‣ จͱͯ͠࢒͠ɺ͍ͭͰ΋ݟฦ͢Α͏ʹͨ͠ ·ͱΊ