¿Cómo evitar la adición de método de inyección para cada vista?
Actualmente, para obtener instancia de, por ejemplo, Picasso en una actividad, tengo que añadir el método de inyección a AppComponent. Cómo evitar la adición del método de inyección, porque tengo un montón de fragmentos y puntos de vista donde se debe inyectar:
AppComponent.class:
- Cómo configurar OnClickListener (Android)
- Modo sin conexión Bluetooth en Android
- Encriptación y descifrado entre Android, PHP y node.js
- Descifrado AES en Android demasiado lento para ser utilizable. ¿NDK será más rápido? ¿Otras ideas?
- ¿Está Android N Stream API backported a versiones inferiores?
@ForApplication @Singleton @Component( modules = {AppModule.class,OkHttpClientModule.class,NetworkApiModule.class,NetworkAuthModule.class}) public interface AppComponent { void inject(Fragment1 obj); void inject(Fragment2 obj); void inject(Fragment3 obj); void inject(Fragment4 obj); void inject(Fragment5 obj); void inject(Fragment6 obj); ... }
Fragmento1.clase
public class Fragment1 extends Fragment { @Inject Picasso mPicasso; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); MyApplication.getComponent(getContext()).inject(this); } }
Mis clases :
AppModule.class:
@Module public class AppModule { private MyApplication mApplication; public AppModule(@NonNull MyApplication mApplication) { this.mApplication = mApplication; } @Provides @NonNull @Singleton public Application provideApplication() { return mApplication; } @Provides @ForApplication Context provideContext(){ return mApplication; } @Provides @Singleton Picasso providesPicasso(@ForApplication Context context) { return new Picasso.Builder(context).build(); } }
ForApplication.class:
@Scope @Retention(RUNTIME) public @interface ForApplication { }
MyApplication.class
public class MyApplicationextends Application { static Context mContext; private AppComponent component; @Override public void onCreate() { super.onCreate(); mContext = this; setupComponent(); } private void setupComponent() { component = DaggerAppComponent.builder().appModule(new AppModule(this)).build(); component.inject(this); } public AppComponent getComponent() { if (component==null) setupComponent(); return component; } public static AppComponent getComponent(Context context) { return ((MyApplication) context.getApplicationContext()).getComponent(); }
ACTUALIZAR
Quiero también inyectar adaptadores para fragmentos, y si voy a añadir inyectar a BaseFragment a continuación, BaseFragment tendrá todos los adaptadores para todos los fragmentos de niños
- Implementación correcta de PagerAdapter en Android
- Android: Errores de archivo IO
- Encuentra la IP del servidor en la red local con el puerto conocido en Java / Android
- Cómo NO cerrar el teclado cuando se pulsa DONE en el teclado
- Jfreechart: ¿Cómo excluir los días de fin de semana de la carta?
- "No se puede resolver el método 'openFileOutput (Java.lang.String, int)'"
- Java.lang.IllegalStateException: Ya conectado
- ActivityTwo.java no contó
Una solución sería utilizar la herencia para la inyección.
Simplemente defina un BaseFragment con una instancia de @Inject Picasso, cree un método de inyección en su DaggerComponent para este BaseFragment y llámelo en el método onCreate del BaseFragment. Los Fragmentos más específicos como Fragment1, 2 .. pueden heredar de este BaseFragment y usar la instancia de Picasso.
La solución es que puedes hacer la herencia ex: use extend Actividad o Fragmento e inyección en onCreate () en esa clase
A continuación se muestra el ejemplo de lo que hago:
Graph.java
@Singleton @Component(modules = { AppModule.class, }) public interface Graph { void inject(BaseActivity activity); void inject(BaseFragment fragment); }
BaseActivity.java
public class BaseActivity extends AppCompatActivity { protected List<Subscription> mSubscriptions; @Inject protected SharedDB dm; @Inject protected RestApi restApi; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getGraph().inject(this); } public Graph getGraph() { return MyApplication.graph(this); } //... }
BaseFragment.java
public class BaseFragment extends Fragment { protected List<Subscription> mSubscriptions; protected Unbinder unbinder; @Inject protected SharedDB dm; @Inject protected RestApi restApi; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); getGraph().inject(this); } public Graph getGraph() { return MyApplication.graph(getActivity()); } //.... }
MyApplication.java
public class MyApplication extends Application { private Graph mGraph; @Override public void onCreate() { super.onCreate(); setGraph(DaggerGraph.builder() .appModule(new AppModule(this)) .build()); } public Graph getGraph() { return mGraph; } public void setGraph(Graph graph) { mGraph = graph; } public static Graph graph(Context context) { DominoApp app = (DominoApp) context.getApplicationContext(); return app.getGraph(); } //.... }
¿Qué pasa con esto?
public final class MySimpleDelegate { @Inject protected Picasso picasso; @Inject protected Lazy<AdapterOne> lazyAdapterOne; @Inject protected Provider<AdapterTwo> providerAdapterTwo; public MySimpleDelegate(Context context) { MyApplication.getComponent(context).inject(this); } @NonNull public void getPicasso() { return picasso; } @NonNull AdapterOne getAdapterOne() { // the object is injected when the following method is called return lazyAdapterOne.get(); } @NonNull AdapterTwo getAdapterTwo() { // a new instance is created every time this methos is called return providerAdapterTwo.get(); } } public class Fragment1 extends Fragment { private MySimpleDelegate delegate; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); delegate = new MySimpleDelegate(getContext()); Picasso picasso = delegate.getPicasso(); AdapterOne one = delegate.getAdapterOne(); AdapterTwo two = delegate.getAdapterTwo(); } }
Por cierto, si el único problema es Picasso, también proporciona un método 'setSingletonInstance'. Ver este enlace
EDITAR
Creo que puedes llegar a lo que quieres usando el proveedor de dagas o las fábricas perezosas. Vea el ejemplo anterior.
Lo resolví agregando clase de delegado con la biblioteca lombok
@Accessors(prefix = "m") public class AdapterDelegate { @Getter @Inject Lazy<FlatAdapter> mFlatAdapterLazy; public AdapterDelegate(){ MyApplication.getComponent(MyApplication.getContext()).inject(this); } public static AdapterDelegate get() { return new AdapterDelegate(); } }
Y en una actividad
public class MainActivity extends Activity { FlatAdapter mFlatAdapter = AdapterDelegate.get().getFlatAdapterLazy().get();
No se puede evitar la adición de método de inyección para cada clase de destino de forma plana, pero se puede evitar llamar a ese método de inyección en cada clase mediante la reflexión. Con esta solución puede llamar a método de inyección sólo en la clase padre y luego ComponentReflectionInjector
proporcionaría dependencias para cada clase secundaria en cadena de herencia.
Cómo sería:
Component { void inject(Child b); } //Activity, fragment - no matter class Parent { ComponentReflectionInjector componentReflectionInjector; void onCreate() { componentReflectionInjector = new ComponentReflectionInjector(Component.class, /* component instance*/); componentReflectionInjector.inject(this); } } //your fragment with Picasso class Child extends Parent { @Inject MyDependency dependency; }
Y entonces las dependencias estarían disponibles en el método onCreate
de Child
clase Child
.
Esa solución muy discutible valdría por conveniencia perder algún rendimiento y valdría la pena algunos posibles problemas con ProGuard
después de la ofuscación, y dagger2 han sido diseñados para no usar la reflexión en todos los marcos DI, pero aún así.
- No se puede resolver el símbolo: FusedLocationProviderClient. Versión de Google Play Services utilizada 11.0.1
- Cómo activar el receptor de difusión de la notificación