Dagger Android Injection - Part 3 - Inject Fragment

Nutron
3 min readFeb 18, 2018

--

image power by www.flaticon.com

บทความนี้จะพูดถึงการทำ dependency Injection ด้วย Dagger2 โดยจะเน้นอธิบาย ถึง API ใหม่ใน Dagger2 version 2.11+ ที่สามารถทำงานร่วมกัน Android Environment ได้ดีทำให้การ Inject Activity หรือ Fragment ทำได้ง่ายขึ้น โดยจะแบ่งเป็นสองตอนคือ

Lessons learn

จากบทความที่แล้วเราได้ทราบว่า Activity กับ Application มีความสัมพันธ์กัน โดย Application จะประกอบไปด้วยหลายๆ Activity ดังนั้น AppComponent ที่เป็น Component หลักของ Application จึงเป็น Root ของ ActivityComponent อื่นๆด้วย เช่นกัน ซึ่งแสดงให้เห็นดังภาพด้านล่าง

ในทำนองเดียวกัน Fragment กับ Activity ก็มีความสัมพันธ์เช่นเดียวกับ Activity กับ Application โดยหนึ่ง Activity อาจจะประกอบไปด้วยหลายๆ Fragment (หรือไม่มีเลย) ซึ่งแน่นอนว่า Component ของ Fragment ก็ต้องมีความสัมพันธ์กับ Component ของ Activity ด้วย ถึงจุดนี้หลายๆคนคงน่าจะเดาออกว่าภาพรวมความสัมพันธ์ของ FragmentComponent และ ActivityComponent จะเป็นอย่างไร ใครที่ยังนึกไม่ออกลองดูภาพด้านล่างประกอบครับ

Start implementing, No more theory!

หลังจากที่เราเห็นภาพรวมของความสัมพันธ์กันไปแล้ว ก็ได้เวลาลงมือกันครับโดยจะขอทำต่อจากบทความที่แล้ว โดยสมมุติเหตุการณ์ว่า MainActivity ของเรามี DetailFragment เป็นส่วนหนึ่งของการแสดงผลข้อมูล ซึ่งก่อนที่จะไปเริ่มลงโค้ดกัน ก็ขอทบทวนขั้นตอนการ Inject Activity กันก่อน โดยขั้นตอนของการ Inject Activity สามารถสรุปคร่าวๆได้ดังนี้

  1. สร้าง AppModule ซึ่งเป็น Module ของ AppComponent ขึ้นมา
  2. สร้าง AppComponent แล้วกำหนด AppModule ให้กับ AppComponent
  3. สร้าง Module ของ ActivityComponent
  4. สร้าง ActivityComponent แล้วกำหนด Module ที่สร้างในข้อสามให้กับ ActivityComponent
  5. กำหนด ActivityComponent ให้กับ AppModule โดยใช้คำสั่ง subcomponent
  6. สร้าง ActivityBinder เพื่อบอก Dagger ว่าจะมี Activity Component อะไรบ้าง
  7. กำหนด ActivityBinder ให้กับ AppComponent เนื่องจาก root component ของ ActivityComponent ต่างๆคือ AppComponent
  8. Implement interface HasActivityInjector ใน class Application เพื่อกำหนดตัว ActivityInjector ให้กับ Dagger
  9. สร้างตัวแปล DispatchingAndroidInjector<Activity> แล้ว return กลับไปใน method activityInjector ที่มาพร้อมกับ interface HasActivityInjector เพื่อใช้ dagger สามารถ Inject Activity ต่างๆของเราได้
  10. [OPTIONAL] ทำลายขั้นตอนที่ 4, 5 ด้วย @ContributesAndroidInjector

เมื่อเข้าใจถึงวิธีการ Inject Activity แล้ว การ Inject Fragment ก็จะทำไม่ต่างกันครับ โดย FragmentComponent จะไปอิงกับ ActivityComponent แทน

Step 1). สร้าง Module ของ FragmentComponent

ให้เราสร้าง Module ของ Component ขึ้นมาก่อน โดยในที่นี้จะให้ชื่อว่า DetailFragmentModule ครับ

Step 2). สร้าง FragmentBinder

