กริช - เราควรสร้างส่วนประกอบและโมดูลสำหรับแต่ละกิจกรรม / ชิ้นส่วน


85

ฉันทำงานกับ dagger2 มาระยะหนึ่งแล้ว และฉันก็สับสนในการสร้างส่วนประกอบ / โมดูลของตัวเองสำหรับแต่ละกิจกรรม / ส่วนย่อย โปรดช่วยฉันชี้แจงสิ่งนี้:

ตัวอย่างเช่นเรามีแอปและแอปมีประมาณ 50 หน้าจอ เราจะใช้โค้ดตามรูปแบบ MVP และ Dagger2 สำหรับ DI สมมติว่าเรามี 50 กิจกรรมและ 50 ผู้นำเสนอ

ในความคิดของฉันโดยปกติเราควรจัดระเบียบรหัสดังนี้:

  1. สร้าง 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, ....)
    
    }
    
  2. สร้าง ActivityScope:

    @Scope
    @Documented
    @Retention(value=RUNTIME)
    public @interface ActivityScope {
    }
    
  3. สร้างส่วนประกอบและโมดูลสำหรับแต่ละกิจกรรม โดยปกติฉันจะจัดให้เป็นคลาสคงที่ในคลาสกิจกรรม:

    @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.
    

นี่เป็นเพียงตัวอย่างง่ายๆที่แสดงให้เห็นว่าฉันจะนำสิ่งนี้ไปใช้ได้อย่างไร

แต่เพื่อนของฉันเพิ่งให้ฉันใช้งานอีกครั้ง:

  1. สร้าง 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.
    
    }
    
  2. สร้าง 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, ....)
    
    }
    

คำอธิบายของเขาคือเขาไม่จำเป็นต้องสร้างส่วนประกอบและโมดูลสำหรับแต่ละกิจกรรม ฉันคิดว่าความคิดของเพื่อนฉันไม่ดีเลย แต่โปรดแก้ไขฉันถ้าฉันผิด นี่คือเหตุผล:

  1. หน่วยความจำรั่วไหลจำนวนมาก :

    • แอปจะสร้างผู้นำเสนอ 50 คนแม้ว่าผู้ใช้จะเปิดเพียง 2 กิจกรรมก็ตาม
    • หลังจากผู้ใช้ปิดกิจกรรมผู้นำเสนอจะยังคงอยู่
  2. จะเกิดอะไรขึ้นถ้าฉันต้องการสร้างสองอินสแตนซ์ของกิจกรรมเดียว (เขาจะสร้างผู้นำเสนอสองคนได้อย่างไร)

  3. การเริ่มต้นแอปจะใช้เวลานานมาก (เพราะต้องสร้างผู้นำเสนอวัตถุต่างๆ ... )

ขอโทษที่โพสต์ยาว แต่ช่วยชี้แจงเรื่องนี้ให้ฉันและเพื่อนด้วยฉันไม่สามารถโน้มน้าวเขาได้ ความคิดเห็นของคุณจะได้รับการชื่นชมมาก

/ ------------------------------------------------- ---------------------- /

แก้ไขหลังจากทำการสาธิต

ก่อนอื่นขอบคุณสำหรับคำตอบของ @pandawarrior ฉันควรจะสร้างการสาธิตก่อนที่จะถามคำถามนี้ ฉันหวังว่าข้อสรุปของฉันที่นี่จะช่วยคนอื่นได้

  1. สิ่งที่เพื่อนของฉันทำไม่ได้ทำให้หน่วยความจำรั่วไหลเว้นแต่เขาจะกำหนดขอบเขตให้กับ Provides-method (ตัวอย่างเช่น @Singleton หรือ @UserScope ... )
  2. เราสามารถสร้างผู้นำเสนอได้หลายคนถ้า Provides-method ไม่มีขอบเขตใด ๆ (ดังนั้นจุดที่สองของฉันก็ผิดเช่นกัน)
  3. กริชจะสร้างผู้นำเสนอเมื่อจำเป็นเท่านั้น (ดังนั้นแอพจะใช้เวลาไม่นานในการเริ่มต้นฉันสับสนกับ Lazy Injection)

