Dagger 2 不注入接口类型

Dagger 2 not injecting in interface type

我试图在由 class 实现的接口类型中注入一个字段。

这是我到目前为止所做的。

这些是查看界面:

public interface PostView extends View, ListView<Post>, EmptyView<String> {
}
public interface View {

    public void showProgressIndicator();

    public void hideProgressIndicator();

    public void onSuccess();

    public void onFailure();

    public void onFailure(String message);
}

public interface ListView<E> {

    public void onListItems(List<E> items,
            int pageNum,
            int pageSize,
            boolean next);

}

public interface EmptyView<E> {

    public void onEmpty(E e);

    public void onEmpty(String message);
}

组件:

@Singleton
@Component(modules = ApiModule.class)
public interface ApiComponent {

    Api provideApi();

}

@UserScope
@Component(dependencies = ApiComponent.class, modules = PostModule.class)
public interface PostComponent {

    PostPresenter providePostPresenter();

    void inject(NetworkTest networkTest);
}

模块:

@Module
public class ApiModule {

    private static final Logger logger = Logger.getLogger(ApiModule.class.getSimpleName());

    private final String baseUrl;

    public ApiModule(String baseUrl) {
        this.baseUrl = baseUrl;
    }

    @Provides
    @Singleton
    boolean provideIsLoggerEnabled() {
        logger.info("proviedIsLoggerEnabled()");
        return true;
    }

    @Provides
    @Singleton
    OkHttpClient provideOkHttpClient(boolean logEnabled) {
        logger.info(" provideOkHttpClient(logEnabled)");
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        Interceptor requestInterceptor = new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                return chain.proceed(chain.request());
            }
        };
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .addInterceptor(requestInterceptor)
                .addNetworkInterceptor(interceptor);
        return builder.build();
    }

    @Provides
    @Singleton
    Api provideApi(OkHttpClient okHttpClient) {
        logger.info("provideApi");
        Retrofit retrofit = new Retrofit.Builder()
                .client(okHttpClient)
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        return retrofit.create(Api.class);
    }

}

@Module
public class PostModule {

    private static final Logger logger = Logger.getLogger(PostModule.class.getSimpleName());
    private final PostView postView;

    public PostModule(PostView postView) {
        this.postView = postView;
    }

    @Provides
    @UserScope
    PostService providePostService(Api api) {
        logger.info("Provider post with api now");
        return new PostService(api);
    }

    @Provides
    @UserScope
    PostPresenter providePostPresenter(PostService service) {
        logger.info("Providing presenter with service now");
        return new PostPresenter(postView, service);
    }
}

主持人:

public class PostPresenter extends AbstractPresenter {

    private static final Logger logger = Logger.getLogger(PostPresenter.class.getSimpleName());
    private PostView postView;
    private PostService postService;

    public PostPresenter(PostView postView, PostService postService) {
        this.postView = postView;
        this.postService = postService;
    }

    @Override
    protected View getView() {
        logger.info("Getting view");
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    public void getPosts() {
        logger.info("Getting posts ");
        Call<List<Post>> posts = this.postService.getPosts();
        postView.showProgressIndicator();
        posts.enqueue(new Callback<List<Post>>() {

            @Override
            public void onResponse(Call<List<Post>> call, Response<List<Post>> rspns) {
                postView.onListItems(rspns.body(), 1, 25, true);
                postView.hideProgressIndicator();
                postView.onSuccess();
            }

            @Override
            public void onFailure(Call<List<Post>> call, Throwable thrwbl) {
                onApiCallError(thrwbl);
                postView.hideProgressIndicator();
            }
        });
    }
}

public abstract class AbstractPresenter {

    private static final Logger logger = Logger.getLogger(AbstractPresenter.class.getSimpleName());

    protected abstract View getView();

    /*
     * General indication whether api call stated or not.
     */
    protected void onApiCallStart() {
        logger.info("Api call started");
        View v = getView();
        if (v != null) {
            v.showProgressIndicator();
        }
    }

    protected void onApiCallEnd() {
        logger.info("Api call finished");
        View v = getView();
        if (v != null) {
            v.hideProgressIndicator();
        }
    }

    /*
     * General error handling 
     */
    protected void onApiCallError(Throwable e) {
        logger.info("Api call terminated with error");
        View v = getView();
        if (v != null && e != null) {
            v.onFailure(e.getMessage());
        }
    }
}

网络测试:

public class NetworkTest implements PostView {

    private static final Logger logger = Logger.getLogger(NetworkTest.class.getSimpleName());

    private PostComponent component;
    @Inject
    PostPresenter presenter;

    public NetworkTest(ApiComponent apiComponent) {
        component = DaggerPostComponent.builder()
                .apiComponent(apiComponent)
                .postModule(new PostModule(this))
                .build();
    }

    public void init() {
        component.inject(this);
    }

    void showPosts() {
        if (presenter != null) {
            logger.info("Hurray it worked");
            presenter.getPosts();
        } else {
            logger.warning("Alas it failed");
        }
    }

    @Override
    public void showProgressIndicator() {
        logger.info("Show progress indicator here");
    }

    @Override
    public void hideProgressIndicator() {
        logger.info("Hide progress indicator here");
    }

    @Override
    public void onSuccess() {
        logger.info("Api calls successfull");
        System.exit(0);
    }

    @Override
    public void onFailure() {
        logger.warning("Api call failure");
        System.exit(0);
    }

    @Override
    public void onFailure(String message) {
        logger.warning(message);
        System.exit(0);
    }

    @Override
    public void onListItems(List<Post> items, int pageNum, int pageSize, boolean next) {
        logger.info("List received is: " + new Gson().toJson(items));
    }

    @Override
    public void onEmpty(String e) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    public static void main(String[] args) {
        ApiComponent apiComponent = DaggerApiComponent.builder()
                .apiModule(new ApiModule("https://jsonplaceholder.typicode.com/"))
                .build();

        NetworkTest networkTest = new NetworkTest(apiComponent);
        networkTest.init();
        networkTest.showPosts();
    }

}

我的问题是当我尝试使用

void inject(NetworkTest networkTest); //It works
void inject(PostView postView); //Doesn't work

我希望 PostPresenter 应该被注入任何正在实施 PostView 的 class。

但是当我这样做时 @Inject 字段 return 为空。 有没有人对此有任何线索。

NetworkTest 有一个 Dagger 可以在编译时检测到的 @Inject 字段。 PostView 没有。 Dagger 2 可以对 NetworkTest 和 PostView 进行注入,但是因为 PostView 没有 @Inject-注解的方法,所以 Dagger 2 没有什么可以注入的。

如果你想表达 PostView 的任意实现者可以被注入,你应该添加一个 @Inject 注释的 initializeinjectPresenter 方法(等);否则,只有 get/inject 来自 Dagger 的具体类型,因此它们的所有依赖项都可以一次注入。


Dagger 2 user's guide(强调我的)所述,"Dagger is a fully static, compile-time dependency injection framework for both Java and Android." 与 Guice 或 Spring 不同,Dagger 2 不执行运行时反射,因此(例如)生成的组件方法inject(PostView) 只能注入在 PostView 或其超类型 上定义的字段和方法 ,不能注入在子类型上定义的任何内容。

在一般意义上,我认为您期望(或限制)您的 PostView 接口实现者要求以某种方式注入 Presenter 是不合理的;如果你想创建一个显式的 presenter-providing 生命周期方法,你可以在不涉及 Dagger 的情况下在 PostView 上完成,这样你的 类 可以更具体地说明它们的依赖关系,而不是将必要的 deps 与 "unnecessary-but-included" 根据您的规定。