Trước tiên, bạn nên suy nghĩ qua Vasily's answer.
Nhưng hãy suy nghĩ một chút về cách chúng tôi đã thực hiện điều này trước Dagger Android? Chúng tôi đã xây dựng một thành phần con từ thành phần được lấy từ lớp Application
. Sau đó, chúng tôi có thể sử dụng tiểu hợp phần này để chèn các trường, ví dụ như chế độ xem tùy chỉnh.
Vì vậy, chúng tôi sẽ cố gắng thực hiện chính xác điều tương tự ngay bây giờ.
Giả sử, mục tiêu của chúng tôi là để tiêm MyAdapter
lớp thành một MyButton
:
public class MyButton extends AppCompatButton {
@Inject MyAdapter adapter;
public MyButton(Context context) {
super(context);
...
}
}
Và chúng ta hãy làm adapter có một sự phụ thuộc vào các hoạt động Context
, không ứng dụng Context
:
public class MyAdapter {
@Inject
public MyAdapter(@Named("activity") Context context) {
}
}
Hãy bắt đầu từ lớp tùy chỉnh Application
.
MyApplication.java
public class MyApplication extends DaggerApplication {
@Inject
DispatchingAndroidInjector<Activity> dispatchingActivityInjector;
public static MySubcomponent mySubcomponent;
@Override
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
return DaggerAppComponent.builder()
.create(this);
}
}
AppComponent.java:
@Component(modules = {AndroidSupportInjectionModule.class, ActivityBindingModule.class, AppModule.class})
@Singleton
public interface AppComponent extends AndroidInjector<MyApplication> {
@Component.Builder
abstract class Builder extends AndroidInjector.Builder<MyApplication> {
}
}
AppModule.java
@Module
abstract class AppModule {
@Binds
@Singleton
@Named("app")
abstract Context providesContext(Application application);
}
ActivityBindingModule.java
@Module(subcomponents = MySubcomponent.class)
public abstract class ActivityBindingModule {
@Binds
@IntoMap
@ActivityKey(MainActivity.class)
abstract AndroidInjector.Factory<? extends Activity>
bindMainActivityInjectorFactory(MySubcomponent.Builder builder);
}
AndroidSupportInjectionModule.java
được vận chuyển với chính nó dao găm. Nếu bạn không sử dụng các lớp học từ gói hỗ trợ (ví dụ: android.app.Fragment
thay vì android.support.v4.app.Fragment
), thì hãy sử dụng AndroidInjectionModule.java
.
MySubcomponent.java
@ActivityScope
@Subcomponent(modules = {SubcomponentModule.class/*, other modules here, if needed */})
public interface MySubcomponent extends AndroidInjector<MainActivity> {
void inject(MyButton button);
@Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<MainActivity> {
public abstract MySubcomponent build();
}
}
SubcomponentModule.java
@Module
abstract class SubcomponentModule {
@Binds
@ActivityScope
@Named("activity")
abstract Context toContext(MainActivity activity);
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Inject
MySubcomponent subcomponent;
@Override
protected void onCreate(Bundle savedInstanceState) {
// Will inject `subcomponent` field
AndroidInjection.inject(this);
// Saving this component in a static field
// Hereafter you are taking responsibility of mySubcomponent lifetime
MyApplication.mySubcomponent = subcomponent;
super.onCreate(savedInstanceState);
setContentView(new MyButton(this));
}
}
Có tất cả trong số này, hiện nay đây là cách MyButton
sẽ trông giống như:
public class MyButton extends AppCompatButton {
@Inject MyAdapter adapter;
public MyButton(Context context) {
super(context);
MyApplication.mySubcomponent.inject(this);
}
}
Tôi thừa nhận rằng điều này có vẻ hacky và chắc chắn không phải là một cách tiếp cận để dính vào. Tôi rất vui khi thấy một cách tiếp cận tốt hơn.
Bạn rất có thể cần phải sao chép cơ chế dựa trên nguồn AndroidInjector cho cả hộp thoại và chế độ xem. – EpicPandaForce
Không phải nếu đánh bại toàn bộ mục đích nếu tôi phải viết một 'AndroidInjector' tùy chỉnh cho những loại này. Tôi đã hy vọng cập nhật ứng dụng của mình để đơn giản hóa cách mọi thứ được tiêm. –
Tôi không sử dụng nó: D – EpicPandaForce