ดังนั้นเหตุผลทั้งหมดที่ฉันได้กล่าวไว้ข้างต้นส่วนใหญ่ผิด แต่ไม่ได้หมายความว่าเราควรทำตามความคิดของเพื่อนด้วยเหตุผลสองประการ:

  1. มันไม่ดีสำหรับสถาปัตยกรรมของแหล่งที่มาเมื่อเขาใส่ผู้นำเสนอทั้งหมดในโมดูล / ส่วนประกอบ (มันละเมิดหลักการแยกส่วนต่อประสานอาจเป็นราคาความรับผิดชอบเดียวด้วย)

  2. เมื่อเราสร้าง Scope Component เราจะรู้ว่าเมื่อใดที่สร้างขึ้นและเมื่อใดที่ถูกทำลายซึ่งเป็นประโยชน์อย่างมากในการหลีกเลี่ยงการรั่วไหลของหน่วยความจำ ดังนั้นสำหรับแต่ละกิจกรรมเราควรสร้างส่วนประกอบที่มี @ActivityScope ลองนึกภาพตามการใช้งานของเพื่อน ๆ ว่าเราลืมใส่ Scope บางส่วนใน Provider-method => memory leaks จะเกิดขึ้น

ในความคิดของฉันกับแอปขนาดเล็ก (มีเพียงไม่กี่หน้าจอที่ไม่มีการอ้างอิงมากหรือมีการอ้างอิงที่คล้ายกัน) เราสามารถใช้ความคิดของเพื่อน ๆ ได้ แต่แน่นอนว่าไม่แนะนำ

ต้องการอ่านเพิ่มเติมเกี่ยวกับ: อะไรเป็นตัวกำหนดวงจรชีวิตของส่วนประกอบ (กราฟวัตถุ) ใน Dagger 2 ขอบเขตกิจกรรม Dagger2 ฉันต้องการโมดูล / ส่วนประกอบกี่ชิ้น?

และอีกหนึ่งข้อสังเกต: หากคุณต้องการดูว่าเมื่อใดที่วัตถุถูกทำลายคุณสามารถเรียกใช้วิธีการเหล่านั้นร่วมกันและ GC จะทำงานทันที:

    System.runFinalization();
    System.gc();

หากคุณใช้เพียงวิธีเดียว GC จะทำงานในภายหลังและคุณอาจได้ผลลัพธ์ที่ไม่ถูกต้อง

คำตอบ:


85

การประกาศโมดูลแยกสำหรับแต่ละโมดูลActivityไม่ใช่ความคิดที่ดีเลย การประกาศองค์ประกอบแยกต่างหากสำหรับแต่ละส่วนActivityนั้นยิ่งแย่ลงไปอีก เหตุผลที่อยู่เบื้องหลังสิ่งนี้ง่ายมาก - คุณไม่จำเป็นต้องใช้โมดูล / ส่วนประกอบเหล่านี้จริงๆ (อย่างที่คุณเคยเห็นมาแล้วด้วยตัวเอง)

อย่างไรก็ตามการมีส่วนประกอบเพียงอย่างเดียวที่เชื่อมโยงกับApplicationวงจรชีวิตและการใช้เพื่อฉีดเข้าไปในทั้งหมดActivitiesก็ไม่ใช่วิธีที่ดีที่สุดเช่นกัน (นี่คือแนวทางของเพื่อนคุณ) ไม่เหมาะสมเนื่องจาก:

  1. มัน จำกัด คุณไว้เพียงขอบเขตเดียว ( @Singletonหรือขอบเขตที่กำหนดเอง)
  2. ขอบเขตเดียวที่คุณถูก จำกัด ให้ทำให้อ็อบเจ็กต์ที่ถูกแทรกเป็น "แอพพลิเคชั่น singletons" ดังนั้นความผิดพลาดในการกำหนดขอบเขตหรือการใช้อ็อบเจ็กต์ที่กำหนดขอบเขตไม่ถูกต้องอาจทำให้หน่วยความจำรั่วไหลได้อย่างง่ายดาย
  3. คุณจะต้องใช้ Dagger2 เพื่อฉีดเข้าไปServicesด้วยเช่นกัน แต่Servicesอาจต้องใช้วัตถุอื่นที่ไม่ใช่Activities(เช่นServicesไม่ต้องการผู้นำเสนอไม่มีFragmentManagerฯลฯ ) การใช้ส่วนประกอบเดียวทำให้คุณขาดความยืดหยุ่นในการกำหนดกราฟวัตถุที่แตกต่างกันสำหรับส่วนประกอบต่างๆ

