Dagger 2 thành phần con so với phụ thuộc thành phần


135

plus()Phương pháp của Dagger 1 là thứ tôi đã sử dụng khá thường xuyên trong các ứng dụng trước đây, vì vậy tôi hiểu các tình huống mà bạn có thể muốn có một thành phần con với toàn quyền truy cập vào các ràng buộc biểu đồ cha.

Trong tình huống nào sẽ có lợi khi sử dụng một phụ thuộc thành phần thay vì phụ thuộc thành phần phụ và tại sao?

Câu trả lời:


228

Phụ thuộc thành phần - Sử dụng phần này khi bạn muốn giữ hai thành phần độc lập.

Các thành phần con - Sử dụng phần này khi bạn muốn giữ hai thành phần được ghép nối.


Tôi sẽ sử dụng dưới đây ví dụ để giải thích phần phụ thuộcthành phần phụ . Một số điểm đáng chú ý về ví dụ này là:

  • SomeClassA1có thể được tạo ra mà không có bất kỳ sự phụ thuộc. ModuleAcung cấp và ví dụ SomeClassA1thông qua provideSomeClassA1()phương thức.
  • SomeClassB1không thể được tạo ra mà không có SomeClassA1. ModuleBcó thể cung cấp một thể hiện SomeClassB1chỉ khi một thể hiện của SomeClassA1được truyền dưới dạng đối số cho provideSomeClassB1()phương thức.
@Module
public class ModuleA {
    @Provides
    public SomeClassA1 provideSomeClassA1() {
        return new SomeClassA1();
    }
}

@Module
public class ModuleB {
    @Provides
    public SomeClassB1 provideSomeClassB1(SomeClassA1 someClassA1) {
        return new SomeClassB1(someClassA1);
    }
}

public class SomeClassA1 {
    public SomeClassA1() {}
}

public class SomeClassB1 {
    private SomeClassA1 someClassA1;

    public SomeClassB1(SomeClassA1 someClassA1) {
        this.someClassA1 = someClassA1;
    }
}

Dagger sẽ đảm nhiệm việc chuyển thể hiện của SomeClassA1một đối số thành provideSomeClassB1()phương thức ModuleBbất cứ khi nào khai báo Thành phần / Thành phần con ModuleBđược khởi tạo. Chúng ta cần hướng dẫn Dagger cách thực hiện sự phụ thuộc. Điều này có thể được thực hiện bằng cách sử dụng phần phụ thuộc hoặc Tiểu hợp phần .

Thành phần phụ thuộc

Lưu ý các điểm sau trong ví dụ phụ thuộc Thành phần bên dưới:

  • ComponentBphải xác định sự phụ thuộc thông qua dependenciesphương thức @Componentchú thích.
  • ComponentAkhông cần phải khai báo ModuleB. Điều này giữ cho hai thành phần độc lập.
public class ComponentDependency {
    @Component(modules = ModuleA.class)
    public interface ComponentA {
        SomeClassA1 someClassA1();
    }

    @Component(modules = ModuleB.class, dependencies = ComponentA.class)
    public interface ComponentB {
        SomeClassB1 someClassB1();
    }

    public static void main(String[] args) {
        ModuleA moduleA = new ModuleA();
        ComponentA componentA = DaggerComponentDependency_ComponentA.builder()
                .moduleA(moduleA)
                .build();

        ModuleB moduleB = new ModuleB();
        ComponentB componentB = DaggerComponentDependency_ComponentB.builder()
                .moduleB(moduleB)
                .componentA(componentA)
                .build();
    }
}

Hợp chất phụ

Lưu ý các điểm sau trong ví dụ SubComponent:

  • Như ComponentBchưa xác định sự phụ thuộc vào ModuleA, nó không thể sống độc lập. Nó trở nên phụ thuộc vào thành phần sẽ cung cấp ModuleA. Do đó nó có một @Subcomponentchú thích.
  • ComponentAđã khai báo ModuleBthông qua phương thức giao diện componentB(). Điều này làm cho hai thành phần được ghép nối. Trong thực tế, ComponentBchỉ có thể được khởi tạo thông qua ComponentA.
public class SubComponent {
    @Component(modules = ModuleA.class)
    public interface ComponentA {
        ComponentB componentB(ModuleB moduleB);
    }

    @Subcomponent(modules = ModuleB.class)
    public interface ComponentB {
        SomeClassB1 someClassB1();
    }

    public static void main(String[] args) {
        ModuleA moduleA = new ModuleA();
        ComponentA componentA = DaggerSubComponent_ComponentA.builder()
                .moduleA(moduleA)
                .build();

        ModuleB moduleB = new ModuleB();
        ComponentB componentB = componentA.componentB(moduleB);
    }
}

4
Tôi có một thiết lập thành phần con không thêm Mô-đun B vào Thành phần, điều đó có nghĩa là trình xây dựng thành phần không cần mô-đunB. Điều này dường như hoạt động theo cách tôi mong đợi cho phép tạo ra ElementA khi bắt đầu ứng dụng và sau đó bắt đầu m
FriendlyMikhail

2
@MikeN - Bạn có thể nêu bật cách bạn có thể thoát khỏi ModuleB trên ElementA không? Tôi chỉ có thể thoát khỏi ModuleB trên ElementA nếu tôi cung cấp các phạm vi khác nhau trên ElementA và ElementB.
Praveer Gupta

1
Bạn đúng thiết lập của tôi hoạt động vì chúng ở các phạm vi khác nhau. xin lỗi
FriendlyMikhail

