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

How do I inject an object into Android Priority Job Queue with Dagger 2?

我正在尝试使用 Dagger 2 集成 Retrofit 2 和 Android 优先作业队列。

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

我无法在创建作业时将 Retrofit 传递给作业,因为 Retrofit 本身无法序列化。

应用程序也无法序列化,所以我无法在 运行s 时从作业中引用 Application Dagger 组件(因为我无法像从活动,因为反序列化作业中不存在 Application 对象。)

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

我不确定使用 Provider<T> 或工厂是否有帮助,因为这超出了我现在的理解范围,但如果是这样的话,我希望得到有关如何构建事物的提示!

编辑: 这就是您使用 Android 优先作业队列创建作业的方式。我已经修改了一个样本以表明我希望注射如何工作。该作业在 onAdded() 上序列化并在 运行 之前使用 onRun():

反序列化
// 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
    }
}

这是我能做到的最简单的解决方案。

首先,创建一个BaseJobclass。这将是注入目标:

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 class 中声明的任何抽象方法。相反,方法将在继承自 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 转换为正确的 class 创建时 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);
        }
    }
};

在我的例子中,大多数(如果不是全部)作业都需要访问相同的全局对象,因此使用 subclass BaseJob 并将其用作唯一的注入目标更清晰。