ดังนั้นองค์ประกอบต่อActivityจึงเป็นการใช้งานมากเกินไป แต่ส่วนประกอบเดียวสำหรับแอปพลิเคชันทั้งหมดนั้นไม่ยืดหยุ่นเพียงพอ ทางออกที่ดีที่สุดอยู่ระหว่างความสุดขั้วเหล่านี้ (ตามปกติ)

ฉันใช้แนวทางต่อไปนี้:

  1. คอมโพเนนต์ "แอปพลิเคชัน" เดี่ยวที่จัดเตรียมอ็อบเจ็กต์ "global" (เช่นอ็อบเจ็กต์ที่มี global state ซึ่งแชร์ระหว่างคอมโพเนนต์ทั้งหมดในแอ็พพลิเคชัน) สร้างอินสแตนซ์ในApplication.
  2. ส่วนประกอบย่อย "คอนโทรลเลอร์" ของคอมโพเนนต์ "แอปพลิเคชัน" ที่จัดเตรียมอ็อบเจ็กต์ที่ "คอนโทรลเลอร์" ที่ผู้ใช้ต้องเผชิญ (ในสถาปัตยกรรมของฉันคือActivitiesและFragments) สร้างอินสแตนซ์ในแต่ละActivityและFragmentและ
  3. ส่วนประกอบย่อย "บริการ" ของคอมโพเนนต์ "แอปพลิเคชัน" ที่จัดเตรียมอ็อบเจ็กต์ที่ทุกคนServicesต้องการ Serviceอินสแตนซ์ในแต่ละ

ต่อไปนี้เป็นตัวอย่างวิธีที่คุณสามารถใช้แนวทางเดียวกันได้


แก้ไขกรกฎาคม 2017

ฉันตีพิมพ์กวดวิชาวิดีโอที่แสดงให้เห็นถึงวิธีการจัดโครงสร้างกริชรหัสฉีดพึ่งพาในการประยุกต์ใช้ Android: Android กริชสำหรับผู้เชี่ยวชาญด้านการสอน


แก้ไขกุมภาพันธ์ 2018

ฉันได้เผยแพร่หลักสูตรฉบับสมบูรณ์เกี่ยวกับการฉีดการพึ่งพาใน AndroidAndroid

ในหลักสูตรนี้ฉันจะอธิบายทฤษฎีของการฉีดพึ่งพาและแสดงให้เห็นว่ามันเกิดขึ้นตามธรรมชาติในแอปพลิเคชัน Android ได้อย่างไร จากนั้นฉันจะสาธิตวิธีการสร้าง Dagger ให้เข้ากับแผนการฉีดพึ่งพาทั่วไป

หากคุณเรียนหลักสูตรนี้คุณจะเข้าใจว่าเหตุใดแนวคิดของการมีคำจำกัดความแยกต่างหากของโมดูล / ส่วนประกอบสำหรับแต่ละกิจกรรม / ส่วนย่อยจึงมีข้อบกพร่องโดยพื้นฐานที่สุด

