1

I have the following implementation with dagger for Room Module. This causes an error on injecting the RoomMoule at the ViewModel class. Following is my Code:

App

class App : DaggerApplication(), HasActivityInjector {

@Inject
lateinit var activityDispatchInjector: DispatchingAndroidInjector<Activity>

override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
    return DaggerAppComponent.builder().create(this)
}


override fun activityInjector(): DispatchingAndroidInjector<Activity> {
    return activityDispatchInjector
}
}

AppModule

@Module
class AppModule {

@Provides
@Singleton
fun providesContext(app: Application): Context = app
}

RoomModule

@Module
class RoomModule {

@Singleton
@Provides
fun provideAppDatabase(context: Context): AppRoomDataBase =
        Room.databaseBuilder(context,
                AppRoomDataBase::class.java, "sample.db")
                .build()


@Singleton
@Provides

fun provideRepository(appRoomDataBase: AppRoomDataBase): ResultRepository {
    return ResultRepository(appRoomDataBase)
}    

}

AppComponent

@Singleton
@Component(modules = [
(AndroidSupportInjectionModule::class),
(AppModule::class),
(ActivityModule::class),
(FragmentModule::class),
(ViewModelModule::class),
(RoomModule::class)])
interface AppComponent : AndroidInjector<App> {

@Component.Builder
abstract class Builder : AndroidInjector.Builder<App>()
}

HomeViewModel

class HomeViewModel @Inject constructor() : ViewModel() {

@Inject lateinit var resultRepository: ResultRepository

private var liveList: LiveData<List<Result>>? = null

fun getResults(): LiveData<List<Result>>? {

     liveList = resultRepository.findAll()

    return liveList
  }
}

ResultRepository

class ResultRepository(appRoomDB : AppRoomDataBase) {

val mAppDb : AppRoomDataBase = appRoomDB

fun findAll(): LiveData<List<Result>> {
    return mAppDb.resultDao().getAll()
}
}

On building this i'm getting the error as

