Search code examples
javaandroiddagger-2android-viewholderdagger

I can't Inject my class in to my ViewHolder with Dagger2


I maked a PictureDownloader to download images and set into my viewHolder. So I want to Inject one instance of PictureDownloader in that viewHolder, but it is always null and I can't find my mistake with the injection. What I have to do more? I need another Module? I have to inject this ViewHolder?

Here I bring all these classes:

AppComponent:

@Singleton
@Component(modules = {ActivityBindingModule.class,
    AppModule.class,
    PictureDownloaderModule.class,
    AndroidSupportInjectionModule.class})
public interface AppComponent extends AndroidInjector<MarvelApplication> {
    PictureDownloader getPictureDownloader();

    @Component.Builder
    interface Builder {
        @BindsInstance
        AppComponent.Builder application(Application application);
        AppComponent build();
    }
}

PictureDonwloaderModule:

@Module
public class PictureDownloaderModule {
    @Provides
    @Singleton
    CacheImageHandler providesCacheImageHandler(Context context) {
        return new CacheImageHandler(context);
    }

    @Singleton
    PictureDownloader providesPictureDownloader(CacheImageHandler cacheImageHandler) {
        return new PictureDownloader(cacheImageHandler);
    }
}

PictureDownloader:

@Singleton
public class PictureDownloader {

    private CacheImageHandler mCacheHandler;

    @Inject
    public PictureDownloader(CacheImageHandler cacheHandler) {
        this.mCacheHandler = cacheHandler;
    }

    public void download(String url, ImageView imageView) {
        if (url == null) {
            return;
        }
        if (imageView == null) {
            return;
        }

        // resetPurgeTimer();
        Bitmap bitmap = mCacheHandler.getBitmapFromCache(url);

....

CacheImageHandler:

@Singleton
public class CacheImageHandler {

    private Context mContext;
    private SoftImageCache mSoftCache;

    @Inject
    public CacheImageHandler(Context context) {
        mContext = context;
        int memClass = ( (ActivityManager) mContext.getSystemService( Context.ACTIVITY_SERVICE ) ).getMemoryClass();
        int cacheSize = 1024 * 1024 * memClass;
        mSoftCache = new SoftImageCache(cacheSize);
    }

    // Save Bitmap to CacheDir and save it on softCache
    public void saveBitmapToCache(String key, Bitmap bitmap) {
        if (bitmap != null) {

...

HomeListViewHolder:

public class HomeListViewHolder extends RecyclerView.ViewHolder {

    @Inject
    PictureDownloader mPictureDownloader;

    @BindView(R.id.image_character)
    ImageView mImageView;

    private View mItemView;
    private HomeListListener mListener;

    public HomeListViewHolder(View itemView, final HomeListListener listener) {
        super(itemView);
        ButterKnife.bind(this, itemView);
        this.mItemView = itemView;
        this.mListener = listener;
    }

    public void bindModel(final CharacterModel character) {
        mPictureDownloader.download(
            "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/shiny/",
            mImageView);

        mItemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (mListener != null) {
                    mListener.onCharacterClick(character);
                }
            }
        });
    }

MyApplication:

public class MarvelApplication extends DaggerApplication {

    @Inject
    PictureDownloader mPictureDownloader;

    @Override
    protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
        return DaggerAppComponent.builder().application(this).build();
    }

    public PictureDownloader getPictureDownloader(){
        return mPictureDownloader;
    }
}

Solution

  • Your viewholder is not part of the dagger graph, you should pass a donwloader reference through viewholder constructor instead from a instance that is part of dagger graph.

    public class HomeListViewHolder extends RecyclerView.ViewHolder {
    
        PictureDownloader mPictureDownloader;
    
        @BindView(R.id.image_character)
        ImageView mImageView;
    
        private View mItemView;
        private HomeListListener mListener;
    
        public HomeListViewHolder(View itemView, final HomeListListener listener, final  PictureDownloader pictureDownloader) {
            super(itemView);
            mPictureDownloader = pictureDownloader;
            ButterKnife.bind(this, itemView);
            this.mItemView = itemView;
            this.mListener = listener;
        }
        ...
    

    by the way you may remove these :

    public interface AppComponent extends AndroidInjector<MarvelApplication> {
        // PictureDownloader getPictureDownloader(); <-- useless
    
        ...
    }
    
    @Module
    public class PictureDownloaderModule {
        @Provides
        @Singleton
        CacheImageHandler providesCacheImageHandler(Context context) {
            return new CacheImageHandler(context);
        }
    
    
        // !!! Useless already added to the graph through constructor injection
        /*@Singleton
        PictureDownloader providesPictureDownloader(CacheImageHandler cacheImageHandler) {
            return new PictureDownloader(cacheImageHandler);
        }*/
    }