2017-07-10 15 views
6

Tôi đang làm việc trên thư viện Android về cơ bản là một khách hàng cho một số dịch vụ REST mà tôi đã viết. Tôi có một số lớp lưu trữ, hàng đợi mạng, trình phân tích cú pháp, v.v. và giống như nhiều lớp như vậy, chúng có phụ thuộc vào Context hoặc trên những thứ như SharedPreferences được tạo từ Context. Tất cả các đối tượng này đều ẩn sau lớp mặt tiền, vì vậy người tiêu dùng thư viện của tôi không nhìn thấy chúng hoặc tương tác trực tiếp với họ.Tôi làm cách nào để xây dựng thư viện Android dựa trên Dagger mà không buộc phải sử dụng ứng dụng để sử dụng Dagger?

Vì sự tỉnh táo của riêng tôi, tôi muốn sử dụng Dagger 2 để tiêm phụ thuộc để quản lý các phiên bản của các lớp này INTERNALLY trong thư viện của tôi. Tuy nhiên, tôi không muốn ép buộc các ứng dụng sử dụng thư viện của mình để sử dụng Dagger; chỉ vì tôi đã chọn sử dụng Dagger không có nghĩa là người dùng của tôi phải có.

Tất cả các hướng dẫn tôi đã thấy dường như mong đợi rằng tôi đang xây dựng một ứng dụng, không chỉ là một thư viện. Nhiều hướng dẫn này cho tôi biết tôi nên tạo lớp Application được kế thừa từ DaggerApplication. Tuy nhiên, trong trường hợp của tôi, tôi không có Application (hoặc bất kỳ lớp nào Activity hoặc Service`) trong thư viện của mình, và tôi không muốn người dùng của mình phải sử dụng các lớp cơ sở của Dagger.

Vậy làm cách nào tôi có thể sử dụng Dagger mà không bị "rò rỉ" nó khỏi thư viện của mình? Tôi đã tìm thấy một câu trả lời một phần here, nhưng tôi không chắc chắn cách điều chỉnh mẫu "trình bao bọc" của tác giả để xử lý sự phụ thuộc của tôi trên Context. Tôi có thể chuyển một ngữ cảnh vào phương thức getComponent() của trình bao bọc hay Dagger có thể lấy một tham chiếu Ngữ cảnh theo một cách khác không?

Trả lời

4

Thư viện là gần như như một Ứng dụng (khi nói đến Dagger). Có, bạn không có đối tượng application nhưng bạn không thực sự cần một đối tượng.

người tiêu dùng Thư viện của bạn, tôi hy vọng nó sẽ đơn giản để sử dụng, vì vậy tôi không muốn biết con trỏ nào là gì cả (hoặc nếu bạn sử dụng nội bộ).

Cho phép người dùng của bạn vượt qua số Context khi họ gọi thư viện của bạn lần đầu tiên (ví dụ). Có một số DaggerInjector (Tôi nghĩ mẫu của bạn gọi nó là trình bao bọc) có tham chiếu tĩnh đến giao diện Component của bạn.

Ví dụ (và như vậy, chỉ là một ví dụ generic):

public class DaggerInjector { 

    private static YourComponent component; 

    private DaggerInjector() { 
     super(); 
    } 

    public static YourComponent getComponent() { 
     return component; 
    } 

    public static YourComponent buildComponent(Context context) { 
     component = DaggerYourComponent 
       .builder() 
       .yourModule(new YourModule(context)) 
       .build(); 
     return component; 
    } 
} 

“module” của bạn có thể trông giống như:

@Module 
public class YourModule { 

    private Context context; 

    public YourModule(Context context) { 
     this.context = context; 
    } 

    @Provides 
    @Singleton 
    final Context providesContext() { 
     return context; 
    } 
} 

Để sử dụng nó:

người dùng của bạn gọi một phương pháp (hoặc bạn tự gọi nó là lần đầu tiên nếu thành phần đó là null):

DaggerInjector.buildComponent(context); 

Điều này sẽ đảm bảo thành phần Dagger được khởi tạo và mã được tạo. Hiểu rằng gọi buildComponent là một công việc tốn kém (Dagger phải làm rất nhiều!) Vì vậy chỉ làm điều đó một lần (trừ khi bạn cần phải khởi tạo lại thư viện với các giá trị khác nhau chỉ được biết trong thời gian chạy).

Một số thư viện chỉ yêu cầu một ngữ cảnh trong mọi cuộc gọi, vì vậy điều đó không nằm ngoài câu hỏi; bạn có thể, sau đó, khởi tạo dao găm lần đầu tiên bạn được gọi (bằng cách kiểm tra nếu getComponent() là null trong bộ phun).

Sau khi bạn DaggerInjector.getComponent() không phải là null nữa, bây giờ bạn có thể thêm @Inject và những thứ "tiêm" thích hợp ...

ví dụ: trong YourModule bạn có thể có:

@Provides 
SomeObject providesSomeObject() { 
    return new SomeObject(); 
} 

// THIS “Context” here is automatically injected by Dagger thanks to the above. 
@Provides 
@Singleton 
SomeOtherObject providesSomeOtherObject(Context context) { 
    return new SomeOtherObject(context); //assume this one needs it 
} 

và trong bất kỳ "tiêm" đối tượng (nghĩa là một đối tượng có phương thức inject trong thành phần của bạn…) bạn có thể làm:

public class AnObjectThatWantsToInjectStuff { 

    @Inject 
    SomeObject someObject; 
    @Inject 
    SomeOtherObject someOtherObject; 

    public AnObjectThatWantsToInjectStuff() { 
      super(); 
      DaggerComponent.getComponent().inject(this); 

      // you can now use someObject and someOtherObject 
    } 
} 

Đối với ở trên để làm việc, bạn cần trong YourComponent (mà là một Interface) mã như thế này:

void inject(AnObjectThatWantsToInjectStuff object);

(nếu không thì gọi DaggerComponent.getComponent().inject(this) sẽ thất bại tại thời gian biên dịch)

Thông báo tôi không bao giờ trôi qua một bối cảnh đến YourInjectableContext, Dagger đã biết cách lấy nó.

Hãy cẩn thận với rò rỉ tho. Tôi khuyên bạn nên lưu trữ context.getApplicationContext() thay vì chỉ đơn thuần là Context cho tất cả/hầu hết các trường hợp (trừ khi bạn cần một ngữ cảnh Hoạt động để tăng bố cục/chủ đề, ngữ cảnh ứng dụng được cung cấp bởi ứng dụng tiêu thụ là tất cả những gì bạn cần).

+1

Cảm ơn bạn rất nhiều vì câu trả lời này! Tôi đã theo dõi các đề xuất của bạn và mọi thứ đang hoạt động tốt. – Dalbergia

+0

Ứng dụng có hoạt động không? Tiếp theo quá trình tương tự nhưng không hoạt động. Tôi nhận được "không thể tìm thấy biểu tượng lớp DaggerYourComponent" lỗi trong khi xây dựng các ứng dụng. @ Dalbergia, Có phải nó hoạt động mà không có thành phần giao diện người dùng của Android không? –

+1

Nó làm việc cho tôi và rõ ràng OP cũng làm cho nó hoạt động. @TejasMehta thử làm sạch/xây dựng lại hoặc một cái gì đó. Lỗi của bạn có nghĩa là thành phần của bạn không được tạo đúng cách hoặc bạn không sử dụng đúng tên. –

Các vấn đề liên quan