ฉันทำงานกับ dagger2 มาระยะหนึ่งแล้ว และฉันก็สับสนในการสร้างส่วนประกอบ / โมดูลของตัวเองสำหรับแต่ละกิจกรรม / ส่วนย่อย โปรดช่วยฉันชี้แจงสิ่งนี้:
ตัวอย่างเช่นเรามีแอปและแอปมีประมาณ 50 หน้าจอ เราจะใช้โค้ดตามรูปแบบ MVP และ Dagger2 สำหรับ DI สมมติว่าเรามี 50 กิจกรรมและ 50 ผู้นำเสนอ
ในความคิดของฉันโดยปกติเราควรจัดระเบียบรหัสดังนี้:
สร้าง AppComponent และ AppModule ซึ่งจะให้วัตถุทั้งหมดที่จะใช้ในขณะที่แอปเปิดอยู่
@Module public class AppModule { private final MyApplicationClass application; public AppModule(MyApplicationClass application) { this.application = application; } @Provides @Singleton Context provideApplicationContext() { return this.application; } //... and many other providers } @Singleton @Component( modules = { AppModule.class } ) public interface AppComponent { Context getAppContext(); Activity1Component plus(Activity1Module module); Activity2Component plus(Activity2Module module); //... plus 48 methods for 48 other activities. Suppose that we don't have any other Scope (like UserScope after user login, ....) }
สร้าง ActivityScope:
@Scope @Documented @Retention(value=RUNTIME) public @interface ActivityScope { }
สร้างส่วนประกอบและโมดูลสำหรับแต่ละกิจกรรม โดยปกติฉันจะจัดให้เป็นคลาสคงที่ในคลาสกิจกรรม:
@Module public class Activity1Module { public LoginModule() { } @Provides @ActivityScope Activity1Presenter provideActivity1Presenter(Context context, /*...some other params*/){ return new Activity1PresenterImpl(context, /*...some other params*/); } } @ActivityScope @Subcomponent( modules = { Activity1Module.class } ) public interface Activity1Component { void inject(Activity1 activity); // inject Presenter to the Activity } // .... Same with 49 remaining modules and components.
นี่เป็นเพียงตัวอย่างง่ายๆที่แสดงให้เห็นว่าฉันจะนำสิ่งนี้ไปใช้ได้อย่างไร
แต่เพื่อนของฉันเพิ่งให้ฉันใช้งานอีกครั้ง:
สร้าง PresenterModule ซึ่งจะให้ผู้นำเสนอทั้งหมด:
@Module public class AppPresenterModule { @Provides Activity1Presenter provideActivity1Presentor(Context context, /*...some other params*/){ return new Activity1PresenterImpl(context, /*...some other params*/); } @Provides Activity2Presenter provideActivity2Presentor(Context context, /*...some other params*/){ return new Activity2PresenterImpl(context, /*...some other params*/); } //... same with 48 other presenters. }
สร้าง AppModule และ AppComponent:
@Module public class AppModule { private final MyApplicationClass application; public AppModule(MyApplicationClass application) { this.application = application; } @Provides @Singleton Context provideApplicationContext() { return this.application; } //... and many other provides } @Singleton @Component( modules = { AppModule.class, AppPresenterModule.class } ) public interface AppComponent { Context getAppContext(); public void inject(Activity1 activity); public void inject(Activity2 activity); //... and 48 other methods for 48 other activities. Suppose that we don't have any other Scope (like UserScope after user login, ....) }
คำอธิบายของเขาคือเขาไม่จำเป็นต้องสร้างส่วนประกอบและโมดูลสำหรับแต่ละกิจกรรม ฉันคิดว่าความคิดของเพื่อนฉันไม่ดีเลย แต่โปรดแก้ไขฉันถ้าฉันผิด นี่คือเหตุผล:
หน่วยความจำรั่วไหลจำนวนมาก :
- แอปจะสร้างผู้นำเสนอ 50 คนแม้ว่าผู้ใช้จะเปิดเพียง 2 กิจกรรมก็ตาม
- หลังจากผู้ใช้ปิดกิจกรรมผู้นำเสนอจะยังคงอยู่
จะเกิดอะไรขึ้นถ้าฉันต้องการสร้างสองอินสแตนซ์ของกิจกรรมเดียว (เขาจะสร้างผู้นำเสนอสองคนได้อย่างไร)
การเริ่มต้นแอปจะใช้เวลานานมาก (เพราะต้องสร้างผู้นำเสนอวัตถุต่างๆ ... )
ขอโทษที่โพสต์ยาว แต่ช่วยชี้แจงเรื่องนี้ให้ฉันและเพื่อนด้วยฉันไม่สามารถโน้มน้าวเขาได้ ความคิดเห็นของคุณจะได้รับการชื่นชมมาก
/ ------------------------------------------------- ---------------------- /
แก้ไขหลังจากทำการสาธิต
ก่อนอื่นขอบคุณสำหรับคำตอบของ @pandawarrior ฉันควรจะสร้างการสาธิตก่อนที่จะถามคำถามนี้ ฉันหวังว่าข้อสรุปของฉันที่นี่จะช่วยคนอื่นได้
- สิ่งที่เพื่อนของฉันทำไม่ได้ทำให้หน่วยความจำรั่วไหลเว้นแต่เขาจะกำหนดขอบเขตให้กับ Provides-method (ตัวอย่างเช่น @Singleton หรือ @UserScope ... )
- เราสามารถสร้างผู้นำเสนอได้หลายคนถ้า Provides-method ไม่มีขอบเขตใด ๆ (ดังนั้นจุดที่สองของฉันก็ผิดเช่นกัน)
- กริชจะสร้างผู้นำเสนอเมื่อจำเป็นเท่านั้น (ดังนั้นแอพจะใช้เวลาไม่นานในการเริ่มต้นฉันสับสนกับ Lazy Injection)
ดังนั้นเหตุผลทั้งหมดที่ฉันได้กล่าวไว้ข้างต้นส่วนใหญ่ผิด แต่ไม่ได้หมายความว่าเราควรทำตามความคิดของเพื่อนด้วยเหตุผลสองประการ:
มันไม่ดีสำหรับสถาปัตยกรรมของแหล่งที่มาเมื่อเขาใส่ผู้นำเสนอทั้งหมดในโมดูล / ส่วนประกอบ (มันละเมิดหลักการแยกส่วนต่อประสานอาจเป็นราคาความรับผิดชอบเดียวด้วย)
เมื่อเราสร้าง Scope Component เราจะรู้ว่าเมื่อใดที่สร้างขึ้นและเมื่อใดที่ถูกทำลายซึ่งเป็นประโยชน์อย่างมากในการหลีกเลี่ยงการรั่วไหลของหน่วยความจำ ดังนั้นสำหรับแต่ละกิจกรรมเราควรสร้างส่วนประกอบที่มี @ActivityScope ลองนึกภาพตามการใช้งานของเพื่อน ๆ ว่าเราลืมใส่ Scope บางส่วนใน Provider-method => memory leaks จะเกิดขึ้น
ในความคิดของฉันกับแอปขนาดเล็ก (มีเพียงไม่กี่หน้าจอที่ไม่มีการอ้างอิงมากหรือมีการอ้างอิงที่คล้ายกัน) เราสามารถใช้ความคิดของเพื่อน ๆ ได้ แต่แน่นอนว่าไม่แนะนำ
ต้องการอ่านเพิ่มเติมเกี่ยวกับ: อะไรเป็นตัวกำหนดวงจรชีวิตของส่วนประกอบ (กราฟวัตถุ) ใน Dagger 2 ขอบเขตกิจกรรม Dagger2 ฉันต้องการโมดูล / ส่วนประกอบกี่ชิ้น?
และอีกหนึ่งข้อสังเกต: หากคุณต้องการดูว่าเมื่อใดที่วัตถุถูกทำลายคุณสามารถเรียกใช้วิธีการเหล่านั้นร่วมกันและ GC จะทำงานทันที:
System.runFinalization();
System.gc();
หากคุณใช้เพียงวิธีเดียว GC จะทำงานในภายหลังและคุณอาจได้ผลลัพธ์ที่ไม่ถูกต้อง
ControllerModule
จะสร้างใหม่Presenter
แล้วพรีเซนเตอร์จะถูกฉีดในหรือActivity
Fragment
มีความคิดเห็นที่ชัดเจนในการสนับสนุนหรือต่อต้านสิ่งนี้หรือไม่?