webentwicklung-frage-antwort-db.com.de

Wie beantrage ich eine Injektion in Android Fragments and Services?

Ich folge diesem Tutorial , um Dagger 2 meinem Android-Projekt hinzuzufügen.

Nach dem Einrichten und Erstellen der Module und Komponenten kann ich die Abhängigkeiten in einer Aktivität wie folgt hinzufügen:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_account);
    ButterKnife.bind(this);
    ((AppController) getApplication()).getNetComponent().inject(this);
}

Ich habe Probleme damit, wie man Abhängigkeiten in ein Fragment und einen IntentService einfügt.

public class FragmentBrandList extends ListFragment {
}

In welcher Klasse soll ich die @Override-Methode anfordern und wie lautet der Code dafür?

9
Devesh Agrawal

In dieser Klasse, welche @Override-Methode ich verwenden soll, und was wird der Code sein, um die Abhängigkeit in Fragment hinzuzufügen?

Die korrekte Stelle zum Aufrufen der Injektion in einem Fragment ist onAttach(Context context). Dies ist im Abschnitt wo zu injizieren des Dagger 2-Benutzerhandbuchs hier angegeben.

@Override
public void onAttach(Context context) {
    ((AppController) context.getApplicationContext()).getNetComponent().inject(this);
    super.onAttach(context);
}

Der richtige Ort, um die Injektion innerhalb eines Dienstes aufzurufen, ist onCreate()

@Override 
public void onCreate() {
    ((AppController) getApplication()).getNetComponent().inject(this);
    super.onCreate();

}

Beachten Sie, dass in beiden Fällen die Aufforderung zur Injektion vor dem Aufruf von super.onCreate() erfolgt. Das Dagger-Benutzerhandbuch erklärt es so:

Es ist wichtig, AndroidInjection.inject () vor super.onCreate () in einer Activity aufzurufen, da der Aufruf von Super Fragmente aus der vorherigen Aktivitätsinstanz während der Konfigurationsänderung anfügt, wodurch die Fragmente eingefügt werden. Damit die Fragmentinjektion erfolgreich ist, muss die Aktivität bereits injiziert werden. Für Benutzer von ErrorProne ist es ein Compiler-Fehler, AndroidInjection.inject () nach super.onCreate () aufzurufen.

Mit anderen Worten:

  1. Mit dem Activity super.onCreate()-Aufruf werden Fragmente aus einer vorherigen Instanz erneut angefügt 
  2. Dieser super-Aufruf bewirkt, dass Fragmente erneut injiziert werden (da Fragmente in onAttach injiziert werden).
  3. Fragmente sollten injiziert werden, nachdem ihre Aktivität injiziert wurde. Fordern Sie daher die Injektion in Ihrer Aktivität an, bevor Sie super.onCreate() aufrufen.

Sie können immer überprüfen, wo Sie injizieren sollen, indem Sie den entsprechenden Quellcode für die com.google.dagger:dagger-Android-Klassen wie DaggerFragment und DaggerService betrachten. Siehe das GitHub-Repo hier

Stellen Sie für Ihr spezielles Beispiel sicher, dass Sie die neuen Injektionsstellen zur NetComponent hinzugefügt haben:

void inject(FragmentBrandList frag);

void inject(BrandListService service);
13
David Rawson

Schritt 1: Erstellen Sie Ihr ApplicationModule

@Module
public class ApplicationModule {

    private final DIApplication application;

    public ApplicationModule(DIApplication application) {
        this.application = application;
    }

    @Provides @Singleton
    public DIApplication provideApplication() {
        return application;
    }

    @Provides @Singleton
    public DogModel provideDogModel() {
        return new DogModelImpl("Scooby-doo");
    }

}

Schritt 2: Erstellen Sie Ihre ApplicationComponent:

@Singleton
@Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
    void inject(DIApplication application);

    void inject(BaseActivity activity);
    void inject(BaseFragment fragment);

    void inject(DogSyncService service);
}

Schritt 3: Erstellen Sie eine DI-Klasse:

public class DependencyInjector {

    private static ApplicationComponent applicationComponent;