วิธีการดังกล่าวทำให้โครงสร้างของเลเยอร์การนำเสนอจากชุดคลาส "ฟังก์ชัน" ถูกสะท้อนเข้าไปในโครงสร้างของชุดคลาส "การก่อสร้าง" ดังนั้นการเชื่อมต่อเข้าด้วยกัน สิ่งนี้ขัดต่อวัตถุประสงค์หลักของการฉีดแบบพึ่งพาซึ่งก็เพื่อให้ชุดคลาส "การก่อสร้าง" และ "ฟังก์ชัน" ไม่ปะติดปะต่อกัน


ขอบเขตการใช้งาน:

@ApplicationScope
@Component(modules = ApplicationModule.class)
public interface ApplicationComponent {

    // Each subcomponent can depend on more than one module
    ControllerComponent newControllerComponent(ControllerModule module);
    ServiceComponent newServiceComponent(ServiceModule module);

}


@Module
public class ApplicationModule {

    private final Application mApplication;

    public ApplicationModule(Application application) {
        mApplication = application;
    }

    @Provides
    @ApplicationScope
    Application applicationContext() {
        return mApplication;
    }

    @Provides
    @ApplicationScope
    SharedPreferences sharedPreferences() {
        return mApplication.getSharedPreferences(Constants.PREFERENCES_FILE, Context.MODE_PRIVATE);
    }

    @Provides
    @ApplicationScope
    SettingsManager settingsManager(SharedPreferences sharedPreferences) {
        return new SettingsManager(sharedPreferences);
    }
}

ขอบเขตตัวควบคุม:

@ControllerScope
@Subcomponent(modules = {ControllerModule.class})
public interface ControllerComponent {

    void inject(CustomActivity customActivity); // add more activities if needed

    void inject(CustomFragment customFragment); // add more fragments if needed

    void inject(CustomDialogFragment customDialogFragment); // add more dialogs if needed

}



@Module
public class ControllerModule {

    private Activity mActivity;
    private FragmentManager mFragmentManager;

    public ControllerModule(Activity activity, FragmentManager fragmentManager) {
        mActivity = activity;
        mFragmentManager = fragmentManager;
    }

    @Provides
    @ControllerScope
    Context context() {
        return mActivity;
    }

    @Provides
    @ControllerScope
    Activity activity() {
        return mActivity;
    }

    @Provides
    @ControllerScope
    DialogsManager dialogsManager(FragmentManager fragmentManager) {
        return new DialogsManager(fragmentManager);
    }

    // @Provides for presenters can be declared here, or in a standalone PresentersModule (which is better)
}

จากนั้นในActivity:

public class CustomActivity extends AppCompatActivity {

    @Inject DialogsManager mDialogsManager;

    private ControllerComponent mControllerComponent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getControllerComponent().inject(this);

    }

    private ControllerComponent getControllerComponent() {
        if (mControllerComponent == null) {

            mControllerComponent = ((MyApplication)getApplication()).getApplicationComponent()
                    .newControllerComponent(new ControllerModule(this, getSupportFragmentManager()));
        }

        return mControllerComponent;
    }
}

ข้อมูลเพิ่มเติมเกี่ยวกับการฉีดแบบพึ่งพา:

Dagger 2 Scopes Demystified

Dependency Injection ใน Android


1
ขอบคุณ @vasiliy สำหรับการแบ่งปันความคิดเห็นของคุณ นี่คือวิธีที่ฉันจะใช้มันและตามกลยุทธ์ในปัจจุบัน ในกรณีที่มีรูปแบบ MVP ที่เรียกว่าControllerModuleจะสร้างใหม่Presenterแล้วพรีเซนเตอร์จะถูกฉีดในหรือActivity Fragmentมีความคิดเห็นที่ชัดเจนในการสนับสนุนหรือต่อต้านสิ่งนี้หรือไม่?
Wahib Ul Haq

@ Vasiliy ฉันอ่านบทความทั้งหมดของคุณและฉันพบว่าบางทีคุณอาจไม่ได้พิจารณาผู้โต้ตอบและผู้นำเสนอในกลไก ControllerModule จะให้การพึ่งพาของผู้โต้ตอบและผู้นำเสนอทั้งหมดหรือไม่ โปรดให้คำแนะนำเล็กน้อยในกรณีที่ฉันพลาดอะไรไป
iamcrypticcoder

