[英]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. 最后,为了确保事情联系了起来,加上
DependencyInjector
到JobManager
在创建时。 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.