2016-09-12 11 views
7

Obecnie, aby uzyskać przykład na przykład Picasso w działaniu, muszę dodać metodę wstrzykiwania do AppComponent. Jak uniknąć dodawania metodą wstrzyknięć, bo mam sporo fragmentów i poglądów, gdzie powinien być wstrzykiwana:Jak uniknąć dodawania metody wstrzykiwania dla każdego widoku?

AppComponent.class:

@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); 
    ... 
    } 

Fragment1.class

public class Fragment1 extends Fragment { 
    @Inject Picasso mPicasso; 
    @Override 
    public void onCreate(@Nullable Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     MyApplication.getComponent(getContext()).inject(this); 
    } 
} 

My klasy:

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(); 
    } 

UPDATE

Chcę również wstrzykiwać adaptery do fragmentów, a jeśli dodam wstrzyknąć do BaseFragment następnie BaseFragment będą mieć wszystkie przejściówki dla wszystkich fragmentów potomnych

Odpowiedz

0

postanowiłem go dodając Delegate class z lombok library

@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(); 
    } 
} 

I w działaniu

public class MainActivity extends Activity { 
    FlatAdapter mFlatAdapter = AdapterDelegate.get().getFlatAdapterLazy().get(); 
2

Jednym rozwiązaniem byłoby wykorzystanie dziedziczenia do wstrzyknięcia.

Po prostu zdefiniuj BaseFragment za pomocą instancji @Inject Picasso, utwórz metodę wtrysku w swoim DaggerComponent dla tej BaseFragment i wywołaj ją w metodzie onCreate BaseFragment. Bardziej szczegółowe Fragmenty, takie jak Fragment1, 2 .. mogą dziedziczyć z tej BaseFragment i używać instancji Picasso.

+0

chcę wstrzykiwać adaptery do fragmentów, a jeśli dodam wstrzyknąć do BaseFragment następnie BaseFragment będą miały wszystkie adaptery dla wszystkich fragmentów potomnych – NickUnuchek

+0

Czy te adaptery są dostępne w tym samym komponencie, co operator picasso? Czym różnią się te adaptery od siebie? – Jacob

+0

Myślę, że @Jacob przynosi dobrą odpowiedź na stole, ale jeśli musisz wstrzyknąć innych członków, nie masz wyboru, aby zrobić to osobno dla wszystkich! –

1

Co z tym?

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(); 
    } 
} 

Nawiasem mówiąc, jeśli jedynym problemem jest Picasso, zapewnia również metodę "setSingletonInstance". Zobacz this link

EDIT

wierzę, że można osiągnąć to, czego chcą przy użyciu dostawcy sztyletu lub Lazy fabryk. Zobacz przykład powyżej.

+0

to rozwiązanie łamie elastyczność sztyletu. Więc jeśli TS chciał dodać kolejną zależność do swojego fragmentu, utworzyłby innego delegata lub w końcu stworzył metodę iniekcyjną dla tego fragmentu. – Beloo

+0

Naprawdę nie rozumiem twojego komentarza, czym jest "elastyczność sztyletu"? Sztylet jest ogólną biblioteką wtrysku i nie jest konieczne, aby działała wewnątrz fragmentu lub działań (to jest jego elastyczność). To rozwiązanie polega po prostu na przeniesieniu zastrzyku na inną klasę, aby uniknąć dodawania każdego widoku/fragmentu/działania do komponentu (o to prosił autor). –

+0

Załóżmy, że fragment docelowy ma ponad 20 zależności. Jak więc można rozwiązać to przy takim podejściu? Czy dostarczyłbyś ponad 20 delegatów? Co więcej, nie jest rozsądnie używać tego, jeśli nasz fragment miał tylko zależność od picassa, ponieważ nie będzie on gotowy do wzrostu/skalowania. – Beloo

1

Rozwiązanie to można wykonać dziedziczenia Ex: użycie rozszerzyć działalność lub fragmentem i zrobić zastrzyk w onCreate() w tych klasie

Poniżej jest przykład co zrobić:

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(); 
    } 

    //.... 
} 
-1

Nie można uniknąć dodawania metody wstrzykiwania dla każdej płaskiej metody docelowej, ale można uniknąć wywoływania tej metody iniekcji w każdej klasie za pomocą odbicia. Z this solution możesz wywołać metodę inject tylko w klasie nadrzędnej, a następnie ComponentReflectionInjector zapewni zależności dla każdej klasy potomnej w łańcuchu dziedziczenia.

Jak to będzie wyglądać:

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; 
} 

a następnie Zależności będzie już dostępny w onCreate metody Child klasie.

To jest bardzo ważne, że warto stracić trochę wydajności i czy warto mieć pewne problemy z ProGuard po zaciemnieniu, a dagger2 został zaprojektowany tak, aby w ogóle nie używać odbicia w frameworkach DI, ale nadal.

Powiązane problemy