@ mahbub.kuet ถ้าฉันเข้าใจสิ่งที่คุณอ้างถึงโดย "ผู้โต้ตอบ" และ "ผู้นำเสนอ" ControllerComponentควรฉีดสิ่งเหล่านี้ ไม่ว่าคุณจะต่อสายเข้าไปข้างในControllerModuleหรือแนะนำโมดูลเพิ่มเติมก็ขึ้นอยู่กับคุณ ในแอปจริงฉันแนะนำให้ใช้วิธีการหลายโมดูลต่อองค์ประกอบแทนที่จะรวมทุกอย่างไว้ในโมดูลเดียว นี่คือตัวอย่างสำหรับApplicationComponentแต่คอนโทรลเลอร์จะเหมือนกัน: github.com/techyourchance/idocare-android/tree/master/app/src/…
Vasiliy

2
@ Mr.Hyde โดยทั่วไปใช่ แต่คุณจะต้องประกาศอย่างชัดเจนในการApplicationComponentอ้างอิงทั้งหมดที่ControllerComponentสามารถใช้ได้ นอกจากนี้จำนวนวิธีการของรหัสที่สร้างขึ้นจะสูงขึ้น ฉันยังไม่พบเหตุผลที่ดีในการใช้ส่วนประกอบที่อ้างอิง
Vasiliy

1
วันนี้ฉันใช้แนวทางนี้ในทุกโครงการของฉันและฉันไม่ได้ใช้อะไรเลยจากdagger.androidแพ็คเกจเพราะฉันคิดว่ามันไม่ดี ดังนั้นตัวอย่างนี้จึงยังคงเป็นปัจจุบันอยู่มากและยังคงเป็นวิธีที่ดีที่สุดในการทำ DI ใน Android IMHO
Vasiliy

15

ตัวอย่างที่ดีที่สุดบางส่วนของวิธีจัดระเบียบส่วนประกอบโมดูลและแพ็คเกจของคุณมีอยู่ในที่เก็บ Github ของ Google Android Architecture Blueprints ที่นี่ที่นี่

หากคุณตรวจสอบซอร์สโค้ดที่นั่นคุณจะเห็นว่ามีคอมโพเนนต์ที่กำหนดขอบเขตแอพเดียว (พร้อมวงจรชีวิตของระยะเวลาของแอพทั้งหมด) จากนั้นแยกส่วนประกอบที่กำหนดขอบเขตกิจกรรมสำหรับกิจกรรมและส่วนที่สอดคล้องกับฟังก์ชันที่กำหนดใน a โครงการ. ตัวอย่างเช่นมีแพ็คเกจต่อไปนี้:

addedittask
taskdetail
tasks

ภายในแต่ละแพ็คเกจมีโมดูลส่วนประกอบผู้นำเสนอ ฯลฯ ตัวอย่างเช่นภายในtaskdetailมีคลาสต่อไปนี้:

TaskDetailActivity.java
TaskDetailComponent.java
TaskDetailContract.java
TaskDetailFragment.java
TaskDetailPresenter.java
TaskDetailPresenterModule.java

ข้อดีของการจัดระเบียบด้วยวิธีนี้ (แทนที่จะจัดกลุ่มกิจกรรมทั้งหมดในคอมโพเนนต์หรือโมดูลเดียว) คือคุณสามารถใช้ประโยชน์จากตัวปรับการเข้าถึง Java และดำเนินการตามรายการ Java ที่มีประสิทธิภาพ 13 กล่าวอีกนัยหนึ่งคลาสที่จัดกลุ่มฟังก์ชันจะอยู่ในลักษณะเดียวกัน แพคเกจและคุณสามารถใช้ประโยชน์จากprotectedและpackage-private ตัวปรับแต่งการเข้าถึงเพื่อป้องกันการใช้งานชั้นเรียนของคุณโดยไม่ได้ตั้งใจ