    public static void initialize(DIApplication diApplication) {
        applicationComponent = DaggerApplicationComponent.builder()
                .applicationModule(new ApplicationModule(diApplication))
                .build();
    }

    public static ApplicationComponent applicationComponent() {
        return applicationComponent;
    }

    private DependencyInjector(){}
}

Letzter Schritt: Injizieren Sie überall mit:

DependencyInjector.applicationComponent()

Ihre Frage hat mich dazu inspiriert, ein Demoprojekt zu erstellen, das Aktivität, Fragment und Service mit Dagger2 zeigt. Hier ist der Git: https://github.com/write2sv/AndroidDIDagger2/tree/master/app/src/main/Java/work/shaggy/didemo

7
write2sv

Ich habe es gemacht mit ((AppController) getActivity().getApplication()).getNetComponent().inject(this);

in der Fragment.onCreate()-Methode.

1
Rumid
((MyApp) context.getApplicationContext()).getApplicationComponent().inject(MyFragment.this);

Ich habe dies in der onAttach(Context context)-Methode des Fragments hinzugefügt.

0
Adi

Sie können den Autadogger verwenden, um zu vermeiden, dass die gesamte Boilerplate geschrieben werden muss. Ich verwende diese Architektur sehr oft:

build.gradle

apt 'com.github.lukaspili.autodagger2:autodagger2-compiler:1.1'
compile 'com.github.lukaspili.autodagger2:autodagger2:1.1'

YourApp.Java

@AutoComponent( modules = YourApp.YourAppModule.class )
public class YourApp extends Application {

    private static YourApp instance;
    private YourAppComponent component;

    public YourAppComponent getComponent() {
        return this.component;
    }

    @Override
    public void onCreate() {
        super.onCreate();

        setupComponent();
    }

    private void setupComponent() {
        component = DaggerYourAppComponent.builder()
                .yourAppModule(new YourAppModule(instance))
                .build();
    }


    @dagger.Module
    public static class YourAppModule {
        private YourApp app;

        YourAppModule(YourAppApp application) {
            this.app = application;
        }

        @Provides @AutoExpose(YourApp.class)
        Application provideApplication() {
            return app;
        }

        @Provides @AutoExpose(PoswalaApp.class)
        Context provideContext() {
            return app;
        }

        @Provides @AutoExpose(YourApp.class)
        Retrofit provideApiAdapter() {
            return ApiService.getServiceInstance();
        }
    }
}

YourActivity.Java

@AutoComponent(
    dependencies = YourApp.class,
    modules = YourActivity.YourActivityModule.class
)

public class YourActivity extends BaseActivity implements YourActivityView {

    private YourActivityComponent component;
    @Inject MyPresenter presenter

    // This is an abstract method from BaseActivity
    @Override
    protected void setupComponent(YourAppComponent appComponent) {
        component = DaggerYourActivityComponent.builder()
                .yourAppComponent(((YourApp) getApplication()).getComponent())
                .yourActivityModule(new YourctivityModule(this))
                .build();
    }

    @Override
    protected MyPresenter getPresenter() {
        return presenter;
    }


    @dagger.Module
    public static class YourActivityModule {

        private YourActivityView view;

        YourActivityModule(YourActivityView view) {
            this.view = view;
        }


        @Provides @AutoExpose(YourActivity.class)
        YourActivityView provideView() {
            return view;
        }

        // Your other dependencies
    }
}

Kurze Erklärung:

Das Modul Ihrer App muss eine "universelle" Abhängigkeit haben. Auf diese Weise können Sie jedoch mehrere Module für eine Klasse verwenden. Sie müssen nur das anpassen 

@AutoComponent(
    dependencies = YourApp.class,
    modules = { YourActivity.YourActivityModule.class, YourFragment.YourFragmentModule.class }
)

block. Sie können mit dieser Syntax beliebig viele Module hinzufügen.

Hoffe das hilft dir

0
Chisko

Sie müssen nur die Injektormethode für alles einschließen, was Sie injizieren möchten. 

@Singleton
@Component
public interface AppComponent {
    void inject(MainActivity activity);
    void inject(FragmentBrandList fragmentBrandList);
} 
0
EpicPandaForce