Search code examples
androiddagger

Dagger2, interface in presenter


I am learning dager2. And as for me i have not clear moment with interface and presenter. For example i have a project without dagger2.

MainActivity <- acitivty
MainView <- interface
MainPresenter <- class

I have realized interface MainView in MainActivity

MainActivity implements MainView {

   onCreate(///) {
       MainPresener mP = new MainPresenter(this)
        mp.getData() 
   }        

   @overirde // method from interface
    public void test(String test) {///}
}

My presenter

MainPresenter{
public void MainPresenter(MainView mainView) {///}

public void getData() {mainView.test("test")}
}

My interface

inreface MainView  {
public void test(String test)
}

----------------------------------------------------------

So, as for me everething is clear. When i used dagger2 i had a code like this:

interface UserView

interface UserView {
    fun setData(data: String)
}

for a test i created two module

@Module
class HelpersModule {

    @Provides
    fun provideUserHelper(): UserHelper {
        return UserHelper()
    }

    @Provides
    fun provideGeneralHelper(): GeneralHelpers {
        return GeneralHelpers()
    }

}

and

@Module
class UserModule {

    @Provides
    fun provideUserPresenter(userHelper: UserHelper,
                             generalHelpers: GeneralHelpers): UserPresenter {
        return UserPresenter(userHelper, generalHelpers)
    }

also i had AppComponent

@Component(modules = arrayOf(UserModule::class, HelpersModule::class))
@Singleton
interface AppComponent {
    // inject to ...

    // activities
    fun inject(activity: MainActivity)
}

My presenter

class UserPresenter(private val userHelper: UserHelper, private val generalHelpers: GeneralHelpers) {

    private  val TAG: String = UserPresenter::class.java.simpleName

    fun getUser() {
        Log.e(TAG, "getUser")

    }

}

My activity

class MainActivity : AppCompatActivity(), UserView {

    private var TAG: String = "MainActivity"

    @Inject
    lateinit var userPresenter: UserPresenter

    override fun onCreate(savedInstanceState: Bundle?) {
        // init app component, this activity
        App.appComponent.inject(activity = this@MainActivity)
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    override fun onResume() {
        super.onResume()
        userPresenter.getUser()
    }

    override fun setData(data: String) {
        Log.e(TAG, "data from presenter $data")
    }

}

My question: How i can call methods from interface UserView in UserPresenter like this:

    class UserPresenter(private val userHelper: UserHelper, private val generalHelpers: GeneralHelpers) {

        private  val TAG: String = UserPresenter::class.java.simpleName

        fun getUser() {
            Log.e(TAG, "getUser")
// call method from interface UserView, and display data in MainActivity
            userView.setData("Alex, ${userHelper.getDefAge()} ${generalHelpers.generalHelper()}")
        }

    }

Solution

  • You will have to inject your view into the presenter either by using the DI framework or by manually setting the view.

    Option 1

    class UserPresenter(private val userHelper: UserHelper, private val generalHelpers: GeneralHelpers) {
       private val TAG: String = UserPresenter::class.java.simpleName
       lateinit var userView: UserView 
    
       fun getUser() {
          Log.e(TAG, "getUser")
          userView.setData("Alex, ${userHelper.getDefAge()} ${generalHelpers.generalHelper()}")
       }
    }
    

    Call onCreate() in your Activity

    presenter.userView = this
    

    Option 2

    You will have to create another module preferably an interface or an abstract class to include in your UserModule. Dagger doesn't know how to provide the UserView, so we need to instruct the DI how-to. Change to Presenter's constructor:

    class UserPresenter(private val userHelper: UserHelper, private val generalHelpers: GeneralHelpers, private va userView: UserView ) {
       private val TAG: String = UserPresenter::class.java.simpleName
    
       fun getUser() {
          Log.e(TAG, "getUser")
          userView.setData("Alex, ${userHelper.getDefAge()} ${generalHelpers.generalHelper()}")
       }
    }
    
    @Module
    abstract class UserViewModule {
       @Binds
       abstract fun bindUserView(activity: MainActivity): UserView
    }
    
    ...
    // in your UserModule
    @Module(includes = [UserViewModule::class])
    class UserModule { 
    ...
    }
    

    I think you might be able to simplify the above using one module if Dagger knows how to provide the rest of presenter's dependencies. Get rid of UserModule in favor of UserViewModule.