0

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;
    }
}
  • Please [have a look here](https://stackoverflow.com/a/50270376/1837367). You're neither doing constructor injection, nor field injection and you could remove all the `@Inject` other than the single one in `MarvelApplication `. Please read carefully and make sure to understand when and how to use `@Inject` – David Medenjak May 17 '18 at 18:00
  • Thank you I have read the link but the only way that I see It's going to work is Injecting that class (PictureDownloader) into my Fragment and pass this into the constructor of my adapter and later into the constructor of my ViewHolder. Is there another way to do it? – Martin Rico Martinez May 18 '18 at 06:45

1 Answers1

2

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);
    }*/
}
Samuel Eminet
  • 4,647
  • 2
  • 18
  • 32
  • 1
    So I have to Inject from my fragment the PictureDownloader and pass this object into the contructor of my adapter and later of the contructor of my ViewHolder? Or is there another way to do it? Thanks for your help! – Martin Rico Martinez May 18 '18 at 06:42
  • 1
    Yes, you usually don't inject view/viewholder (this isn't recommanded if you search from dagger github, though it can be done https://gist.github.com/ronshapiro/af99799fe9dd7ec412f2d4e45b843370 or http://frogermcs.github.io/inject-everything-viewholder-and-dagger-2-example/), you pass injected dependencies from you controller (fragment/activity/...) to your view – Samuel Eminet May 18 '18 at 09:37