Pro Yearly is on sale from $80 to $50! »

droidkaigi-2017-renovation

8928b5277aa7234dbca4ff782952343a?s=47 funnelbit
March 09, 2017

 droidkaigi-2017-renovation

8928b5277aa7234dbca4ff782952343a?s=128

funnelbit

March 09, 2017
Tweet

Transcript

  1. େن໛ΞϓϦͷ Ϧϊϕʔγϣϯ ๺ଜɹྋ

  2. ๺ଜྋ 5XJUUFS!FYQFSPQFSP )BUFOBGVOOFMCJU ͜Μʹͪ͸

  3. ژ౎ΦϑΟε

  4. (PPHMF*0 ߦ͖·͢ w ߦ͘ਓ͍ͨΒ͓࿩͍ͤͯͩ͘͞͞!

  5. ࠓ೔࿩͢͜ͱ w ڊେͳΞϓϦͷϦϑΝΫλϦϯάʹ͍ͭͯ w ਐΊํ w ઃܭ

  6. ࠓ೔࿩͢͜ͱ w ๲େ͕͗ͯ࣌ؒ͢଍Γ·ͤΜ! w ͋ͱͰ͓࿩͠·ͤΜ͔ w εςοΧʔ্ࠩ͛͠·͢ʢઌண໊ʣ

  7. None
  8. େن໛

  9.   "OEPSJE "OEPSJE

  10.   "OEPSJE "OEPSJE ݹ͍ίʔυ͕࢒Γଓ͚͍ͯΔ

  11. ϦϑΝΫλϦϯά ͍ͨ͠

  12. ϦϑΝΫλϦϯά͍ͨ͠ w ୯७ʹίʔυ͕େ͖͍ ઃܭ͕౷Ұ͞Ε͍ͯͳ͍ w ػೳ௥ՃͰίʔυΛ௥͏࣌ؒˠ૿Ճ w pYͰίʔυΛ௥͏࣌ؒˠ૿Ճ w কདྷͷηΩϡϦςΟ͕৺഑

  13. ϦϑΝΫλϦϯά͍ͨ͠ w ยखؒͰ΍͍ͬͯͨࠒ΋͋ͬͨ w ઃܭΛे෼ʹͱΔ͕࣌ؒͳ͔ͬͨ w ஔ͖׵͖͑Εͳ͍ʂ

  14. ϦϑΝΫλϦϯά͍ͨ͠ w ϦϑΝΫλϦϯάʹઐ೦͢Δظ͕ؒඞཁ w ϦϑΝΫλϦϯάվΊϦϊϕʔγϣϯ

  15. ϦϊϕʔγϣϯͷྲྀΕ

  16. ϦϊϕʔγϣϯͷྲྀΕ w υϝΠϯ஌ࣝͷ֫ಘ w ઃܭ w ࣮૷ʢϦϑΝΫλϦϯάʣ

  17. υϝΠϯ஌ࣝͷ֫ಘ

  18. υϝΠϯ஌ࣝͷ֫ಘ w ੲ͔Β։ൃ͠ଓ͚͍ͯΔਓ͸͍ͳ͍ w ׬ᘳͳυϝΠϯ஌ࣝΛ୭΋͍࣋ͬͯͳ͍ w νʔϜϝϯόڞ௨ͷυϝΠϯ஌͕ࣝඞཁ

  19. υϝΠϯ஌ࣝͷ֫ಘ ը໘Λ஌Δ

  20. ը໘Λ஌Δ w ྺ࢙ͱͱ΋ʹը໘͕૿͑ͨ w Ͳͷը໘͔Βىಈ͞ΕɺͲΜͳը໘͕ग़Δͷ͔Λ ஌Δ w ֎෦ΞϓϦ͔Βىಈ͞Εͨ࣌༻ͷը໘ w ϩάΠϯͯ͠Δͱ಺༰͕มΘΔը໘

    w Τϥʔ࣌ͷը໘
  21. ը໘Λ஌Δ εΫϦʔϯγϣοτΛࡱΓ·͘Δ

  22. ը໘Λ஌Δ w (SBQIWJ[ͰભҠΛՄࢹԽ

  23. ը໘Λ஌Δ w େ͖͗͢ΔͷͰࢴʹҹ࡮

  24. ը໘Λ஌Δ w େ͖͗͢ΔͷͰࢴʹҹ࡮

  25. ը໘Λ஌Δ w ը໘໊ w .PEFM w 7JFX

  26. ը໘Λ஌Δ w ը໘ͷ৘ใΛυΩϡϝϯτԽ

  27. υϝΠϯ஌ࣝͷ֫ಘ σβΠϯҙਤͷ֬ೝ

  28. σβΠϯҙਤͷ֬ೝ w ը໘Ұཡ͸σβΠφ΋ݟΔ w ֤෦ͷσβΠϯͷཧ༝Λ஌Δ w ඞཁͳ͍ͱ͜Ζ͸࡟Δ

  29. σβΠϯҙਤͷ֬ೝ

  30. σβΠϯҙਤͷ֬ೝ

  31. σβΠϯҙਤͷ֬ೝ

  32. σβΠϯҙਤͷ֬ೝ

  33. σβΠϯҙਤͷ֬ೝ

  34. ઃܭ

  35. ઃܭ w ϥΠϒϥϦબఆ w ΞʔΩςΫνϟͷܾఆ w αϯϓϧΞϓϦͷ࡞੒ w υΩϡϝϯτԽ w

    ϦϑΝΫλϦϯά։࢝
  36. ઃܭ ϥΠϒϥϦબఆ

  37. ϥΠϒϥϦબఆ w ࢖ͬͯ΋ྑͦ͞͏ɺͱ͍͏ͷΛ্͍͛ͯ͘ w ઃܭͰมΘΔͨΊɺ֬ఆ͢Δͷ͕໨తͰ͸ͳ͍ w 3FUSPpU 3Y+BWB  3Y-JGFDZDMF

    %BUBCJOEJOH 3FBMNʜ
  38. ઃܭ ΞʔΩςΫνϟͷܾఆ

  39. ΞʔΩςΫνϟͷܾఆ w ͲΜͳύϥμΠϜʹ͢Δ͔ߟ͑Δ w .7$ .71 .77.  w ϥΠϒϥϦͱ΋૊Έ߹Θ͍ͤͯ͘

    w ΞʔΩςΫνϟΛकΔͷ͕໨తͰ͸ͳ͍ w ඞཁʹԠͯ͡ண่͢
  40. ઃܭ αϯϓϧΞϓϦͷ࡞੒

  41. αϯϓϧΞϓϦͷ࡞੒ w ग़དྷ্͕ͬͨઃܭΛࢼ͢मਖ਼

  42. ઃܭ ग़དྷ্͕ͬͨઃܭ

  43. ओͳϥΠϒϥϦ w %BHHFS w 3FBMN w 3FUSPpU w 3FUSPMBNCEB w

    3Y"OESPJE w 3Y+BWB w 3Y-JGFDZDMF
  44. ओͳϨΠϠʔ 3FQPTJUPSZ *OUFSBDUPS 7JFX.PEFM 7JFX

  45. લఏ w ԼͷϨΠϠʔ͸্ͷϨΠϠʔΛ஌Βͳ͍ w ϨΠϠʔͷॲཧΛ֎ʹ࿙Β͞ͳ͍ w ԼͷϨΠϠʔ্͕ͷϨΠϠʔʹ݁ՌΛ఻͑Δͱ ͖͸0CTFSWBCMFΛ࢖͏ w %BHHFSͰ*OKFDU͢Δ

  46. 3FQPTJUPSZ

  47. 3FQPTJUPSZ w &OUSZ3FQPTJUPSZͳΒ&OUSZʹؔΘΔॲཧΛ୲ ౰͢Δ w *OUFSGBDFͱͦͷ࣮૷Λ༻ҙ͢Δ w ςετ͕༰қʹ w 3FQPTJUPSZΛఏڙ͢Δ%BHHFSͷ.PEVMFΛ

    ಉ͡ύοέʔδ಺ʹ࣋ͭ
  48. 3FQPTJUPSZ QBDLBHFߏ੒ w CPPLNBSLEPNBJO w &OUSZ w &OUSZKBWB .PEFM 

    w &OUSZ3FQPTJUPSZKBWB *OUFSGBDF  w &OUSZ3FQPTJUPSZ*NQMKBWB w &OUSZ.PEVMFKBWB
  49. 3FQPTJUPSZ *OUFSGBDF public interface EntryRepository {
 Single<List<Entry>> getGalleryEntries(Category category);
 }

  50. 3FQPTJUPSZ *NQM public class EntryRepositoryImpl implements EntryRepository {
 BookmarkAPI mBookmarkAPI;


    @Inject
 public EntryRepositoryImpl(BookmarkAPI bookmarkAPI) {
 mBookmarkAPI = bookmarkAPI;
 } @Override
 public Single<List<Entry>> getGalleryEntries(Category category) {
 return mBookmarkAPI
 .getEntryListGallery(category.getId())
 .map(entries -> Lists.transform(entries, e -> new Entry(e, true)));
 }
 }
  51. 3FQPTJUPSZ .PEVMF @Module
 public abstract class EntryModule {
 @Singleton
 @Binds


    public abstract EntryRepository provideEntryRepository(EntryRepositoryImpl impl);
 }
  52. *OUFSBDUPS

  53. *OUFSBDUPS w ಺෦ʹ3FQPTJUPSZΛ࣋ͭ w ඞͣ3YͰฦ͢ w มߋՄೳͳঢ়ଶΛ࣋ͨͳ͍ w εϨουΛܾఆ͢Δ w

    ࠷ޙʹ͸ඞͣϝΠϯεϨουʹ໭͢ w *OUFSBDUPSΛ૊Έ߹Θͤͳ͍લఏͷઃܭ
  54. *OUFSBDUPS QBDLBHFߏ੒ w CPPLNBSLJOUFSBDUPS w TDIFEVMFS w 4DIFEVMFS4XJUDIKBWB w 4DIFEVMFS4XJUDI5SBOTGPSNFSKBWB

    w (FU6TFS1BHFKBWB w (FU&OUSZKBWB w ʜ
  55. *OUFSBDUPS 
 public class GetUserPage {
 private final UserRepository mUserRepository;


    private final SchedulerSwitch mSchedulerSwitch;
 
 @Inject
 public GetUserPage(UserRepository repository, SchedulerSwitch schedulerSwitch) {
 mUserRepository = repository;
 mSchedulerSwitch = schedulerSwitch;
 }
 
 public Single<UserPage> execute(HatenaId hatenaId, int limit) {
 return mUserRepository
 .getUserPage(hatenaId, limit)
 .compose(mSchedulerSwitch.fromIOtoUI());
 }
 }
  56. *OUFSBDUPS 
 public class GetUserPage {
 private final UserRepository mUserRepository;


    private final SchedulerSwitch mSchedulerSwitch;
 
 @Inject
 public GetUserPage(UserRepository repository, SchedulerSwitch schedulerSwitch) {
 mUserRepository = repository;
 mSchedulerSwitch = schedulerSwitch;
 }
 
 public Single<UserPage> execute(HatenaId hatenaId, int limit) {
 return mUserRepository
 .getUserPage(hatenaId, limit)
 .compose(mSchedulerSwitch.fromIOtoUI());
 }
 }
  57. *OUFSBDUPS 
 public class GetUserPage {
 private final UserRepository mUserRepository;


    private final SchedulerSwitch mSchedulerSwitch;
 
 @Inject
 public GetUserPage(UserRepository repository, SchedulerSwitch schedulerSwitch) {
 mUserRepository = repository;
 mSchedulerSwitch = schedulerSwitch;
 }
 
 public Single<UserPage> execute(HatenaId hatenaId, int limit) {
 return mUserRepository
 .getUserPage(hatenaId, limit)
 .compose(mSchedulerSwitch.fromIOtoUI());
 }
 }
  58. *OUFSBDUPS 4DIFEVMFS4XJUDI w *05ISFBE.BJO5ISFBE public class SchedulerSwitch {
 private final

    Scheduler mIOScheduler;
 private final Scheduler mUIScheduler;
 
 @Inject
 public SchedulerSwitch(@IOScheduler Scheduler ioScheduler, @UIScheduler Scheduler uiScheduler) {
 mIOScheduler = ioScheduler;
 mUIScheduler = uiScheduler;
 }
 
 public <T> SchedulerSwitchTransformer<T> fromIOtoUI() {
 return new SchedulerSwitchTransformer<>(mIOScheduler, mUIScheduler);
 }
 }
  59. *OUFSBDUPS 4DIFEVMFS4XJUDI5SBOTGPSNFS public class SchedulerSwitchTransformer<T> implements
 ObservableTransformer<T, T>,
 FlowableTransformer<T, T>,


    SingleTransformer<T, T>,
 MaybeTransformer<T, T>,
 CompletableTransformer
 { …
 public SchedulerSwitchTransformer(Scheduler from, Scheduler to) {
 mFromScheduler = from;
 mToScheduler = to;
 }
 
 @Override
 public ObservableSource<T> apply(Observable<T> upstream) {
 return upstream.subscribeOn(mFromScheduler).observeOn(mToScheduler);
 } …
  60. 7JFX.PEFM

  61. 7JFX.PEFM w ಺෦ʹ*OUFSBDUPSΛ࣋ͭ w 7JFX͸7JFX.PEFMͷ͜ͱΛ஌ͬͯΔ w 7JFX.PEFMͷϝιουΛୟ͍ͯྑ͍ w 7JFX.PEFM͸7JFXΛ஌Βͳ͍ w

    "DUJWJUZ'SBHNFOU΋7JFXͱΈͳ͢
  62. 7JFX.PEFM w ಺෦ʹ௨஌༻0CTFSWBCMFΛ࣋ͭ w ঢ়ଶ͕มΘΔͱ௨஌ w %BUB#JOEJOHͰࣗ਎͕-BZPVUʹηοτ͞ΕΔ ͜ͱ΋૝ఆ w ʢ͋Δఔ౓͸ʣ࢖͍·Θ͞ΕΔલఏ

  63. 7JFX.PEFM w $PNNFOUT'SBHNFOU$PNNFOUT7JFX.PEFM

  64. 7JFX.PEFM QBDLBHFߏ੒ w CPPLNBSLQSFTFOUBUJPO w WJFXNPEFM w $PNNFOUT7JFX.PEFMKBWB w ʜ

  65. None
  66. None
  67. $PNNFOUT7JFX.PEFM public class CommentsViewModel { … private final BehaviorSubject<Page<BookmarkCommentViewModel>> mPages

    = BehaviorSubject.create();
 public final Observable<Page<BookmarkCommentViewModel>> pages = mPages.hide();
 
 private final PublishSubject<Throwable> mErrors = PublishSubject.create();
 public final Observable<Throwable> errors = mErrors.hide(); 
 @Inject
 public CommentsViewModel(Observable<FragmentEvent> lifecycle,
 GetEntryCommentList getEntryCommentList,
 AddStar addStar,
 Target target) {
 mLifecycle = lifecycle;
 mGetEntryCommentList = getEntryCommentList;
 mAddStar = addStar; …
  68. $PNNFOUT7JFX.PEFM public void getNextPage() {
 mPager
 .next()
 .subscribe(
 mPages::onNext,
 mErrors::onNext


    );
 } w 'SBHNFOU͔ΒϝιουΛݺͿ
  69. None
  70. None
  71. 7JFX.PEFMͷ֊૚ w 7JFX.PEFM͸֊૚Λ࣋ͭʢ͜ͱ΋͋Δʣɻ w $PNNFOUT7JFX.PEFM w $PNNFOU7JFX.PEFM w $PNNFOU7JFX.PEFM w

    $PNNFOU7JFX.PEFM
  72. $PNNFOU7JFX.PEFM public final class CommentViewModel {
 public final String profileImageUrl;


    public final String username;
 public final String comment;
 public final List<String> tags;
 public final String timestamp; 
 public ObservableList<HatenaStar> stars;
 private final AddStar mAddStar;
 
 private final PublishSubject<Throwable> mErrors;
 
 public CommentViewModel(
 String entryId,
 BookmarkComment bookmarkComment,
 AddStar addStar,
 PublishSubject<Throwable> errorsSubject)
 {
 …
 }
  73. $PNNFOU7JFX.PEFM 
 public void addStar() {
 // ελʔ௥Ճதͷදࣔɻ
 HatenaStar requesting

    = new HatenaStar(HatenaStar.Color.REQUESTING, null, null, true);
 stars.add(requesting);
 
 mAddStar.execute(mEntryStarInfo)
 .subscribe(
 () -> {
 stars.set(stars.size() - 1, new HatenaStar(HatenaStar.Color.YELLOW, null, null, true));
 },
 e -> {
 mErrors.onNext(new AddStarFailed());
 stars.remove(requesting);
 }
 );
 }
  74. $PNNFOU-BZPVU … <FrameLayout
 android:id=“@+id/add_star_button” …
 android:onClick="@{() -> viewModel.addStar()}">
 </FrameLayout> <com.hatena.android.view.star.HatenaStarsView


    android:id=“@+id/star_view" …
 app:hatenaStars=“@{viewModel.stars}"/> …
  75. 7JFX.PEFM /BWJHBUPS

  76. 7JFX.PEFM /BWJHBUPS w ભҠΛද͢Ϋϥε w 7JFX.PEFMͷதͰ࡞Βͣɺ֎෦͔Β౉͞ΕΔ w PO$MJDL࣌౳ͷભҠͰ࢖ΘΕΔ

  77. 7JFX.PEFM /BWJHBUPS QBDLBHFߏ੒ w CPPLNBSLQSFTFOUBUJPO w OBWJHBUPS w -PHJO/BWJHBUPSKBWB

  78. 7JFX.PEFM /BWJHBUPS public interface LoginNavigator {
 void openLogin();
 }

  79. 7JFX.PEFM /BWJHBUPS public interface LoginNavigator {
 void openLogin();
 
 @dagger.Module


    class Module {
 private final LoginNavigator mNavigator;
 
 public Module(LoginNavigator navigator) {
 mNavigator = navigator;
 }
 
 @Provides
 public LoginNavigator provideNavigator() {
 return mNavigator;
 }
 }
 }
  80. 7JFX.PEFM /BWJHBUPS public class TopicFragment extends BaseFragment { private final

    LoginNavigator mNavigator = () -> startActivity( new Intent(getActivity(), LoginActivity.class) ); …
  81. 7JFX.PEFM /BWJHBUPS @Nullable
 @Override
 public View onCreateView(...) {
 ((App) getActivity().getApplication())

    …
 .topicFragmentComponent()
 .loginNavigatorModule( new LoginNavigator.Module(mNavigator) )
 .build()
 .inject(this);
  82. 7JFX.PEFM /BWJHBUPS public class TopicViewModel { …
 private final LoginNavigator

    mNavigator;
 public final ObservableField<View.OnClickListener> onClickListener = new ObservableField<>(
 new View.OnClickListener(){
 @Override
 public void onClick(View view) {
 mNavigator.openLogin();
 }
 });
  83. 7JFX.PEFM /BWJHBUPS <TextView
 android:id="@+id/login"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:onClick="@{viewModel.onClickListener}"
 android:text="ϩάΠϯը໘΁"/>

  84. ઃܭͷ υΩϡϝϯτԽ

  85. ઃܭͷυΩϡϝϯτԽ w ࡞Δલʹߏ੒ΛυΩϡϝϯτԽ͢Δ w ਓͷೖΕସΘΓʹඋ͑Δ w ઃܭΛϒϨͤ͞ͳ͍

  86. ઃܭͷυΩϡϝϯτԽ w ͜ͷઃܭʹͳͬͨཧ༝΋ॻ͘ w ೲಘͯ͠΋Β͏ͨΊ

  87. ઃܭͷυΩϡϝϯτԽ w 7JFX.PEFM w ֓ཁ w 7JFX.PEFM͸දࣔʹඞཁͳσʔλΛอ࣋͠ɺ0CTFSWBCMFͰ ͦΕͧΕͷ7JFXʹ఻͑·͢ɻͦΕ͸5FYU7JFX͔΋͠Ε·ͤ Μ͠ɺ3FDZDMFS7JFXͰද͍ࣔͯ͠Δ*UFNୡɺ͸ͨ·ͨ 'SBHNFOU͔΋͠Ε·ͤΜɻ

    w 7JFX.PEFM͸ɺܾͯ͠7JFXʹ͍ͭͯ஌ͬͯ͸ͳΓ·ͤΜɻ ྫ͑͹ɺҎԼͷྫΛݟ͍ͯͩ͘͞ʜ
  88. ઃܭͷυΩϡϝϯτԽ w ن໿ w 7JFX.PEFM͸7JFXʹ͍ͭͯ஌ͬͯ͸ͳΒͳ͍ɻ͜ Ε͸5FYU7JFX΍%JBMPHɺ5PBTUɺ3FDZDMFS7JFXͱ ͦͷ"EBQUFSͳͲΛࢦ͢ɻ w 7JFX.PEFM͸"DUJWJUZ΍'SBHNFOU΋7JFXͱݟ ͳ͢ɻ

  89. ઃܭͷυΩϡϝϯτԽ w 7JFX.PEFM͸ը໘ભҠͷॲཧΛߦ͏͕ɺ௚઀*OUFOU Λ࡞ͬͨΓɺ'SBHNFOU.BOBHFSΛૢ࡞ͨ͠Γ͸ͤͣɺ ͦΕΒͷૢ࡞͕࣮૷͞Εͨ/BWJHBUPSJOUFSGBDFͰߦ ͏ɻ/BWJHBUPS͸"DUJWJUZ΍'SBHNFOUͰ࣮૷͞ Εɺ7JFX.PEFMʹ*OKFDU͞ΕΔɻ

  90. ணख

  91. ணख w ਐΊํ w ը໘ຖʹλεΫΛ੾Δํ๏

  92. ணख w ઢ͕ଟ͍ͱ͜Ζ͸བྷΈ͕ଟͦ͏େม

  93. ணख w ઢ͕গͳ͍ͱ͜Ζ͸ָͦ͏

  94. ը໘ຖʹਐΊΔํ๏ w Ұͭ׬੒͢Δͷʹ͕͔͔࣌ؒΔ w ݟੵ΋Γʹ͍͘ɺ෼୲͠ʹ͍͘

  95. ϨΠϠʔຖʹਐΊΔํ๏ w 3FQPTJUPSZ*OUFSBDUPS7JFX.PEFMͱਐ Ί͍ͯ͘ w มߋͨ͠ͱ͖ͷӨڹΛ࠷খݶʹͰ͖Δ w ൺֱతݟੵ΋Γ͠΍͍͢

  96. ஔ͖׵͑ํ w ͍͖ͳΓશ෦มߋ͠ͳ͍ʢഁ໓͠·͢ʣ w 3Y+BWBԽ͸ޙճ͠ʢ؆୯ͳΒ΍Δʣ w Ҡߦ༻ύοέʔδʹҰ࣌తͳΫϥεΛ࡞ΔʢҠ ߦޙʹফ͢ʣ w $PNQPOFOU΋গͣͭ͠Ҡಈ͍ͯ͘͠

  97. ݟੵ΋Γ

  98. ϦϦʔε

  99. ϦϦʔε w ̍ʙ̎िؒ͝ͱʹϦϦʔε༷ͯ͠ࢠݟΔ

  100. ·ͱΊ

  101. ·ͱΊ w ணखલʹ w υϝΠϯ஌ࣝΛಘΔ w খ͞ͳΞϓϦΛ࡞ͬͯࢼ͢ w υΩϡϝϯτԽ͢Δ w

    ४උ͕ॏཁ
  102. ·ͱΊ w ணखޙʹ w ϨΠϠʔຖʹ෼͚ͯԼ͔Β΍͍ͬͯ͘ w ඞͣݟੵ΋Δ w ௕ͯ͘΋िؒ͝ͱʹϦϦʔε

  103. ·ͱΊ w ઃܭ͸ϓϩμΫτʹΑͬͯઍࠩສผ w ྑ͍ઃܭΛ෦෼తʹऔΓೖΕΔ w ׬ᘳʹಉ͡ʹ͢Δͷ͸ࠔ೉

  104. ͋Γ͕ͱ͏͍͟͝·ͨ͠