2016-01-26 7 views
5

私はそれは私が(私は、JavaとAndroidに新たなんだ)ここで間違ったパターンを使用していますが、私はしようとしている可能性がありますダガー2にDagger 2でAndroid優先ジョブキューにオブジェクトを挿入するにはどうすればよいですか?

を使用してレトロフィット2とAndroid優先ジョブキューを統合しようとしていますDaggerによって作成されたRetrofitインスタンスにシリアル化され、実行前に直列化解除されるオブジェクトからアクセスします(Android Job Queueはディスクに永続化されたジョブをシリアル化します)。 Retrofitインスタンスは、Application Daggerコンポーネントによって作成されます。これは、依存関係の1つでSharedPreferencesを使用しているためです。

Retrofit自体をシリアル化できないため、作成時にRetrofitをジョブに渡すことができません。

アプリケーションもシリアル化できないため、実行時にApplication Daggerコンポーネントをジョブから参照することはできません(アプリケーションオブジェクトが存在しないため、アクティビティから実行できるように((MyApplication) myApplication).component().inject(this);を挿入できません)。 )

私はジョブのためだけに別のインスタンスを作成するのではなく、残りのアプリケーションで使用するRetrofitインスタンスを効率的に使用したいと考えています。それも可能ですか?

Provider<T>または工場を使用しているかどうかわかりませんが、それは私の理解の範囲を超えているので助けになるかもしれませんが、そうした場合には構造物の仕方についてのヒントが大好きです。

EDIT:この方法で、Android優先度ジョブキューを使用してジョブを作成します。私は、注射がどのように機能しているかを示すためにサンプルを修正しました。それはonRun()で実行れる前の仕事はonAdded()にシリアライズとデシリアライズされます。

// 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

一般的には、モデル/シンプルクラスをシリアル化します。 Retrofitインスタンスにアクセスする必要があるのはなぜですか? Manager/Presenter/Handlerクラスを追加してバックエンド呼び出しを行い、モデル(シリアル化されたクラス)をオプションなしに保持していますか? –

+0

@DavidMedenjak Androidの優先度ジョブキューで何が起こるかを示すサンプルコードを追加しました。それが実行されると、私のサービス(またはRetrofit)を仕事から呼び出す必要があります。 – snafu109

+1

ライブラリのreadmeには、インジェクタを追加してDIをサポートしていることが示されています。既に試しましたか?これは最もきれいな方法のように思えます –

答えて

6

は、ここで私が管理できる最も簡単なソリューションです。

まず、BaseJobクラスを作成します。これは、注入対象となります。

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

それはabstract宣言さそうJobクラスで宣言された抽象メソッドをオーバーライドする必要はありませんです。代わりに、BaseJobを継承するジョブでメソッドがオーバーライドされます。

BaseJobを継承するジョブを作成します。 BaseJobに注入され、任意のフィールドが使用可能です:

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

最後に、それが作成されますときJobManagerDependencyInjectorを追加し、物事がリンクアップしていることを確認します。これは、ジョブのBaseJobに注入:

BaseJobを使用してスキップし MyActualJobに直接注入しないのはなぜ
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); 

DependencyInjectorを作成するときにこれは、私はあなたが仕事の種類が作成されていたかどうか確認するためにinstanceofを使用しなければならないと信じて、注入対象となる複数のジョブがあるがあれば、仕事や正しいクラスにjobをキャストします:

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

私の場合、すべてのジョブが同じグローバルオブジェクトへのアクセスを必要としているとは限りませんので、BaseJobをサブクラス化し、それを唯一の注入ターゲットとして使用する方がきれいです。

+0

これは動作します! – chip

+0

ちょっと、それぞれのジョブが別のサービスを使用している場合はどうなりますか? ジョブごとにBaseJobを作成できますか? –

+0

いいえ、BaseJobにサービスを追加することはできません。 @Inject DifferentServiceサービス。 またはif文で新しいジョブをチェックして挿入する – Jessicardo

関連する問題