2
" SomeClassB1phụ thuộc vào SomeClassA1. ComponentAphải xác định rõ ràng sự phụ thuộc." ==> bạn có nghĩa là " ComponentBphải xác định rõ ràng sự phụ thuộc"?
Tar

1
Tương tự như những gì @Tar đã chỉ, tôi hiểu rằng trong " SomeClassB1phụ thuộc vào SomeClassA1. ComponentAKhông cần xác định rõ ràng sự phụ thuộc." bạn có nghĩa là " ComponentBkhông cần xác định rõ ràng sự phụ thuộc."
Sabas LG

45

Theo tài liệu :

Component Dependencycung cấp cho bạn quyền truy cập chỉ các ràng buộc được hiển thị dưới dạng phương thức cung cấp thông qua các phụ thuộc thành phần, tức là bạn chỉ có quyền truy cập vào các loại được khai báo trong ngoặc đơn Component.

SubComponentcung cấp cho bạn quyền truy cập vào toàn bộ biểu đồ liên kết từ cha mẹ của nó khi nó được khai báo, tức là bạn có quyền truy cập vào tất cả các đối tượng được khai báo trong Modules của nó .

Hãy nói rằng, bạn có một ApplicationComponentchứa tất cả Androidnhững thứ liên quan ( LocationService, Resources, SharedPreference, vv). Bạn cũng muốn có DataComponentnơi bạn quản lý mọi thứ cho sự kiên trì cùng với WebServiceđể đối phó với các API. Điều duy nhất bạn thiếu DataComponentApplication Contextnơi cư trú ApplicationComponent. Cách đơn giản nhất để có được một Contexttừ DataComponentsẽ là một phụ thuộc vào ApplicationComponent. Bạn cần chắc chắn rằng bạn đã Contextkhai báo rõ ràng ApplicationComponentvì bạn chỉ có quyền truy cập vào nội dung được khai báo. Trong trường hợp này, không có công việc thủ công, có nghĩa là bạn không cần chỉ định Submodulestrong cha mẹ Componentvà thêm rõ ràng mô hình con của bạn vào mô đun cha mẹ như:

MySubcomponent mySubcomponent = myComponent.plus(new ChildGraphModule("child!")); // No need!

Bây giờ xem xét rằng trường hợp bạn muốn tiêm WebServicetừ DataComponentLocationServicetừ ApplicationComponentthành của bạn Fragmentmà liên kết bằng cách sử dụng @Submodule plustính năng trên. Điều thú vị ở đây là thành phần bạn liên kết với ( ApplicationComponent) không cần phải phơi bày WebServicecũng không phải LocationServicevì bạn có quyền truy cập vào toàn bộ biểu đồ ngay lập tức.


2
Nếu tôi hiểu chính xác, không có giao diện được gọi @Submodule. Có phải là một lỗi đánh máy?
Hồi giáo Salah

Tôi thích cách này sử dụng một ví dụ thực tế để thể hiện sự khác biệt. Tuy nhiên, điều này khó hiểu hơn việc đọc các tài liệu. Nó sẽ giúp có ít hơn classesnhư các ví dụ và nhiều hình ảnh để minh họa điểm chính xác.
sudocoder

17

Dưới đây là ví dụ mã với ảnh chụp màn hình để hiểu thêm về Thành phần và SubComponent:

Thành phần: nhập mô tả hình ảnh ở đây

  1. AppComponent chứa hai khai báo.
  2. AppComponent khởi tạo vào lớp App.
  3. HomeActivityComponent phụ thuộc vào AppComponent.
  4. Trong HomeActivity về khởi tạo DaggerHomeActivityComponent, tôi đưa đối tượng AppComponent làm thành phần.

Thành phần phụ:

nhập mô tả hình ảnh ở đây

  1. AppComponent chứa SubComponent hoặc SubComponents.
  2. AppComponent khởi tạo vào lớp App.
  3. SubComponent không biết về ParentComponent của mình. Điều đó chỉ cung cấp các phụ thuộc của riêng mình bằng cách bao gồm Mô-đun.
  4. Trong HomeActivity tôi đang tiêm SubComponent bằng cách sử dụng Thành phần gốc của nó.

Và sơ đồ hình ảnh: nhập mô tả hình ảnh ở đây

Nguồn: liên kết


Sơ đồ sẽ không có ý nghĩa hơn nếu thành phần phụ kèm theo AppComponent?
Florian Walther

1

Một điều khác mà tôi không nhận ra cho đến bây giờ là:

  • Một @Subcomponentcá thể có chính xác một thành phần cha mẹ (mặc dù các thành phần khác nhau có thể khởi tạo cùng một thành phần đó @Subcomponentvà là cha mẹ của cá thể đó)
  • A @Componentcó thể có 0, một hoặc nhiều thành phần "cha" được khai báo thông qua các phụ thuộc thành phần

1
Có lẽ trong trường hợp thứ hai, không đúng khi nói '@Component' có thể có ... cha mẹ. Thay vào đó '@Component' không có cha mẹ, nhưng người khác có thể phụ thuộc vào điều đó (đơn giản là sử dụng nó) thông qua các phụ thuộc thành phần.
demaksee

@demaksee Tôi không biết, dường như với tôi rằng nếu bạn vạch ra hệ thống phân cấp thành phần của mình, bạn sẽ nhận được tại DAG và tôi nghĩ đó là một cách tiêu chuẩn để coi mối quan hệ này là cha mẹ và con trong ngữ cảnh đồ thị. Nếu chúng ta đang nói về hoạt động bên trong của Dagger, thì tôi đoán đó có thể không phải là từ đúng.
iskolek
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.