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

GUIアプリケーションの構造と設計

cockscomb
October 31, 2017

 GUIアプリケーションの構造と設計

Presented at Hatena Engineer Seminar #9

https://hatena.connpass.com/event/69844/

cockscomb

October 31, 2017
Tweet

More Decks by cockscomb

Other Decks in Programming

Transcript

  1. (6*ΞϓϦέʔγϣϯͷߏ଄ͱઃܭ

    View full-size slide

  2. (6*ΞϓϦέʔγϣϯͷߏ଄ͱઃܭ
    w εϚʔτϑΥϯʢJ04"OESPJEʣ
    w σεΫτοϓ
    w 8FCʢ3FBDUʣ

    View full-size slide

  3. ΞϓϦέʔγϣϯͷઃܭ
    J04
    $PDPBUPVDI
    "QQ
    -JCSBSJFT
    "OESPJE
    BOESPJE
    "QQ
    -JCSBSJFT
    8FC
    %0.
    "QQ
    -JCSBSJFT
    ʜ
    ʜ
    "QQ
    -JCSBSJFT
    ͜͜

    View full-size slide

  4. εςʔτϑϧ
    w (6*ΞϓϦέʔγϣϯͷຊ࣭తͳ೉͠͞
    w ঢ়ଶΛͲ͏΍ͬͯѻ͏ͷ͔

    View full-size slide

  5. w 0CTFSWFSύλʔϯ
    w ΦϒδΣΫτͷੜ੒ɾ؅ཧ
    w ඇಉظॲཧͷந৅Խ

    View full-size slide

  6. "OESPJEBQQ
    ,PUMJO
    3Y+BWB
    %BHHFS
    %BUB#JOEJOH
    "SDIJUFDUVSF$PNQPOFOUT

    View full-size slide

  7. 0CTFSWFSύλʔϯ

    View full-size slide

  8. 0CTFSWFSύλʔϯ
    w (P'ͷͷσβΠϯύλʔϯʹ΋਺͑ΒΕΔ
    w ঢ়ଶΛ؂ࢹͰ͖Δ
    w Ϟσϧͷঢ়ଶΛ6*ʹ൓өͤ͞Δ

    ˠ6*͸Ϟσϧͷঢ়ଶͷࣸ૾

    View full-size slide

  9. ୯७ͳ0CTFSWFSύλʔϯ
    w +BWB#FBOT
    w ,FZ7BMVF0CTFSWBUJPO J04

    w 3FEVYʹ͓͚Δ4UPSFͷTVCTDSJCF 8FC

    View full-size slide

  10. όΠϯσΟϯά
    w %BUB#JOEJOH "OESPJE

    w $PDPB#JOEJOHT J04

    w 3FBDU 8FC

    View full-size slide

  11. %BUB#JOEJOH





    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    android:id="@+id/titleView"
    android:text="@{entry.title}"
    .../>
    android:id="@+id/bodyView"
    android:text="@{entry.body}"
    .../>
    ...


    View full-size slide

  12. %BUB#JOEJOH
    class EntryViewHolder(private val binding: EntryItemBinding):
    RecyclerView.ViewHolder(binding.root) {
    companion object {
    fun create(parent: ViewGroup) = EntryViewHolder(
    EntryItemBinding.inflate(LayoutInflater.from(parent.context),
    parent,
    false)
    )
    }
    fun bindTo(entry: Entry?) {
    binding.entry = entry
    }
    }

    View full-size slide

  13. σʔλϕʔε
    w 3PPN "OESPJE

    w 3FBMN
    w $PSF%BUB J04

    View full-size slide

  14. 3PPN
    @Entity(tableName = "entry",
    indices = arrayOf(
    Index(value = "date")
    ))
    data class Entry(
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
    val title: String,
    val body: String,
    val date: Date
    )

    View full-size slide

  15. 3PPN
    @Dao
    interface EntryDao {
    @Insert
    fun insertEntry(entry: Entry)
    @Update
    fun updateEntry(entry: Entry)
    @Delete
    fun deleteEntry(entry: Entry)
    @Query("SELECT * FROM entry ORDER BY date DESC")
    fun entriesByDate(): Flowable> // RxJava 2
    }

    View full-size slide

  16. 3PPN
    @Dao
    interface EntryDao {
    @Insert
    fun insertEntry(entry: Entry)
    @Update
    fun updateEntry(entry: Entry)
    @Delete
    fun deleteEntry(entry: Entry)
    @Query("SELECT * FROM entry ORDER BY date DESC")
    fun entriesByDate(): LiveData> // LiveData
    }

    View full-size slide

  17. 3PPN
    @Dao
    interface EntryDao {
    @Insert
    fun insertEntry(entry: Entry)
    @Update
    fun updateEntry(entry: Entry)
    @Delete
    fun deleteEntry(entry: Entry)
    @Query("SELECT * FROM entry ORDER BY date DESC")
    fun entriesByDate(): LivePagedListProvider // Paging Library
    }

    View full-size slide

  18. 3PPN
    class EntriesViewModel @Inject constructor(entryDao: EntryDao): ViewModel() {
    val entries: LiveData> = entryDao.entriesByDate().create(0, 50)
    }
    class EntriesAdapter: PagedListAdapter(EntryDiffCallback()) {
    override fun onBindViewHolder(holder: EntryViewHolder?, position: Int) {
    val entry = getItem(position)
    holder?.bindTo(entry)
    }
    ...
    }
    val entriesAdapter = EntriesAdapter()
    viewModel.entries.observe(this, Observer {
    list -> entriesAdapter.setList(list)
    })
    recyclerView.adapter = entriesAdapter

    View full-size slide

  19. 3FBDUJWF1SPHSBNNJOH
    w 3Y+BWB "OESPJE

    w -JWF%BUB "OESPJE

    w 3Y4XJGU J04

    w 3FBDUJWF$PDPB J04

    w 3Y+4 8FC

    View full-size slide

  20. 3Y+BWB
    fun createEntry(title: String, body: String) = Completable.create { emitter ->
    val entry = Entry(title = title, body = body, date = Date())
    // Slow
    entryDao.insertEntry(entry)
    emitter.onComplete()
    }

    View full-size slide

  21. ΦϒδΣΫτͷੜ੒ɾ؅ཧ

    View full-size slide

  22. ΦϒδΣΫτͷੜ੒ɾ؅ཧ
    w ϝϞϦ্ͷΦϒδΣΫτͱ͍͏ঢ়ଶʹ͍ͭͯ
    w ΦϒδΣΫτΛͲ͏؅ཧ͢Δ͔
    w ΦϒδΣΫτ΁ͷࢀরΛͲ͏औಘ͢Δ͔
    w ը໘ؒͰͷ৘ใͷ΍ΓऔΓ

    View full-size slide

  23. 4JOHMFUPOύλʔϯ
    w 4JOHMFUPO
    w άϩʔόϧม਺
    w 3FEVYͷ4UPSF 8FC

    View full-size slide

  24. %FQFOEFODZ*OKFDUJPO
    w %BHHFS "OESPJE

    w 3FBDU3FEVYͷDPOOFDU 8FC

    View full-size slide

  25. %BHHFS
    w %*$POUBJOFSϑϨʔϜϫʔΫ
    w ΦϒδΣΫτΛఏڙ͢Δ.PEVMFͱ

    ͦΕΛอ࣋͢Δ$PNQPOFOU
    w "OESPJE޲͚ͷػೳ͕ॆ࣮

    View full-size slide

  26. %BHHFS
    class App: Application(), HasActivityInjector {
    @Inject lateinit var activityInjector: DispatchingAndroidInjector
    private fun applicationInjector() = DaggerAppComponent.builder()
    .app(this)
    .build()
    override fun onCreate() {
    super.onCreate()
    applicationInjector().inject(this)
    }
    override fun activityInjector() = activityInjector
    }

    View full-size slide

  27. %BHHFS
    @Singleton
    @Component(modules = arrayOf(
    AndroidSupportInjectionModule::class,
    AppModule::class,
    DatabaseModule::class,
    ActivityBuilder::class
    ))
    interface AppComponent {
    @Component.Builder
    interface Builder {
    @BindsInstance
    fun app(app: App): Builder
    fun build(): AppComponent
    }
    fun inject(app: App)
    }

    View full-size slide

  28. %BHHFS
    @Module abstract class AppModule {
    @Binds abstract fun bindsContext(app: App): Context
    }
    @Module abstract class ActivityBuilder {
    @ContributesAndroidInjector
    abstract fun contributesMainActivity(): MainActivity
    }
    @Module object DatabaseModule {
    @JvmStatic @Singleton @Provides
    fun providesAppDatabase(context: Context): Database =
    Room.databaseBuilder(context, Database::class.java, "diary_db").build()
    @JvmStatic @Provides
    fun providesEntryDao(database: Database) = database.entryDao()
    }

    View full-size slide

  29. %BHHFS
    class MainActivity : AppCompatActivity() {
    @Inject lateinit var entryDao: EntryDao
    ...
    override fun onCreate(savedInstanceState: Bundle?) {
    AndroidInjection.inject(this)
    super.onCreate(savedInstanceState)
    ...
    }
    ...
    }

    View full-size slide

  30. ͦͷଞ
    w "SDIJUFDUVSF$PNQPOFOUTͷ7JFX.PEFM
    "OESPJE

    w $PSF%BUB J04

    View full-size slide

  31. ඇಉظॲཧͷந৅Խ

    View full-size slide

  32. ඇಉظॲཧͷந৅Խ
    w ඇಉظతͳॲཧ͸ͦΕࣗମ͕ঢ়ଶͱݴ͑Δ
    w ॲཧதͳͷ͔Ͳ͏͔
    w ਖ਼ৗʹऴྃͨ͠ͷ͔ࣦഊͨ͠ͷ͔
    w ϝΠϯεϨουΛࢭΊΒΕͳ͍

    View full-size slide

  33. ݴޠػೳͷར༻
    w ίʔϧόοΫ
    w ؔ਺ϙΠϯλ
    w Ϋϩʔδϟ
    w HFOFSBUPS
    w BTZOD BXBJU

    View full-size slide

  34. ந৅දݱ
    w ΩϡʔΠϯά
    w 5ISFBE1PPM&YFDVUPS +BWB

    w 0QFSBUJPO2VFVF J04

    w 1SPNJTF

    View full-size slide

  35. 3FBDUJWF1SPHSBNNJOH
    w 3Y+BWB "OESPJE

    w 3Y4XJGU J04

    w 3FBDUJWF$PDPB J04

    w 3Y+4 8FC

    View full-size slide

  36. 3Y+BWB
    val compositeDisposable = CompositeDisposable()
    fun createEntry(title: String, body: String) = Completable.create { emitter ->
    val entry = Entry(title = title, body = body, date = Date())
    entryDao.insertEntry(entry)
    emitter.onComplete()
    }
    fun create() {
    val disposable = createEntry(
    "ࠓ೔ͷ೔ه",
    "ࠓ೔ͷ൩͝൧͸ϋϯόʔάͩͬͨɻ͓͍͔ͬͨ͠ɻ")
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe()
    compositeDisposable.add(disposable)
    }

    View full-size slide

  37. (6*ΞϓϦέʔγϣϯͷಛੑ
    w Ϟσϧͷঢ়ଶΛ΋ͱʹ6*Λߋ৽͠ଓ͚Δ
    w ը໘ؒͰͷσʔλͷ΍ΓऔΓ͕ඞཁ
    w ϝΠϯεϨουΛࢭΊͯ͸͍͚ͳ͍

    View full-size slide

  38. ͭͷߏ଄
    w 0CTFSWFSύλʔϯ
    w ΦϒδΣΫτͷੜ੒ɾ؅ཧ
    w ඇಉظॲཧͷந৅Խ

    View full-size slide

  39. "OESPJEBQQ
    ,PUMJO
    3Y+BWB
    %BHHFS
    %BUB#JOEJOH
    "SDIJUFDUVSF$PNQPOFOUT

    View full-size slide

  40. "DUJWJUZ
    'SBHNFOU 'SBHNFOU
    "QQMJDBUJPO
    "QQ

    $PNQPOFOU
    "QQ.PEVMF
    7JFX.PEFM
    %BHHFS
    3Y+BWB
    "SDIJUFDUVSF
    $PNQPOFOUT
    0UIFS

    .PEFMT
    7JFX
    7JFX
    %BUB#JOEJOH
    "DUJWJUZ

    $PNQPOFOU
    "DUJWJUZ.PE

    View full-size slide

  41. 0CTFSWFSύλʔϯ
    w %BUB#JOEJOH
    w 3PPN "SDIJUFDUVSF$PNQPOFOUT

    w -JWF%BUB "OESPJE

    w 3Y+BWB

    View full-size slide

  42. ΦϒδΣΫτͷੜ੒ɾ؅ཧ
    w %BHHFS
    w 7JFX.PEFM "SDIJUFDUVSF$PNQPOFOUT

    View full-size slide

  43. ඇಉظॲཧͷந৅Խ
    w Ϋϩʔδϟ ,PUMJO

    w 3Y+BWB

    View full-size slide

  44. (6*ΞϓϦέʔγϣϯͷߏ଄ͱઃܭ
    w యܕతͳ(6*ΞϓϦέʔγϣϯͷઃܭ͸ͭͷߏ଄Ͱ

    આ໌Ͱ͖Δ
    w ͜ͷߏ଄ʹண؟͢Δ͜ͱͰෳࡶͳ(6*ΞϓϦέʔγϣϯΛ
    ͏·͘ઃܭͰ͖Δ

    View full-size slide