Slide 1

Slide 1 text

FragmentSenarioͱ FragmentFactoryͰ
 ָ͘͠UIςετ DeNA, SWET Nozomi Takuma

Slide 2

Slide 2 text

ࣗݾ঺հ Nozomi Takuma DeNAͷSWETάϧʔϓ Androidͱςετ͕޷͖

Slide 3

Slide 3 text

Outline FragmentScenario Usage FragmentFactory Usage FragmentScenario x FragmentFactory

Slide 4

Slide 4 text

UIςετ είʔϓ͕େ͖͘ͳΓ͗͢Δͱ
 ࣮૷΋࣮ߦ΋େม ·ͣ͸ݱ࣮తʹςετΛӡ༻Ͱ͖Δ
 είʔϓΛઃఆ͍ͨ͠ͱ͜Ζ

Slide 5

Slide 5 text

Fragmentςετ είʔϓΛ୯ҰͷFragmentʹઃఆ͢Δ ґଘΛςετμϒϧʹ͢Δ͜ͱͰ
 ͞ΒʹείʔϓΛখ͘͞΋Ͱ͖Δ

Slide 6

Slide 6 text

είʔϓΛখ͘͞(ྫ) Fragment ViewModel Test
 Double

Slide 7

Slide 7 text

είʔϓΛখ͘͞(ྫ) Fragment ViewModel Test
 Double είʔϓ͸͜͜

Slide 8

Slide 8 text

ςετͰ͖Δ͜ͱ FragmentͷUIςετ Fragment ͱViewModelͷͭͳ͗͜Έ LiveDataͷObserveͱUIߋ৽ DataBindingͰͷ࿈ܞ

Slide 9

Slide 9 text

FragmentScenario Fragmentͷςετ༻API EspressoΛ࢖ͬͨUIςετ Fragmentͷঢ়ଶΛίϯτϩʔϧ androidx.fragment.fragment-tesNng

Slide 10

Slide 10 text

