如何使用Dagger 2将对象注入Android优先级作业队列?

时间:2016-01-26 19:20:18

标签: java android serialization dagger dagger-2

我正在尝试使用Dagger 2集成Retrofit 2和Android Priority Job Queue。

我可能在这里使用了错误的模式(我是Java和Android的新手),但是我试图从一个对象中访问Dagger创建的Retrofit实例,该对象将被序列化然后在执行前反序列化(Android作业队列序列化持久保存到磁盘的作业。 Retrofit实例由Application Dagger组件创建,因为我在其中一个依赖项中使用SharedPreferences。

由于Retrofit本身无法序列化,因此我无法将Retrofit传递给作业。

应用程序也无法序列化,因此我无法在作业运行时从作业中引用Application Dagger组件(因为我不能像{I}一样注入活动,因为Application对象不能在反序列化的工作中不存在。)

我想使用应用程序其余部分使用的Retrofit实例来提高效率,而不是仅为作业创建另一个实例。它甚至可能吗?

我不确定使用((MyApplication) myApplication).component().inject(this);或工厂可能会有所帮助,因为现在我的理解已经超出了我的想法,但如果情况确实如此,我会喜欢暗示如何构建事物!

编辑:这是如何使用Android优先级作业队列创建作业的。我修改了一个样本,以表明我希望注射方式如何工作。该作业在Provider<T>上序列化,并在使用onAdded()运行之前进行反序列化:

onRun()

1 个答案:

答案 0 :(得分:7)

这是我能够管理的最简单的解决方案。

首先,创建一个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
    }
}

最后,为确保相关内容,请在DependencyInjector创建时添加JobManager。这注入了工作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);

为什么不跳过BaseJob并直接注入MyActualJob?这将有效,但是如果有多个作业是注入目标,我相信您必须使用instanceof来检查创建的作业类型,并在创建时将job转换为正确的类{ {1}}:

DependencyInjector

在我的情况下,大多数(如果不是所有)作业都需要访问相同的全局对象,因此将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); } } }; 子类化为更清晰,并将其用作唯一的注入目标。