2017-04-26 5 views
1

Ich baue eine App mit Dagger2. Ich hatte die Abhängigkeitsinjektion mit Dagger2 zu arbeiten, bevor ich versuchte, meinen RecylerAdapter und LayoutManager in injizierte Objekte zu konvertieren. Wenn ich versuche, diese hinzuzufügen, bekomme ich alle möglichen Fehler. Ich habe mehr und mehr auf Dagger2 gelesen und versucht, ein besseres Verständnis davon zu bekommen. Ich habe einige Sachen repariert, bin mir aber immer noch nicht sicher, warum das nicht funktioniert. Ich bekomme viele Kompilierungsfehler, ich denke, das hat etwas mit meinen Abhängigkeiten zu tun, aber ich bin zu diesem Zeitpunkt ratlos. Die Fehler Ich erhalte sind:Dagger2 kann keine Komponentenklassen generieren

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] 

Hier ist, wie ich die Dependency Injection implementiert haben: 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; 
    } 
} 
91.363.210 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()); 
    } 
} 

Ich weiß, eine Menge Code gibt es hier. Jede Hilfe wird geschätzt!

Antwort

1

Ihr Fehler:

MainScreenRecyclerAdapter cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.

So müssen Sie Anzeige @Inject für Ihre MainScreenRecyclerAdapter. Weil Sie diesen Adapter in Ihrem MainScreenModule bereitgestellt haben. So sollte Ihr Adapter sein:

// 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; 
    } 
+0

Huh, richtig. Vielen Dank. Obwohl ich noch die anderen Fehler habe. Mit derselben Logik würde ich auch eine GridLayoutManager-Klasse mit einem annotierten Konstruktor benötigen, richtig? Ich habe jedoch keine eigene GridLayoutManager-Klasse, sondern verwende sie aus der Support-Bibliothek. – intA

Verwandte Themen