FragmentScenario @Test fun test() { // FragmentΛAcNvityͷRootʹΞλονͯ͠ىಈ launchFragmentInContainer() }

Slide 11

Slide 11 text

FragmentScenario @Test fun test() { launchFragmentInContainer() // EspressoͰUIͷݕূ onView(withId(R.id.text_view)).check(matches(withText("Hello"))) }

Slide 12

Slide 12 text

FragmentScenario @Test fun test() { val scenario = launchFragmentInContainer() // Fragmentͷ࠶ੜ੒ scenario.recreate() onView(withId(R.id.stored_text)).check(matches(withText("Stored"))) }

Slide 13

Slide 13 text

FragmentScenario @Test fun test() { val scenario = launchFragmentInContainer() // FragmentʹΞΫηε͍ͨ͠ͱ͖ scenario.onFragment { fragment -> fragment.clearText() } // EspressoͰͷૢ࡞͸onFragmentϒϩοΫ಺ʹ͸ॻ͔ͳ͍ onView(withId(R.id.text)).check(matches(withText(""))) }

Slide 14

Slide 14 text

FragmentScenario Doc Test your app’s fragments h]ps://developer.android.com/ training/basics/fragments/tesNng

Slide 15

Slide 15 text

ґଘΛ੾Γ཭͍ͨ͠ DI Dagger x FragmentScenario? DI LibraryΛಋೖ͍ͯ͠ͳ͍ͱ͜Ζ΋͋Δ

Slide 16

Slide 16 text

ґଘΛ੾Γ཭͍ͨ͠ launchFragmentInContainer(fragmentArgs: Bundle? = null, @StyleRes themeResId: Int = .., factory: FragmentFactory? = null)

Slide 17

Slide 17 text

launchFragmentInContainer(fragmentArgs: Bundle? = null, @StyleRes themeResId: Int = .., factory: FragmentFactory? = null) FragmentFactory!!! ґଘΛ੾Γ཭͍ͨ͠

Slide 18

Slide 18 text

FragmentFactory FragmentΠϯελϯεੜ੒Λίϯτ ϩʔϧ ೚ҙͷίϯετϥΫλΛ࣋ͭ FragmentΛੜ੒͢ΔΑ͏ઃఆͰ͖Δ androidx.fragment.fragment:1.1.0+

Slide 19

Slide 19 text

FragmentFactory class MyFragmentFactory() : FragmentFactory() { override fun instanNate(classLoader: ClassLoader, className: String): Fragment { // classʹରͯ͠ͲͷFragmentΛੜ੒͢Δ͔Λ͜͜ʹॻ͍͍ͯ͘ if (className == MyFragment::class.java.name) { return MyFragment() } return super.instanNate(classLoader, className) } }

Slide 20

Slide 20 text

Custom Constructor class MyFragment(private val viewModelFactory: .. ) : Fragment() { private lateinit var viewModel: MyViewModel override fun onAcNvityCreated(savedInstanceState: Bundle?) { super.onAcNvityCreated(savedInstanceState) viewModel = ViewModelProviders.of(this,
 viewModelFactory).get(MyViewModel::class.java) } }

Slide 21

Slide 21 text

Custom Constructor class MyFragment(private val viewModelFactory: .. ) : Fragment() { private lateinit var viewModel: MyViewModel override fun onAcNvityCreated(savedInstanceState: Bundle?) { super.onAcNvityCreated(savedInstanceState) viewModel = ViewModelProviders.of(this,
 viewModelFactory).get(MyViewModel::class.java) } } ViewModelFactoryΛ ίϯετϥΫλͰड͚औΔFragment

Slide 22

Slide 22 text

Custom Constructor class MyFragmentFactory() : FragmentFactory() { override fun instanNate(classLoader: ClassLoader, className: String): Fragment { if (className == MyFragment::class.java.name) { // ґଘΛίϯετϥΫλͰ౉ͯ͠Fragment Λੜ੒ val viewModelFactory = MyViewModelFactory(MyDataSource()) return MyFragment(viewModelFactory) } return super.instanNate(classLoader, className) } }

Slide 23

Slide 23 text

FragmentFactoryΛ࢖͏ FragmentManager#setFragmentFactory ઃఆͨ͠FragmentFactoryΛ࢖ͬͯ Fragmentͷੜ੒Λͯ͘͠ΕΔ androidx.appcompat:appcompat:1.1.0+

Slide 24

Slide 24 text

FragmentFactoryΛ࢖͏ class MyAcNvity : AppCompatAcNvity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // setContentViewͷલʹFragmentFactoryΛઃఆ͢Δ // AcNvity͔ΒFragmentFactoryܦ༝ͰґଘΛ౉͢ͷ΋Մ supportFragmentManager.fragmentFactory = MyFragmentFactory(applicaNon) setContentView(R.layout.acNvity_my) } }

Slide 25

Slide 25 text

with NavigaNon FragmentManagerʹFragmentFactoryΛ
 ઃఆ͍ͯ͠Ε͹ɺNavigaNonભҠ࣌΋
 ઃఆͨ͠FragmentFactory͕࢖ΘΕΔ

Slide 26

Slide 26 text

with Dagger(ࢀߟURL) h]ps://satoshun.github.io/2018/11/ android_all_inject_ctor/ h]ps://github.com/satoshun-android- example/ConstructorInjecNonExample

Slide 27

Slide 27 text

FragmentFactory x UIςετ @Test fun test() { launchFragmentInContainer(factory = object : FragmentFactory() {
 override fun instanNate(classLoader: ClassLoader, className: String): Fragment { val viewModelFactory = 
 ViewModelFactory(ApplicaNonProvider.getApplicaNonContext(), 
 TestDataSource()) return MyFragment(viewModelFactory) } }) } FragmentFactory x UIςετ

Slide 28

Slide 28 text

FragmentFactory x UIςετ @Test fun test() { launchFragmentInContainer(factory = object : FragmentFactory() {
 override fun instanNate(classLoader: ClassLoader, className: String): Fragment { val viewModelFactory = 
 ViewModelFactory(ApplicaNonProvider.getApplicaNonContext(), 
 TestDataSource()) return MyFragment(viewModelFactory) } }) } FragmentFactory x UIςετ Ұ෦Λελϒʹஔ͖׵͑

Slide 29

Slide 29 text

FragmentFactory x UIςετ Fragment ViewModel Test
 Double Ͱ͖ͨ

Slide 30

Slide 30 text

FragmentFactory x UIςετ @Test fun test() { launchFragmentInContainer(factory = object : FragmentFactory() {
 override fun instanNate(classLoader: ClassLoader, className: String): Fragment { val viewModelFactory = 
 ViewModelFactory(ApplicaNonProvider.getApplicaNonContext(), 
 TestDataSource()) return MyFragment(viewModelFactory) } }) } FragmentFactory x UIςετ ͬ͞͞ͱґଘΛίϯτϩʔϧͰ͖ͯ
 ͨͷ͍͠

Slide 31

Slide 31 text

Summary FragmentScenarioͱFragmentFactoryΛ
 ࢖͑͹είʔϓΛݶఆͨ͠UIςετΛ
 ൺֱత؆୯ʹ࣮૷Ͱ͖Δ

Slide 32

Slide 32 text

͝ਗ਼ௌ͋Γ͕ͱ͏ ͍͟͝·ͨ͠ʂ