Slide 1

Slide 1 text

Kyash Android ͷ ΠʔελʔΤοά࣮૷ 2019/04/18 (໦) Kyash Meetup #6 Kyash Inc. @konifar

Slide 2

Slide 2 text

@konifar (Yusuke Konishi) • ೖࣾͯ͠1೥4ϲ݄͘Β͍
 http://konifar.hatenablog.com/entry/2019/03/22/222554 • AndroidΞϓϦ։ൃ͕ϝΠϯ • ೖ͙ࣾͯ͢͠ʹ39ΞχϝʔγϣϯΛ࣮૷

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

ΠʔελʔΤοά = ָ͓͠Έػೳ

Slide 5

Slide 5 text

ࡩΞχϝʔγϣϯ • ࡩͬΆ͍จࣈΛτϦΨʔ
 ʹͯ͠ɺࡩ͕෣͍ࢄΔʂ

Slide 6

Slide 6 text

http://konifar.hatenablog.com/entry/2018/06/14/173716 ࡩΞχϝʔγϣϯͷ͖͔͚ͬ

Slide 7

Slide 7 text

ࢭ·Βͳ͍ཉ๬

Slide 8

Slide 8 text

ࠓ͸ͨͿΜ 7छྨ͘Β͍͋Δ

Slide 9

Slide 9 text

ΠʔελʔΤοάͷ ίʔυ෦෼ͷ࿩Λ͠·͢

Slide 10

Slide 10 text

ੲͱࠓͷίʔυͷ࿩

Slide 11

Slide 11 text

39Ξχϝʔγϣϯ͚ͩͷࠒ • ཤྺৄࡉը໘ͷViewModelͷҰ෦ʹ͸ͼ͜Δ is39() ϝιου • ౰࣌͸͜Μͳʹָ͠ΜͰ΋Β֦͑ͯு͍ͯ͘͠ͱ͸ࢥͬͯͳ͔ͬͨ

Slide 12

Slide 12 text

ந৅Խ͢Δ

Slide 13

Slide 13 text

ΠʔελʔΤοάͷ෼ղ 1. ର৅ͷ৔ॴʹ 2. ৚݅ʹԠͯ͡ 3. Կ͔Λදࣔ͢Δ

Slide 14

Slide 14 text

39Ξχϝʔγϣϯͷ৔߹ 1. ର৅ͷ৔ॴʹʢૹۚ׬ྃը໘શମʹʣ 2. ৚݅ʹԠͯ͡ʢ39ԁͩͬͨ৔߹ʹʣ 3. Կ͔Λදࣔ͢ΔʢgifΛදࣔ͢Δʣ

Slide 15

Slide 15 text

ࡩΞχϝʔγϣϯͷ৔߹ 1. ର৅ͷ৔ॴʹʢཤྺৄࡉը໘શମʹʣ 2. ৚݅ʹԠͯ͡ʢ࠷ޙͷϝοηʔδʹࡩͬΆ͍จࣈ͕ೖ͍ͬͯͨ৔߹ʹʣ 3. Կ͔Λදࣔ͢ΔʢՖͼΒͷը૾Λ߱ΒͤΔʣ

Slide 16

Slide 16 text

ࠓͷΞϯυϩΠυͷ࣮૷ 7JFX.PEFM 5JNFMJOF)FBEFS &BTUFS&HH'BDUPSZ &BTUFS&HH,FZXPSE
 .BUDIFS 5JNFMJOF)FBEFS &BTUFS&HH 5JNFMJOF)FBEFS &BTUFS&HH 5JNFMJOF)FBEFS &BTUFS&HH EasterEggΛදࣔ͢ΔViewModel͔Β Factoryܦ༝ͰEasterEggΦϒδΣΫτΛऔ Γग़͢ EasterEggΠϯλʔϑΣʔεΛ࣮૷ͯ͠ ʰදࣔ৚݅ʱͱʰදࣔ͢ΔϦιʔεʱΛࢦ ఆ͢Δ දࣔ৚݅͸ɺଞͷը໘ͷEasterEggΫϥε ͱڞ௨ͳͷͰɺMatcherΫϥεͱͯ͠੾Γ ग़͍ͯ͠Δ

Slide 17

Slide 17 text

|--keywords | |--EasterEggKeywordsMatcher.kt | |-—SakuraEasterEggKeywordsMatcher.kt | |…… |--timeline | |--NoTimelineHeaderEasterEgg.kt | |--ThankYouReceiveTimelineHeaderEasterEgg.kt | |--TimelineHeaderEasterEgg.kt | |-—TimelineHeaderEasterEggFactory.kt | |…… |--transaction | |--NoTransactionEasterEgg.kt | |--ThankYouSendTransactionEasterEgg.kt | |--TransactionEasterEgg.kt | |--TransactionEasterEggFactory.kt | |…… • UI૚ͷσΟϨΫτϦͷதʹeastereggsσΟϨΫτϦΛஔ͍͍ͯΔ

Slide 18

Slide 18 text

|--keywords | |--EasterEggKeywordsMatcher.kt | |-—SakuraEasterEggKeywordsMatcher.kt | |…… |--timeline | |--NoTimelineHeaderEasterEgg.kt | |--ThankYouReceiveTimelineHeaderEasterEgg.kt | |--TimelineHeaderEasterEgg.kt | |-—TimelineHeaderEasterEggFactory.kt | |…… |--transaction | |--NoTransactionEasterEgg.kt | |--ThankYouSendTransactionEasterEgg.kt | |--TransactionEasterEgg.kt | |--TransactionEasterEggFactory.kt | |…… • ʮର৅ͷ৔ॴʯ͝ͱʹEasterEggΫϥεͱFactoryΫϥεΛ࡞͍ͬͯΔ • timeline = ཤྺৄࡉը໘্෦ • transaction = ૹۚɾ੥ٻ׬ྃը໘શମ

