如何注入 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),但我不知道我应该怎么做:

关于我的 dagger2 实现的更多细节:

所以基本上,给定一个应用程序对象,匕首应该能够实例化 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
  • 提供
  • 后端、存储库等:应用程序逻辑
  • 服务注入:子组件

也许这可以帮助某人。