เนื่องจากว่าเราจะใช้ความสามารถของ @ContributesAndroidInjector ดังนั้นเราจะข้ามขั้นตอนของการสร้าง Component สำหรับ Fragment ไป เพราะ@ContributesAndroidInjector จะไปสร้าง Component ให้เราเองอัตโนมัติ ซึ่งหน้าตาความสัมพันธ์จะเป็นประมาณภาพด้านล่างโดยให้เราสังเกตุว่า เราจะไม่มีการสร้าง FragmentComponent ขึ้นมา

ให้เราสร้าง class MainFragmentBinder ขึ้นมา ที่ตั้งชื่อเป็น MainFragmentBinder เพราะว่า class นี้จะเป็นตัวกำหนด FragmentComponent ทั้งหมดที่จะมีใน MainComponent ซึ่ง class FragmentBinder จะเป็น class ที่บอก Dagger ให้รู้ว่าเราจะมี FragmentComponent อะไรบ้าง โดยในที่นี้เราจะมีแค่ DetailFragmentComponent

step 3). กำหนด MainFragmentBinder ให้กับ MainActivityComponent

กำหนด MainFragmentBinder ให้กับ MainActivityComponent ที่อยู่ใน ActivityBinder เนื่องจาก root component ของ DetailFragmentComponent ก็คือ MainActivityComponent ซึ่งจะเห็นว่าในขั้นตอนนี้จะคล้ายๆกับตอนที่เรากำหน่อย ActivityBinder ให้กับ AppComponent นั้นเอง

step 4). Implement interface HasSupportFragmentInjector ใน MainActivity

Implement interface HasSupportFragmentInjector ให้กับ MainActivity เพื่อบอก Dagger ว่าเรามี Fragment ที่ต้องการ Inject ใน MainActivity นี้ และอย่าลืมสร้าง instance ของ DispatchingAndroidInjector ให้กับ interface นี้ด้วย ซึ่งจะได้โค้ดหน้าตาประมาณนี้

ซึ่งในขั้นตอนนี้หากใครจะใช้วิธีลัดให้กระชับกว่าเดิม (เหมือนตอนใช้ DaggerApplication) ก็สามารถเปลี่ยนจากการ implement HasSupportFragmentInjector ไปเป็นการ Extend ความสามารถของ Class DaggerAppCompatActivity ได้ เพราะ class นี้ Implement interface HasSupportFragmentInjector ให้กับเราแล้ว แต่อย่างที่บอกเรายังยึด Concept “Composition over inheritance” ดังนั้น เราจะเลือกวิธี Implement ครับ

step 5). Inject Fragment

ถึงจุดนี้เราก็พร้อมใช้งาน Dagger ที่สามารถ Inject ของต่างๆให้กับ Fragment ของเราได้แล้ว โดยที่เราไม่ต้องสร้าง Component เหล่านั้นขึ้นมาใน Fragment ของเรา โดยขั้นตอนการเรียกใช้ใน Fragment จะเป็นประมาณนี้ครับ

class DetailFragment : Fragment(), FragmentDetailContract.View {

@Inject
lateinit var presenter: FragmentDetailContract.UserActionListener

...

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this)
}
...
}

เพียงเท่านี้ presenter ก็จะถูก Inject เข้าไปใน Fragment ของเรา พร้อมใช้งานทันที

ใครสนใจดูโค้ดทั้งหมดสามารถไป Checkout ออกมาดูได้ตาม link ด้านล่างนี้ได้ครับ

Conclusion

ในบทความนี้เราได้เรียนรู้การใช้ API ใหม่ของ Dagger2 เพื่อช่วย Inject object ต่างๆให้กับ Fragment ของเรา ซึ่งจะเห็นว่าขึ้นตอนการทำ ก็ไม่ต่างจากการทำ Injection ของ Activity มากนัก แต่อย่างไรก็ตามจะเห็นว่าขั้นตอนการทำจะค่อนข้างซับซ้อนอยู่พอสมควร ซึ่งต้องอาศัยความจำ ความเข้าใจ และการฝึกฝน แต่รับรองว่าหากเราใช้งานมันได้อย่างคล่องแคล่วแล้ว ผลรับที่ได้คุ้มค่าอย่างแน่นอนครับ

สุดท้ายนี้ก็เช่นเคยครับ หากผู้อ่านคิดว่าบทความนี้มีประโยชน์ ก็ฝากกด 👏 เป็นกำลังใจให้ด้วยนะครับ

--

--