Dagger 2没有在接口类型

时间:2016-10-10 11:51:38

标签: java dependency-injection dagger-2

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

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

这些是视图界面:

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());
        }
    }
}

NetworkTest:

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的班级中都应该注册。

但是当我这样做时@Inject字段返回null。 有没有人对此有任何线索。

1 个答案:

答案 0 :(得分:1)

NetworkTest有一个@Inject字段,Dagger可以在编译时检测到该字段。 PostView没有。 Dagger 2可以在NetworkTest和PostView上执行注入,但由于PostView没有@Inject - 注释方法,因此Dagger 2无需注入。

如果您想表达可以注入PostView的任意实现者,您应该添加@Inject - 带注释的initializeinjectPresenter方法(等);否则,只需从Dagger获取/注入具体类型,这样就可以立即注入所有依赖项。

正如Dagger 2 user's guide(强调我的)中所述,“Dagger是Java和Android的完全静态,编译时依赖注入框架。”与Guice或Spring不同,Dagger 2不执行运行时反射,因此(例如)生成的Component方法inject(PostView)只能在PostView或其超类型上注入定义的字段和方法,而不是任何东西在子类型上定义。

从一般意义上讲,我认为你期望(或约束)你的PostView接口实现者要求以某种方式注入Presenter是不合理的;如果你想制作一个明确的提供者提供生命周期方法,你可以在PostView上做到这一点,而不涉及Dagger,这样你的类可以更具体地依赖于它们的依赖性,而不是将必要的deps与“不必要但包含在内的”包含在一起。你开的处方。