我正在使用Dagger2构建应用程序。在尝试将RecylerAdapter和LayoutManager转换为注入的对象之前,我已经使用Dagger2进行了依赖注入。当我尝试添加这些时,我会遇到各种各样的错误。我一直在阅读有关Dagger2的越来越多的文章,以期更好地理解它,我修复了一些问题,但仍然不确定为什么它不起作用。我遇到了很多编译错误,我认为这与我的依赖关系有关,但此时我很茫然。我得到的错误是:
D:\Development\Android\Projects\GiantBombForAndroid\app\src\main\java\com\app\int_a\giantbombforandroid\main\App.java
Error:(5, 61) error: cannot find symbol class DaggerNetComponent
D:\Development\Android\Projects\GiantBombForAndroid\app\src\main\java\com\app\int_a\giantbombforandroid\main\mainscreen\MainActivity.java
Error:(11, 61) error: cannot find symbol class DaggerMainScreenComponent
D:\Development\Android\Projects\GiantBombForAndroid\app\src\main\java\com\app\int_a\giantbombforandroid\main\data\component\MainScreenComponent.java
Error:(16, 10) error: java.util.List<com.app.int_a.giantbombforandroid.main.model.Result> cannot be provided without an @Provides-annotated method.
com.app.int_a.giantbombforandroid.main.mainscreen.MainActivity.recyclerAdapter
[injected field of type: com.app.int_a.giantbombforandroid.main.mainscreen.MainScreenRecyclerAdapter recyclerAdapter]
com.app.int_a.giantbombforandroid.main.data.module.MainScreenModule.provideMainScreenRecyclerAdapter(java.util.List<com.app.int_a.giantbombforandroid.main.model.Result> videoList, android.content.Context context)
[parameter: java.util.List<com.app.int_a.giantbombforandroid.main.model.Result> videoList]
D:\Development\Android\Projects\GiantBombForAndroid\app\src\main\java\com\app\int_a\giantbombforandroid\main\data\component\NetComponent.java
Error:(23, 10) error: com.app.int_a.giantbombforandroid.main.mainscreen.MainScreenRecyclerAdapter cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.
com.app.int_a.giantbombforandroid.main.mainscreen.MainActivity.recyclerAdapter
[injected field of type: com.app.int_a.giantbombforandroid.main.mainscreen.MainScreenRecyclerAdapter recyclerAdapter]
这是我实现依赖项注入的方式:
MainScreenComponent.java
@CustomScope
@Component(dependencies = NetComponent.class, modules = MainScreenModule.class)
public interface MainScreenComponent {
void inject(MainActivity activity);
}
NetComponent.java
@Singleton
@Component(modules = {AppModule.class, NetModule.class})
public interface NetComponent {
// downstream components need these exposed with the return type
// method name does not really matter
Retrofit retrofit();
void inject(MainActivity activity);
}
AppModule.java
@Module
public class AppModule {
Application application;
public AppModule(Application application){
this.application = application;
}
@Provides
@Singleton
Application provideApplication(){
return application;
}
}
MainScreenModule.java
@Module
public class MainScreenModule {
private final MainScreenContract.View view;
private final Context context;
private final List<Result> videoList;
private final int numColumns;
public MainScreenModule(MainScreenContract.View view, Context context, List<Result> videoList, int numColumns){
this.view = view;
this.context = context;
this.numColumns = numColumns;
this.videoList = videoList;
}
@Provides
@CustomScope
MainScreenContract.View providesMainScreenContractView(){
return view;
}
@Provides
@CustomScope
MainScreenRecyclerAdapter provideMainScreenRecyclerAdapter(List<Result> videoList, Context context){
return new MainScreenRecyclerAdapter(videoList, context);
}
@Provides
@CustomScope
GridLayoutManager provideGridLayoutManager(Context context, int columns){
return new GridLayoutManager(context, columns);
}
}
NetModule.java
@Module
public class NetModule {
// Maybe one day this will be a view object to contain a video?
// Maybe it will become a dependency and will be injected via
// another module? Let Dagger find a view object and create it
public NetModule(){
}
@Provides
@Singleton
SharedPreferences providesSharedPreferences(Application application){
return PreferenceManager.getDefaultSharedPreferences(application);
}
@Provides
@Singleton
Cache provideHttpCache(Application application){
int cacheSize = 10 * 1024 * 1024;
Cache cache = new Cache(application.getCacheDir(), cacheSize);
return cache;
}
@Provides
@Singleton
Gson provideGson(){
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
return gsonBuilder.create();
}
@Provides
@Singleton
OkHttpClient provideOkhttpClient (Cache cache){
OkHttpClient.Builder client = new OkHttpClient.Builder();
client.cache(cache);
// Adds GiantBomb.com api key to request
// Adds json parameter because all requests will expect json
client.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
HttpUrl originalHttpUrl = original.url();
HttpUrl url = originalHttpUrl.newBuilder()
.addQueryParameter("api_key", BuildConfig.GIANTBOMB_API_KEY)
.addQueryParameter("format","json")
.build();
// Request customization: add request headers
Request.Builder requestBuilder = original.newBuilder()
.url(url);
Timber.d("URL:" + url);
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
return client.build();
}
@Provides
@Singleton
Retrofit provideRetrofit(Gson gson, OkHttpClient okHttpClient){
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(Constants.BASE_URL)
.client(okHttpClient)
.build();
return retrofit;
}
}
App.java
public class App extends Application {
private NetComponent netComponent;
@Override
public void onCreate(){
super.onCreate();
netComponent = DaggerNetComponent.builder()
.appModule(new AppModule(this))
.netModule(new NetModule())
.build();
}
public NetComponent getNetComponent(){
return netComponent;
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity implements MainScreenContract.View {
ArrayList<Result> list = new ArrayList<>();
// Objects for RecyclerView
@BindView(R.id.my_recycler_list)
RecyclerView recyclerView;
@Inject
MainScreenRecyclerAdapter recyclerAdapter;
@Inject
MainScreenPresenter mainPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Timber.plant(new Timber.DebugTree() {
// Add the line number to the tag
@Override
protected String createStackElementTag(StackTraceElement element) {
return super.createStackElementTag(element) + ':' + element.getLineNumber();
}
});
//Call the method in MainPresenter to make Network Request
mainPresenter.loadVideo();
DaggerMainScreenComponent.builder()
.netComponent(((App) getApplicationContext()).getNetComponent())
.mainScreenModule(new MainScreenModule(this, this.getApplicationContext(), list, 2))
.build().inject(this);
Timber.d("Array size: " + list.size());
}
@Override
public void showVideos(Video video){
// Loop through the posts, get the title of the post, and add it to our list object
for(int i = 0; i < video.getResults().size(); i++){
Result currentVideo = video.getResults().get(i);
// Filter out Premium videos since these would require authentication
if(currentVideo.getVideoType() != null && !currentVideo.getVideoType().equals("Premium")) {
list.add(currentVideo);
Timber.d("List item " + i + " = " + list.get(list.size()-1));
}
}
// RecyclerView implementation
recyclerView.setLayoutManager(new GridLayoutManager(this, 2));
recyclerAdapter = new MainScreenRecyclerAdapter(list, this.getApplicationContext());
recyclerView.setAdapter(recyclerAdapter);
// set to true because all images will be the same size
recyclerView.setHasFixedSize(true);
}
@Override
public void showError(String message){
// Show error message text as a Toast message
Toast.makeText(getApplicationContext(), "Error" + message, Toast.LENGTH_SHORT).show();
Timber.e("Error: " + message);
}
@Override
public void showComplete(){
// Show completed Toast message
Toast.makeText(getApplicationContext(), "Complete", Toast.LENGTH_SHORT).show();
}
}
MainScreenRecyclerAdapter.java
public class MainScreenRecyclerAdapter extends RecyclerView.Adapter {
private List<Result> myDataset;
private Context myContext;
// TODO: Should I make the list contain Video/Result objects and pull the data from that?
public MainScreenRecyclerAdapter(List<Result> dataset, Context context) {
myDataset = dataset;
myContext = context;
}
// Create new views
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// create a new view
View v = LayoutInflater.from(myContext)
.inflate(R.layout.thumbnail_view, parent, false);
final RecyclerView.ViewHolder viewHolder = new VideoViewHolder(v);
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Timber.d("Stub for VideoViewHolder onClick() method");
}
});
return viewHolder;
}
// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
((VideoViewHolder) holder).bind(myDataset, position, myContext);
}
// Return the size of your dataset (invoked by the layout manager)
@Override
public int getItemCount() {
return myDataset.size();
}
}
VideoViewHolder.java
public class VideoViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.thumbnail)
public ImageView thumbnailView;
@BindView(R.id.video_title_view)
public TextView videoTitle;
public VideoViewHolder(View v) {
super(v);
ButterKnife.bind(this, v);
}
public void bind(List<Result> myDataset, int position, Context myContext){
// - get element from dataset at this position
// - replace the contents of hte view with that element
Result currentVideo = myDataset.get(position);
String imageUrl =currentVideo.getImage().getMediumUrl();
Timber.d("Image URL: " + imageUrl);
Picasso.with(myContext).load(imageUrl).into(thumbnailView);
videoTitle.setText(currentVideo.getName());
}
}
我意识到这里有很多代码。任何帮助表示赞赏!
最佳答案
您的错误:
没有@Inject不能提供MainScreenRecyclerAdapter
构造函数或@Provides或@Produces注释方法。
因此,您必须为@Inject
投放MainScreenRecyclerAdapter
。因为您在MainScreenModule
中提供了此适配器。因此,您的适配器应为:
// TODO: Should I make the list contain Video/Result objects and pull the data from that?
@Inject
public MainScreenRecyclerAdapter(List<Result> dataset, Context context) {
myDataset = dataset;
myContext = context;
}