1
นี่เป็นแนวทางที่ฉันชอบด้วย ฉันไม่ชอบกิจกรรม / ชิ้นส่วนที่เข้าถึงสิ่งที่พวกเขาไม่ควรทำ
Joao Sousa

3

ตัวเลือกแรกจะสร้างคอมโพเนนต์ย่อยสำหรับแต่ละกิจกรรมโดยที่กิจกรรมสามารถสร้างคอมโพเนนต์ย่อยที่จัดเตรียมการพึ่งพา (ผู้นำเสนอ) สำหรับกิจกรรมนั้น ๆ เท่านั้น

ตัวเลือกที่สองจะสร้าง@Singletonองค์ประกอบเดียวที่สามารถให้ผู้นำเสนอเป็นการอ้างอิงที่ไม่ได้กำหนดขอบเขตซึ่งหมายความว่าเมื่อคุณเข้าถึงพวกเขาคุณจะสร้างอินสแตนซ์ใหม่ของผู้นำเสนอทุกครั้ง (ไม่มันจะไม่สร้างอินสแตนซ์ใหม่จนกว่าคุณจะร้องขอ)


ในทางเทคนิคไม่มีวิธีใดเลวร้ายไปกว่าอีกวิธีหนึ่ง แนวทางแรกไม่ได้แยกผู้นำเสนอตามฟีเจอร์ แต่แยกตามชั้น

ฉันเคยใช้ทั้งสองอย่างมันใช้ได้ทั้งคู่

ข้อเสียเพียงประการเดียวของโซลูชันแรก (หากคุณใช้@Component(dependencies={...}แทน@Subcomponent) คือคุณต้องตรวจสอบให้แน่ใจว่าไม่ใช่กิจกรรมที่สร้างโมดูลของตนเองภายในเนื่องจากคุณไม่สามารถแทนที่การใช้งานวิธีโมดูลด้วยการล้อเลียนได้ จากนั้นอีกครั้งหากคุณใช้การฉีดคอนสตรัคเตอร์แทนการฉีดสนามคุณสามารถสร้างคลาสได้โดยตรงด้วยคอนสตรัคเตอร์โดยให้มันล้อเลียนโดยตรง


1

ใช้Provider<"your component's name">แทนการใช้งานส่วนประกอบง่ายๆเพื่อหลีกเลี่ยงการรั่วไหลของหน่วยความจำและสร้างส่วนประกอบที่ไร้ประโยชน์จำนวนมาก ดังนั้นส่วนประกอบของคุณจะถูกสร้างขึ้นโดย lazy เมื่อคุณเรียกใช้เมธอด get () เนื่องจากคุณไม่ได้ใส่อินสแตนซ์ของส่วนประกอบ แต่เป็นเพียงแค่ผู้ให้บริการแทน ดังนั้นผู้นำเสนอของคุณจะถูกนำไปใช้หากมีการเรียก. get () ของผู้ให้บริการ อ่านเกี่ยวกับผู้ให้บริการที่นี่และใช้สิ่งนี้ ( เอกสารทางการกริช )


และวิธีที่ดีอื่น ๆ คือการใช้การเชื่อมต่อหลายมิติ ตามนั้นคุณควรผูกผู้นำเสนอของคุณเข้ากับแผนที่และสร้างผ่านผู้ให้บริการเมื่อคุณต้องการ ( นี่คือเอกสารเกี่ยวกับการเชื่อมโยงหลายมิติ )


-5

เพื่อนของคุณถูกต้องคุณไม่จำเป็นต้องสร้างส่วนประกอบและโมดูลสำหรับทุกกิจกรรม Dagger ควรจะช่วยคุณลดโค้ดที่ยุ่งเหยิงและทำให้กิจกรรม Android ของคุณสะอาดขึ้นด้วยการมอบหมายการสร้างอินสแตนซ์ของคลาสให้กับโมดูลแทนที่จะสร้างอินสแตนซ์ในวิธีการ onCreate ของกิจกรรม

ปกติเราจะทำแบบนี้

public class MainActivity extends AppCompatActivity {


Presenter1 mPresenter1;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mPresenter1 = new Presenter1(); // you instantiate mPresentation1 in onCreate, imagine if there are 5, 10, 20... of objects for you to instantiate.
}

}

