简体   繁体   English

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

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

I'm trying to integrate Retrofit 2 and Android Priority Job Queue by using Dagger 2. 我正在尝试使用Dagger 2集成Retrofit 2和Android Priority Job Queue。

It's likely I'm using the wrong pattern here (I'm new to Java and Android), but I'm trying to access a Dagger-created Retrofit instance from an object that will be serialized then deserialized before execution (Android Job Queue serializes jobs that are persisted to disk). 我可能在这里使用了错误的模式(我是Java和Android的新手),但是我试图从一个对象中访问一个Dagger创建的Retrofit实例,该对象将在执行前被序列化然后反序列化(Android Job Queue序列化持久存储到磁盘的作业)。 The Retrofit instance is created by an Application Dagger component, because I'm using SharedPreferences in one of its dependencies. Retrofit实例由Application Dagger组件创建,因为我在其中一个依赖项中使用SharedPreferences。

I can't pass Retrofit to the job when it's created because Retrofit itself cannot be serialized. 我无法在创建时将Retrofit传递给作业,因为Retrofit本身无法序列化。

Application also can't be serialized, so I can't reference the Application Dagger component from the job when it runs (since I cannot inject with ((MyApplication) myApplication).component().inject(this); like I can do from Activities, because the Application object doesn't exist in the deserialized job.) 应用程序也无法序列化,因此我无法在作业运行时从作业中引用Application Dagger组件(因为我无法注入((MyApplication) myApplication).component().inject(this);就像我能做的那样来自Activities,因为反序列化作业中不存在Application对象。)

I want to use the Retrofit instance used by the rest of the app for efficiency instead of creating another instance just for the job. 我想使用应用程序其余部分使用的Retrofit实例来提高效率,而不是仅为作业创建另一个实例。 Is it even possible? 它甚至可能吗?

I'm not sure if using Provider<T> or a Factory might help because that's beyond my understanding right now, but I'd love a hint about how to structure things if that's the case! 我不确定使用Provider<T>还是工厂可能会有所帮助,因为现在我的理解已经超出了我的想法,但如果是这样的话,我会喜欢暗示如何构建事物!

EDIT: This how you create a job with Android Priority Job Queue. 编辑:这是如何使用Android优先级作业队列创建作业。 I've modified a sample to indicate how I'd like the injection to be working. 我修改了一个样本,以表明我希望注射方式如何工作。 The job is serialized on onAdded() and deserialized before it's run with onRun() : 该作业序列上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
    }
}

Here's the simplest solution that I could manage. 这是我能够管理的最简单的解决方案。

First, create a BaseJob class. 首先,创建一个BaseJob类。 This will be the injection target: 这将是注射目标:

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

It's declared abstract so there's no need to override any of the abstract methods declared in the Job class. 它被声明为abstract因此不需要覆盖Job类中声明的任何抽象方法。 Instead, methods will be overridden in the jobs that inherit from BaseJob . 相反,方法将在从BaseJob继承的作业中被覆盖。

Create a job that inherits from BaseJob . 创建从BaseJob继承的作业。 Any fields injected into BaseJob are available for use: 注入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
    }
}

Finally, to ensure things are linked up, add a DependencyInjector to JobManager when it's created. 最后,为了确保事情联系了起来,加上DependencyInjectorJobManager在创建时。 This injects into the job's BaseJob : 这注入了作业的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);

Why not skip using BaseJob and inject directly into MyActualJob ? 为什么不跳过使用BaseJob并直接注入MyActualJob This will work, however if there are several jobs that are injection targets, I believe you would have to use instanceof to check what kind of job was being created and cast job to the correct class when creating DependencyInjector : 这将有效,但是如果有多个作业是注入目标,我相信你必须使用instanceof来检查创建什么类型的作业,并在创建DependencyInjector时将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);
        }
    }
};

In my case most if not all jobs need access to the same global objects, so it's cleaner to subclass BaseJob and use that as the sole injection target. 在我的情况下,大多数(如果不是所有)作业都需要访问相同的全局对象,因此将BaseJob子类BaseJob并将其用作唯一注入目标更为清晰。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM