2016-01-26 6 views
5

Ich versuche, mithilfe von Dagger Retrofit 2 und Android Priority Job Queue 2.Wie injiziere ich ein Objekt in die Android Priority Job Queue mit Dagger 2?

Es ist wahrscheinlich, ich verwende hier das falsche Muster zu integrieren (Ich bin neu in Java und Android), aber ich versuche, Zugriff auf eine von Dagger erstellte Retrofit-Instanz von einem Objekt, das serialisiert und dann vor der Ausführung deserialisiert wird (Android-Jobwarteschlange serialisiert Jobs, die auf Festplatte gespeichert werden). Die Retrofit-Instanz wird von einer Application Dagger-Komponente erstellt, da ich SharedPreferences in einer ihrer Abhängigkeiten verwende.

Ich kann Retrofit nicht an den Job übergeben, wenn er erstellt wird, da Retrofit selbst nicht serialisiert werden kann.

Die Anwendung kann auch nicht serialisiert werden, daher kann ich die Application Dagger-Komponente nicht vom Job referenzieren, wenn sie ausgeführt wird (da ich nicht mit ((MyApplication) myApplication).component().inject(this); injizieren kann), weil das Application-Objekt nicht existiert im deserialisierten Job.)

Ich möchte die Retrofit-Instanz verwenden, die von der restlichen App für Effizienz verwendet wird, anstatt eine andere Instanz nur für den Job zu erstellen. Ist es überhaupt möglich?

Ich bin mir nicht sicher, ob die Verwendung von Provider<T> oder einer Factory helfen könnte, weil das im Moment nicht mein Verständnis ist, aber ich würde einen Hinweis darauf lieben, wie man Dinge strukturiert, wenn das der Fall ist!

BEARBEITEN: So erstellen Sie einen Auftrag mit Android Priority Job Queue. Ich habe eine Probe modifiziert, um anzuzeigen, wie die Spritze funktionieren soll. Der Auftrag wird auf onAdded() serialisiert und deserialisiert, bevor es mit onRun() laufen gelassen:

// A job to send a tweet 
public class PostTweetJob extends Job { 

    @Inject MyService webservice; 
    public static final int PRIORITY = 1; 
    private String text; 

    public PostTweetJob(String text) { 
     // This job requires network connectivity, 
     // and should be persisted in case the application exits before job is completed. 
     super(new Params(PRIORITY).requireNetwork().persist()); 
    } 
    @Override 
    public void onAdded() { 
     // Job has been saved to disk. 
    } 
    @Override 
    public void onRun() throws Throwable { 
     // Job logic goes here 
     webservice.postTweet(text); 
    } 
    @Override 
    protected void onCancel() { 
     // Clean up 
    } 
} 
+0

Im Allgemeinen serialisieren Sie normalerweise einfache Klassen. Warum sollten sie überhaupt Zugriff auf die Retrofit-Instanz haben? Wird eine Manager/Presenter/Handler-Klasse hinzugefügt, die die Backend-Aufrufe ausführt und das Modell (Ihre serialisierte Klasse) keine Option enthält? –

+0

@DavidMedenjak Ich habe einen Beispielcode hinzugefügt, um zu zeigen, was mit der Android Priority Job Queue passiert. Ich muss meinen Dienst (oder Retrofit) von dem Job aufrufen, wenn er ausgeführt wird. – snafu109

+1

Die Readme-Datei der Bibliothek zeigt, dass DI durch Hinzufügen eines Injektors unterstützt wird, haben Sie das schon versucht? Das scheint der sauberste Weg zu sein. –

Antwort

6

Hier ist die einfachste Lösung, die ich verwalten könnte.

Erstellen Sie zunächst eine BaseJob Klasse. Dies wird die Injektion Ziel sein:

public abstract class BaseJob extends Job { 
    // annotate fields that should be injected and made available to subclasses 
    @Inject MyService service; 

    protected BaseJob(Params params) { 
     super(params); 
    } 
} 

Es erklärt hat abstract so gibt es keine Notwendigkeit, eine der abstrakten Methoden in der Job Klasse deklarierten außer Kraft zu setzen. Stattdessen werden Methoden in den Jobs außer Kraft gesetzt, die von BaseJob erben.

Erstellen Sie einen Job, der von BaseJob erbt. Irgendwelche injiziert Felder in BaseJob sind verfügbar für den Einsatz:

public class MyActualJob extends BaseJob { 
    public static final int PRIORITY = 1; 

    public MyActualJob() { 
     super(new Params(PRIORITY).requireNetwork().persist()); 
    } 

    @Override 
    public void onAdded() { 
     // job added to queue 
    } 

    @Override 
    public void onRun() throws Throwable { 
     // do the work 
     // service will be injected into BaseJob, so you can use it here 
     final Call<User> call = service.getUser(); 
     call.execute(); 
    } 

    @Override 
    protected void onCancel() { 
     // clean up 
    } 
} 

Schließlich, um sicherzustellen, Dinge verknüpft, fügen Sie ein DependencyInjector-JobManager, wenn es erstellt. Dies spritzt in die Arbeit des BaseJob:

DependencyInjector dependencyInjector = new DependencyInjector() { 
    @Override 
    public void inject(Job job) { 
     // this line depends on how your Dagger components are setup; 
     // the important part is to cast job to BaseJob 
     ((MyApplication) app).component().inject((BaseJob) job); 
    } 
}; 
Configuration configuration = new Configuration.Builder(getApplicationContext()) 
     .injector(dependencyInjector) 
     .build(); 
JobManager jobManager = new JobManager(getApplicationContext(), configuration); 

Warum nicht überspringen BaseJob mit und injizieren direkt in MyActualJob?Dies funktioniert, aber wenn es mehr Jobs, die Injektion Ziele sind, glaube ich würden Sie instanceof verwenden müssen zu prüfen, welche Art von Job erstellt und warf job auf die richtige Klasse wurde, als DependencyInjector erstellen:

DependencyInjector dependencyInjector = new DependencyInjector() { 
    @Override 
    public void inject(Job job) { 
     if (job instanceof MyActualJob) { 
      ((MyApplication) app).component().inject((MyActualJob) job); 
     } else if (job instanceof MyRealJob) { 
      ((MyApplication) app).component().inject((MyRealJob) job); 
     } else if (job instanceof MyBetterJob) { 
      ((MyApplication) app).component().inject((MyBetterJob) job); 
     } 
    } 
}; 

In meinem Fall benötigen die meisten, wenn nicht alle Jobs Zugriff auf dieselben globalen Objekte, daher ist es sauberer, BaseJob zu untergliedern und dieses als einziges Injektionsziel zu verwenden.

+0

dieser funktioniert! – chip

+0

hey, was ist, wenn jeder Job einen anderen Service benutzt? Würde ich für jeden Job einen BaseJob erstellen? –

+0

Nein, Sie würden den Dienst entweder zum BaseJob hinzufügen: @Inject DifferentService-Dienst; oder die if-Anweisung prüft und injiziert den neuen Job – Jessicardo

Verwandte Themen