如何注入SyncAdapter

Ben*_*fez 4 android dependency-injection android-syncadapter dagger-2

我刚刚开始学习如何使用Dagger,并且已经将我的Backend连接类转换为自动注入.

该类处理Retrofit并执行网络请求.它曾经有静态方法,但现在它是一个对象,例如:

Backend.fetchPost(context, 42); // old way
mBackend.fetchPost(42); // mBackend is an injected field
Run Code Online (Sandbox Code Playgroud)

上下文用于检索AccountManager使用我的后端服务器提供OAuth令牌的上下文.现在自动注入.

这在活动和片段中效果很好,但我无法弄清楚如何注入我的SyncAdapter课程.
实际上,它是一个我无法控制的框架对象,并且AndroidInjections没有准备好注入这种类的静态方法.

这是我想要工作的代码:

/**
 * 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
    }
}
Run Code Online (Sandbox Code Playgroud)

所以我知道我应该@#!.inject(this)在构造函数中调用某个地方,但我不确切地知道我应该怎么做:

  • 在应用程序类上使用静态字段来检索依赖关系图的头部,并让它浏览它直到它可以注入所有字段
  • 创建一个工厂类和接口,如用于活动和片段的接口
  • 别的什么?

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

  • Backend类有一个@Inject构造函数,所以匕首应该能够构建它,只要它可以得到API和GSON解析器的实例:

    @Inject
    public Backend(BackendApi api, @UploadGson Gson uploadGson) {
        mApi = api;
        mUploadGson = uploadGson;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • BackendModule匕首模块具有@Provide用于方法@UploadGson Gson的对象,并从依赖关系列表BackendApi来应用程序类(改型)(通过各种对象,如注射器或记录器)
  • BackendModule.class被引用的modules = {}应用程序的声明@Component

所以基本上,给定一个应用程序对象,dagger应该能够实例化一个类的对象Backend,我想将它注入到我的SyncAdapter类中.
我只是不知道如何实际触发注射.

PS:如上所述,我昨天学会了Dagger,所以请告知你是否认为我的实施已被破坏.

Ben*_*fez 6

我想我在这里发帖太快了.我认为框架实例化了我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();
    }
}
Run Code Online (Sandbox Code Playgroud)

所以我只需要注入服务,我就完成了.以下是解决这个问题的方法:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

这是同步适配器:默认构造函数是隐藏的(私有),新构造函数是为Dagger制作的:它直接SyncService作为上下文并注入后端和其他对象(在我的例子中,是一个存储库类).

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);
    }
Run Code Online (Sandbox Code Playgroud)

服务注入的新子组件:

@Subcomponent(modules = {})
public interface SyncServiceSubcomponent extends AndroidInjector<SyncService> {
    @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder<SyncService> {
    }
}
Run Code Online (Sandbox Code Playgroud)

这是引用该子组件的模块.它提供了构造函数(resp.)所期望的SyncService(并且AuthenticatorService,它以完全相同的行为实现):SyncAdapterAuthenticator

/**
 * 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);
}
Run Code Online (Sandbox Code Playgroud)

因此,同步适配器具有以下依赖项:

  • 同步服务:由.提供 ServicesModule
  • 后端,存储库等:应用程序逻辑
  • 服务注入:子组件

也许这可以帮助别人.