คุณทำสิ่งนี้แทน

public class MainActivity extends AppCompatActivity {

@Inject
Presenter1 mPresenter1; // the Dagger module take cares of instantiation for your

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    injectThisActivity();
}

private void injectThisActivity() {
    MainApplication.get(this)
            .getMainComponent()
            .inject(this);
}}

ดังนั้นการเขียนสิ่งต่างๆมากเกินไปทำให้จุดประสงค์ของกริชไม่ใช่หรือ? ฉันค่อนข้างจะสร้างอินสแตนซ์ผู้นำเสนอในกิจกรรมถ้าฉันต้องสร้างโมดูลและส่วนประกอบสำหรับทุกกิจกรรม

สำหรับคำถามของคุณเกี่ยวกับ:

1- หน่วยความจำรั่ว:

ไม่เว้นแต่คุณจะใส่ไฟล์ @Singletonคำอธิบายประกอบให้กับผู้นำเสนอที่คุณให้ไว้ Dagger จะสร้างวัตถุเมื่อใดก็ตามที่คุณทำ@Injectในคลาสเป้าหมาย "เท่านั้น จะไม่สร้างผู้นำเสนอคนอื่นในสถานการณ์ของคุณ คุณสามารถลองใช้ Log เพื่อดูว่าสร้างขึ้นหรือไม่

@Module
public class AppPresenterModule {

@Provides
@Singleton // <-- this will persists throughout the application, too many of these is not good
Activity1Presenter provideActivity1Presentor(Context context, ...some other params){
    Log.d("Activity1Presenter", "Activity1Presenter initiated");
    return new Activity1PresenterImpl(context, ...some other params);
}

@Provides // Activity2Presenter will be provided every time you @Inject into the activity
Activity2Presenter provideActivity2Presentor(Context context, ...some other params){
    Log.d("Activity2Presenter", "Activity2Presenter initiated");
    return new Activity2PresenterImpl(context, ...some other params);
}

.... Same with 48 others presenters.

}

2- คุณฉีดสองครั้งและบันทึกรหัสแฮช

//MainActivity.java
@Inject Activity1Presenter mPresentation1
@Inject Activity1Presenter mPresentation2

@Inject Activity2Presenter mPresentation3
@Inject Activity2Presenter mPresentation4
//log will show Presentation2 being initiated twice

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    injectThisActivity();
    Log.d("Activity1Presenter1", mPresentation1.hashCode());
    Log.d("Activity1Presenter2", mPresentation2.hashCode());
    //it will shows that both have same hash, it's a Singleton
    Log.d("Activity2Presenter1", mPresentation3.hashCode());
    Log.d("Activity2Presenter2", mPresentation4.hashCode());
    //it will shows that both have different hash, hence different objects

3. ไม่ออบเจ็กต์จะถูกสร้างขึ้นเมื่อคุณ@Injectเข้าสู่กิจกรรมเท่านั้นแทนที่จะเป็นแอพเริ่มต้น


1
ขอบคุณสำหรับความคิดเห็นสิ่งที่คุณพูดไม่ผิด แต่ฉันคิดว่ามันไม่ใช่คำตอบที่ดีที่สุดโปรดดูโพสต์แก้ไขของฉัน จึงไม่สามารถทำเครื่องหมายว่ายอมรับได้
Mr Mike

@EpicPandaForce: เอ๊ะ แต่คุณต้องสร้างอินสแตนซ์ที่ไหนสักแห่ง บางสิ่งบางอย่างจะต้องละเมิดหลักการผกผันการพึ่งพา
David Liu
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.