AppComponent.java:11: error: [dagger.android.AndroidInjector.inject(T)] 
android.app.Application cannot be provided without an @Inject constructor or 
from an @Provides-annotated method.
public abstract interface AppComponent extends 
dagger.android.AndroidInjector<com.dailypay.base.App> {
            ^
  android.app.Application is injected at
      com.dailypay.di.AppModule.providesContext(app)
  android.content.Context is injected at
      com.dailypay.di.RoomModule.provideAppDatabase(context)
  com.dailypay.room.AppRoomDataBase is injected at
      com.dailypay.di.RoomModule.provideRepository(appRoomDataBase)
  com.dailypay.repo.ResultRepository is injected at
      com.dailypay.ui.home.HomeViewModel.resultRepository
  com.dailypay.ui.home.HomeViewModel is injected at
      com.dailypay.di.ViewModelModule.bindMainViewModel(mainViewModel)
  java.util.Map<java.lang.Class<? extends android.arch.lifecycle.ViewModel>,javax.inject.Provider<android.arch.lifecycle.ViewModel>> is injected at
      com.dailypay.di.ViewModelFactory.<init>(creators)
  com.dailypay.di.ViewModelFactory is injected at
      com.dailypay.di.ActivityModule.bindViewModelFactory(factory)
  android.arch.lifecycle.ViewModelProvider.Factory is injected at
      com.dailypay.ui.home.HomeFragment.viewModelFactory
  com.dailypay.ui.home.HomeFragment is injected at
      dagger.android.AndroidInjector.inject(arg0)

:app:kaptDebugKotlin FAILED

FAILURE: Build failed with an exception.

LvN
  • 701
  • 1
  • 6
  • 22
  • 1
    Post your `ResultRepository` code....i guess you need to provide inject annoation on `ResultRepository` constructor – Burhanuddin Rashid Mar 26 '18 at 06:38
  • I think dagger doesn't know how to provide (where to find) context. Try add include param to your module: @Module(includes = arrayOf(ModuleWithMethodProvideContext::class)). – Cililing Mar 26 '18 at 06:53
  • @ Burhanuddin Rashid I tried with @inject constructor but i go the same error...BTW ResultRepository added – LvN Mar 26 '18 at 06:59
  • @LvN did you try this `class ResultRepository @Inject constructor(appRoomDB : AppRoomDataBase) {..`? – Raghunandan Mar 26 '18 at 07:02
  • @ Raghunandan yes I tried..Got the same error.. I believe some circle dependency occurs somewhere – LvN Mar 26 '18 at 07:05
  • In your `AppModule.providesContext(app)` you don't have access to a `android.app.Application` (I guess you're binding `YourCustomApplicatioin` instead, but you require a standard `Application` object) Fix the method argument to your type or also bind `Application` and it will work. Also please include the affected code _within_ your question (You did not include `AppModule`) – David Medenjak Mar 26 '18 at 10:28
  • Please also [see here](https://stackoverflow.com/q/44912080/1837367) for a detailed explanation. – David Medenjak Mar 26 '18 at 11:29
  • @ David Medenjak I've added AppModule code also i added the android.app.Application not my custom application class – LvN Mar 27 '18 at 04:31

2 Answers2

2

Your AppComponent is missing the @BindsInstance in the Builder.

@Component.Builder
interface Builder : AndroidInjector.Builder<App> {
    @BindsInstance Builder application(Application application);
    AppComponent build();
}
EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
  • I'm getting the following error ` @BindsInstance methods should not be included in @Components id you mean to put it in a @Component.Builder? public abstract dagger.android.AndroidInjector.Builder> application(@org.jetbrains.annotations.NotNull()` – LvN Mar 27 '18 at 04:56
  • 1
    Well as you can see, the `@BindsInstance` i have here is inside a `@Component.Builder`. – EpicPandaForce Mar 27 '18 at 19:19
0

I have provided simple room DB demo using dagger 2 used below code but it is java code you can convert into kotlin easily.

Step 1: Define pojo class for table and class define @Entity annotaion. Step 2: Define into that class into database class like below ...

@Database(entities = {Hero.class, User.class}, version = 1)
public abstract class DemoDatabase extends RoomDatabase {

    public abstract HeroDao getHeroDao();

    public abstract UserDao getUserDao();

}

Step 3: Define Module class for room db..

@Module
public class RoomDbModule {

    private DemoDatabase demoDatabase;

    public RoomDbModule(Application application) {
        demoDatabase= Room.databaseBuilder(application,DemoDatabase.class,"DemoDb").allowMainThreadQueries().build();
    }

    @Provides
    @Singleton
    DemoDatabase getDemoDatabase(){
        return demoDatabase;
    }
}

Step 4: Define Dao class ..

@Dao
public interface HeroDao {
    @Insert
    void insertRecord(Hero hero);
}

Step 5 : define commpoent class..

@Singleton
@Component(modules = {AppModule.class, NetModule.class, RoomDbModule.class, DbHelperModule.class})
public interface ApiComponent {
    void injectApi(MainActivity activity);

    void roomDb(InsertActivity insertActivity);

    void roomDb(PageingActivity pageingActivity);

    void dbHelper(AppCompatActivity appCompatActivity);
}

Step 6 : Define AppActivity as application level and pass into manifest file ...

public class AppActivity extends Application {
    private ApiComponent component;

    @Override
    public void onCreate() {
        super.onCreate();
        component = DaggerApiComponent.builder()
                .appModule(new AppModule(this))
                .roomDbModule(new RoomDbModule(this))
                .dbHelperModule(new DbHelperModule(new DbHelper(this, "UserDb", 1)))
                .netModule(new NetModule("https://api.github.com")).build();
    }

    public ApiComponent getComponent() {
        return component;
    }
}

and define in manifest file in application tag used below

        android:name=".app.AppActivity" // your activity name.

Step 7: Used Room db or inject.. provide full code for insert data into table using room.

public class InsertActivity extends BaseActivity {
    private EditText mEtName,mEtRealName,mEtTeamName;
    private Button mBtnInsert;

    @Inject
    DemoDatabase demoDatabase;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.insert_activity);
        ((AppActivity)getApplication()).getComponent().roomDb(this);
        initView();
    }

    private void initView() {
        mEtTeamName=findViewById(R.id.iaEtTeamName);
        mEtName=findViewById(R.id.iaEtName);
        mEtRealName=findViewById(R.id.iaEtRealName);
        mBtnInsert=findViewById(R.id.iaBtnInsert);
        mBtnInsert.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                insertData();
            }
        });
    }

    private void insertData() {
        Hero hero=new Hero();
        hero.setName(mEtName.getText().toString().trim());
        hero.setRealname(mEtRealName.getText().toString().trim());
        hero.setTeam(mEtTeamName.getText().toString().trim());
        demoDatabase.getHeroDao().insertRecord(hero);
        Toast.makeText(getApplicationContext(),"Insert Successfully",Toast.LENGTH_SHORT).show();
        mEtRealName.setText("");
        mEtName.setText("");
        mEtTeamName.setText("");

    }
}
SonhnLab
  • 321
  • 1
  • 11
  • when you need room db object and access any method for like insert,read etc that time @Inject annotation used for that class access. –  Mar 26 '18 at 06:57
  • 1
    I'm new to dagger - can someone explain why this has been downvoted? – Saik Caskey Jun 18 '18 at 12:02