如何注入 SyncAdapter
How to inject a SyncAdapter
我刚开始学习如何使用 Dagger,我已经将我的 Backend
连接 class 转换为自动注入。
class 处理 Retrofit 并执行网络请求。它曾经有静态方法,但现在它是一个对象,例如:
Backend.fetchPost(context, 42); // old way
mBackend.fetchPost(42); // mBackend is an injected field
上下文用于检索 AccountManager
,它为我的后端服务器提供 OAuth 令牌。现在自动注入。
这在活动和片段中效果很好,但我不知道如何注入我的 SyncAdapter
class。
事实上,它是一个我无法控制的框架对象,并且 AndroidInjections
没有准备好注入那种 class.
的静态方法
这是我想要开始工作的代码:
/**
* Handle the transfer of data between the backend and the app, using the Android sync adapter framework.
*/
public class SyncAdapter extends AbstractThreadedSyncAdapter {
@Inject
public Backend mBackend; // can't use constructor injection,
// so might aswell use a public field
public SyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
}
public SyncAdapter(Context context, boolean autoInitialize, boolean allowParallelSyncs) {
super(context, autoInitialize, allowParallelSyncs);
}
@Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
List<Post> posts = mBackend.getPosts();
// do stuf with the posts
}
}
所以我知道我应该在构造函数中的某个地方调用 @#!.inject(this)
,但我不知道我应该怎么做:
- 在应用程序上使用静态字段class 检索依赖图的头部,并让它浏览直到它可以注入所有字段
- 创建一个工厂class和类似用于活动和片段的接口
- 还有别的吗?
关于我的 dagger2 实现的更多细节:
Backend
class 有一个 @Inject
构造函数,所以 dagger 应该能够构造它,只要它可以获得 API 的实例和 Gson 解析器:
@Inject
public Backend(BackendApi api, @UploadGson Gson uploadGson) {
mApi = api;
mUploadGson = uploadGson;
}
BackendModule
dagger 模块有 @Provide
对象的 @UploadGson Gson
方法,以及从 BackendApi
(改造)到应用程序的依赖列表 class(通过注入器或记录器等各种对象)
- 在应用程序的
modules = {}
声明中引用了 BackendModule.class
@Component
所以基本上,给定一个应用程序对象,匕首应该能够实例化 class Backend
的对象,我想将其注入到我的 SyncAdapter
class.
我只是不知道如何实际触发注入。
PS:如上所述,我昨天学习了Dagger,如果您认为我的实现有问题,请指教。
我想我在这里发帖太快了。我以为框架实例化了我的 SyncAdapter
,但我自己在做:
public class SyncService extends Service {
private static final Object sSyncAdapterLock = new Object();
private static SyncAdapter sSyncAdapter = null;
/**
* Instantiate the sync adapter object.
*/
@Override
public void onCreate() {
synchronized (sSyncAdapterLock) {
if (sSyncAdapter == null) {
sSyncAdapter = new SyncAdapter(getApplicationContext(), true); // bingo!
}
}
}
/**
* Return an object that allows the system to invoke the sync adapter.
*/
@Override
public IBinder onBind(Intent intent) {
return sSyncAdapter.getSyncAdapterBinder();
}
}
所以我只需要注入服务就可以了。解决方法如下:
public class SyncService extends Service {
@Inject
SyncAdapter sSyncAdapter;
/**
* Instantiate the sync adapter object.
*/
@Override
public void onCreate() {
AndroidInjection.inject(this);
}
/**
* Return an object that allows the system to invoke the sync adapter.
*/
@Override
public IBinder onBind(Intent intent) {
return sSyncAdapter.getSyncAdapterBinder();
}
}
这是同步适配器:默认构造函数是隐藏的(设为私有),新构造函数是为 Dagger 设计的:它直接期望 SyncService
作为上下文并注入后端和其他对象(在我的例子中, 存储库 class).
public class SyncAdapter extends AbstractThreadedSyncAdapter {
private static final String TAG = SyncAdapter.class.getSimpleName();
private Backend mBackend;
private PostRepository mRepository;
@Inject
SyncAdapter(SyncService service, Backend backend, PostRepository repo) {
this(service, true);
mBackend = backend;
mRepository = repo;
}
private SyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
}
用于服务注入的新子组件:
@Subcomponent(modules = {})
public interface SyncServiceSubcomponent extends AndroidInjector<SyncService> {
@Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<SyncService> {
}
}
这是引用该子组件的模块。它提供 SyncService
(和 AuthenticatorService
,以完全相同的行为实现)由 SyncAdapter
构造函数(resp. Authenticator
)期望:
/**
* Used to provide/bind services with a factory
* Services can't be injected in the constructor so this is required
*/
@Module(subcomponents = {
SyncServiceSubcomponent.class,
AuthenticatorServiceSubcomponent.class,
})
public abstract class ServicesModule {
@Binds
@IntoMap
@ServiceKey(SyncService.class)
abstract AndroidInjector.Factory<? extends Service> bindSyncServiceInjectorFactory(SyncServiceSubcomponent.Builder builder);
@Binds
@IntoMap
@ServiceKey(AuthenticatorService.class)
abstract AndroidInjector.Factory<? extends Service> bindAuthenticatorServiceInjectorFactory(AuthenticatorServiceSubcomponent.Builder builder);
}
因此同步适配器具有以下依赖关系:
- 同步服务:由
ServicesModule
提供
- 后端、存储库等:应用程序逻辑
- 服务注入:子组件
也许这可以帮助某人。
我刚开始学习如何使用 Dagger,我已经将我的 Backend
连接 class 转换为自动注入。
class 处理 Retrofit 并执行网络请求。它曾经有静态方法,但现在它是一个对象,例如:
Backend.fetchPost(context, 42); // old way
mBackend.fetchPost(42); // mBackend is an injected field
上下文用于检索 AccountManager
,它为我的后端服务器提供 OAuth 令牌。现在自动注入。
这在活动和片段中效果很好,但我不知道如何注入我的 SyncAdapter
class。
事实上,它是一个我无法控制的框架对象,并且 AndroidInjections
没有准备好注入那种 class.
这是我想要开始工作的代码:
/**
* Handle the transfer of data between the backend and the app, using the Android sync adapter framework.
*/
public class SyncAdapter extends AbstractThreadedSyncAdapter {
@Inject
public Backend mBackend; // can't use constructor injection,
// so might aswell use a public field
public SyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
}
public SyncAdapter(Context context, boolean autoInitialize, boolean allowParallelSyncs) {
super(context, autoInitialize, allowParallelSyncs);
}
@Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
List<Post> posts = mBackend.getPosts();
// do stuf with the posts
}
}
所以我知道我应该在构造函数中的某个地方调用 @#!.inject(this)
,但我不知道我应该怎么做:
- 在应用程序上使用静态字段class 检索依赖图的头部,并让它浏览直到它可以注入所有字段
- 创建一个工厂class和类似用于活动和片段的接口
- 还有别的吗?
关于我的 dagger2 实现的更多细节:
Backend
class 有一个@Inject
构造函数,所以 dagger 应该能够构造它,只要它可以获得 API 的实例和 Gson 解析器:@Inject public Backend(BackendApi api, @UploadGson Gson uploadGson) { mApi = api; mUploadGson = uploadGson; }
BackendModule
dagger 模块有@Provide
对象的@UploadGson Gson
方法,以及从BackendApi
(改造)到应用程序的依赖列表 class(通过注入器或记录器等各种对象)- 在应用程序的
modules = {}
声明中引用了BackendModule.class
@Component
所以基本上,给定一个应用程序对象,匕首应该能够实例化 class Backend
的对象,我想将其注入到我的 SyncAdapter
class.
我只是不知道如何实际触发注入。
PS:如上所述,我昨天学习了Dagger,如果您认为我的实现有问题,请指教。
我想我在这里发帖太快了。我以为框架实例化了我的 SyncAdapter
,但我自己在做:
public class SyncService extends Service {
private static final Object sSyncAdapterLock = new Object();
private static SyncAdapter sSyncAdapter = null;
/**
* Instantiate the sync adapter object.
*/
@Override
public void onCreate() {
synchronized (sSyncAdapterLock) {
if (sSyncAdapter == null) {
sSyncAdapter = new SyncAdapter(getApplicationContext(), true); // bingo!
}
}
}
/**
* Return an object that allows the system to invoke the sync adapter.
*/
@Override
public IBinder onBind(Intent intent) {
return sSyncAdapter.getSyncAdapterBinder();
}
}
所以我只需要注入服务就可以了。解决方法如下:
public class SyncService extends Service {
@Inject
SyncAdapter sSyncAdapter;
/**
* Instantiate the sync adapter object.
*/
@Override
public void onCreate() {
AndroidInjection.inject(this);
}
/**
* Return an object that allows the system to invoke the sync adapter.
*/
@Override
public IBinder onBind(Intent intent) {
return sSyncAdapter.getSyncAdapterBinder();
}
}
这是同步适配器:默认构造函数是隐藏的(设为私有),新构造函数是为 Dagger 设计的:它直接期望 SyncService
作为上下文并注入后端和其他对象(在我的例子中, 存储库 class).
public class SyncAdapter extends AbstractThreadedSyncAdapter {
private static final String TAG = SyncAdapter.class.getSimpleName();
private Backend mBackend;
private PostRepository mRepository;
@Inject
SyncAdapter(SyncService service, Backend backend, PostRepository repo) {
this(service, true);
mBackend = backend;
mRepository = repo;
}
private SyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
}
用于服务注入的新子组件:
@Subcomponent(modules = {})
public interface SyncServiceSubcomponent extends AndroidInjector<SyncService> {
@Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<SyncService> {
}
}
这是引用该子组件的模块。它提供 SyncService
(和 AuthenticatorService
,以完全相同的行为实现)由 SyncAdapter
构造函数(resp. Authenticator
)期望:
/**
* Used to provide/bind services with a factory
* Services can't be injected in the constructor so this is required
*/
@Module(subcomponents = {
SyncServiceSubcomponent.class,
AuthenticatorServiceSubcomponent.class,
})
public abstract class ServicesModule {
@Binds
@IntoMap
@ServiceKey(SyncService.class)
abstract AndroidInjector.Factory<? extends Service> bindSyncServiceInjectorFactory(SyncServiceSubcomponent.Builder builder);
@Binds
@IntoMap
@ServiceKey(AuthenticatorService.class)
abstract AndroidInjector.Factory<? extends Service> bindAuthenticatorServiceInjectorFactory(AuthenticatorServiceSubcomponent.Builder builder);
}
因此同步适配器具有以下依赖关系:
- 同步服务:由
ServicesModule
提供
- 后端、存储库等:应用程序逻辑
- 服务注入:子组件
也许这可以帮助某人。