我试图在一个由类实现的接口类型中注入一个字段。
这是我到目前为止所做的。
这些是视图界面:
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。
有没有人对此有任何线索。
答案 0 :(得分:1)
NetworkTest有一个@Inject
字段,Dagger可以在编译时检测到该字段。 PostView没有。 Dagger 2可以在NetworkTest和PostView上执行注入,但由于PostView没有@Inject
- 注释方法,因此Dagger 2无需注入。
如果您想表达可以注入PostView的任意实现者,您应该添加@Inject
- 带注释的initialize
或injectPresenter
方法(等);否则,只需从Dagger获取/注入具体类型,这样就可以立即注入所有依赖项。
正如Dagger 2 user's guide(强调我的)中所述,“Dagger是Java和Android的完全静态,编译时依赖注入框架。”与Guice或Spring不同,Dagger 2不执行运行时反射,因此(例如)生成的Component方法inject(PostView)
只能在PostView或其超类型上注入定义的字段和方法,而不是任何东西在子类型上定义。
从一般意义上讲,我认为你期望(或约束)你的PostView
接口实现者要求以某种方式注入Presenter是不合理的;如果你想制作一个明确的提供者提供生命周期方法,你可以在PostView上做到这一点,而不涉及Dagger,这样你的类可以更具体地依赖于它们的依赖性,而不是将必要的deps与“不必要但包含在内的”包含在一起。你开的处方。