Slide 19

Slide 19 text

interface TimelineHeaderEasterEgg { @DrawableRes fun getAnimationDrawableResId(): Int? fun shouldShow(): Boolean } • λΠϜϥΠϯৄࡉͷ39ΞχϝʔγϣϯͷΠϯλʔϑΣʔε • Կ΋දࣔ͠ͳ͍έʔεͷͨΊʹɺNullObjectύλʔϯͷΑ͏ͳܗͰ NoTransactionEasterEggΫϥε΋࡞͍ͬͯΔ class NoTransactionEasterEgg : TransactionEasterEgg { override fun getAnimationDrawableResId(): Int? = null override fun shouldShow() = false }

Slide 20

Slide 20 text

/** * डऔ࣌ͷ39Ξχϝʔγϣϯ */ class ThankYouReceiveTimelineHeaderEasterEgg( val amount: Long ) : TimelineHeaderEasterEgg { override fun getAnimationDrawableResId() = R.drawable.img_receive_39 override fun shouldShow() = amount == 39L } • 39ԁΛड͚औͬͨ৔߹ͷ࣮૷ • දࣔ৚݅ͱͳΔ shouldShow() ͷςετΛ͔ͬ͠Γॻ͍͍ͯΔ

Slide 21

Slide 21 text

class SakuraEasterEggKeywordsMatcher : EasterEggKeywordsMatcher { override fun getKeywords() = arrayListOf( "͘͞Β", "αΫϥ", "ࡩ", "Ֆݟ", "͸ͳΈ", "ϋφϛ", "ԅ", String(byteArrayOf(-16, -97, -116, -72)) // ࡩͷemoji ) } • ͘͞ΒΞχϝʔγϣϯͷΩʔϫʔυΛఆٛ • JUnitͰParameterized TestΛॻ͘

Slide 22

Slide 22 text

@RunWith(Parameterized::class) class SakuraEasterEggKeywordsMatcherUnitTest( private val message: String, private val result: Boolean ) { companion object { @JvmStatic @Parameterized.Parameters fun data(): List> { return listOf( arrayOf("αΫϥ͕͘͞", true),
 arrayOf("", true), arrayOf("α Ϋϥ", false),
 …… ) } } @Test fun containsKeyword() {
 val subject = SakuraEasterEggKeywordsMatcher() assertEquals(result, subject.containsKeyword(message)) } }

Slide 23

Slide 23 text

class TimelineHeaderEasterEggFactory( val amount: Long, val message: String? ) { // ద༻͞ΕΔॱʹϦετʹηοτ͍ͯ͠·͢ private val easterEggs = arrayListOf( … // ωλόϨʹͳΔͷͰφΠγϣ ThankYouReceiveTimelineHeaderEasterEgg(amount) ) fun createEasterEgg(): TimelineHeaderEasterEgg { easterEggs.forEach { if (it.shouldShow()) return it } return NoTimelineHeaderEasterEgg() } } • Factory͸ɺEasterEggͷϦετΛ࣋ͬͯɺ৚݅ʹԠͯ͡࠷ॳʹද ࣔ৚݅ʹ߹கͨ͠EasterEggΛฦ͢

Slide 24

Slide 24 text

val easterEgg = TimelineHeaderEasterEggFactory(
 amount, 
 message
 ).createEasterEgg() 
 …
 @get:Bindable val headerEasterEggVisible: Boolean get() = easterEgg.shouldShow() @get:Bindable val headerEasterEggDrawable: Int? get() = easterEgg.getAnimationDrawableResId() • ViewModelͰEasterEggΛݩʹDataBindingͷ஋ΛܾΊͯBind • AnimationDrawableResId͸gifͳͷͰɺGifDrawableΛbindͰ͖ ΔBindingAdapterΛ࡞͍ͬͯΔ
 https://github.com/koral--/android-gif-drawable

Slide 25

Slide 25 text

ࠓޙͷίʔυͷ࿩

Slide 26

Slide 26 text

ʮͦ΋ͦ΋αʔόʔαΠ υʹϩδοΫ͋Δ΂͖ ͡Όͳ͍ʁʯ

Slide 27

Slide 27 text

ʮͦ͏ͩͶʂʂʯ

Slide 28

Slide 28 text

ࠓޙͷ໺๬ • Android/iOSʹϩδοΫ͕ࢄΒ͹Βͳ͍Α͏ʹαʔ όʔαΠυʹϩδοΫΛدͤΔ = APIԽ • ΞχϝʔγϣϯϑΝΠϧΛΫϥΠΞϯτଆͰ࣋ͨͳ ͍Α͏ʹμ΢ϯϩʔυͷ࢓૊ΈΛ༻ҙ͢Δ = Ξϓ ϦαΠζͷ࡟ݮ • ΫϥΠΞϯτͰͷந৅ԽͰ࢓༷͕ݻ·͖ͬͯͨࠓͳ Β΍͍͚ͬͯͦ͏

Slide 29

Slide 29 text

No content

Slide 30

Slide 30 text

͍Ζ͍Ζࢼͯ͠܅͚ͩͷ ΠʔελʔΤοάΛ୳ͦ͏ʂ ※ ͪͳΈʹࣗ෼ͷkyash_id͸ konifar ͩΑ

Slide 31

Slide 31 text

࠙਌ձͰฉ͍ͯ΋Β͑Ε͹ Ͱ͖Δ͚ͩԿͰ΋࿩͠·͢ ͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