https://kotlinlang.org logo
o

Ofir Bar

03/11/2020, 5:25 PM
Hey guys, Can anyone please post a short code example for the part marked in red? I didn’t understand what the author meant by “Presenter” and “the same scope as the view model”. Of course I can search for that on Google but I would like to get a code example exactly for the context marked in Red Source: https://medium.com/androiddevelopers/viewmodels-and-livedata-patterns-antipatterns-21efaef74a54
s

satyan

03/11/2020, 5:35 PM
In pseudo code:
Copy code
FeatureViewModel @Inject(
  private val subFeatureAPresenter: subFeatureAPresenter,
  private val subfeatureBPresenter: subfeatureBPresenter
) {

    fun onAction(action: Action) {
      if (action is related to subFeatureAPresenter) {
        val change = subFeatureAPresenter.action(action)
        // handle change
      }
      if (action is related to subFeatureBPresenter) {
        val change = subFeatureBPresenter.action(action)
        // handle change
      }
    }
}
👍 1
a

Anastasia Finogenova

03/12/2020, 1:13 AM
Consider moving your business logic to UseCase/Interactor instead. So your ViewModel will keep the presentation logic and the Interactor will have no knowledge of Android classes and be easily unit tested. Inject those Interactors into the ViewModel for better testability
👍 1
s

Samuel Michael

03/12/2020, 5:00 AM
Copy code
class AddCreditCardPresenter @Inject constructor(
    private val interactor: AddCreditCardContract.Interactor
) : AddCreditCardContract.Presenter {
    private var view: AddCreditCardContract.View? = null

    init {
        interactor.setPresenter(this)
    }

    override fun onViewAttached(view: AddCreditCardContract.View, router: AddCreditCardContract.Router) {
        this.view = view
        interactor.onRouterAttached(router)
        interactor.onLifeCycleStarted { view as Fragment }

        if (view.isEmpty()) {
            interactor.loadData()
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        interactor.onActivityResult(requestCode, resultCode, data)
    }

    override fun onViewDetached() {
        view = null
        interactor.onRouterDetached()
    }

    override fun onBackPressed() {
        interactor.onBackPressed()
    }

    override fun onDestroyed() {
        interactor.onDestroyed()
    }

    override fun onDataLoaded(dataModel: AddCreditCardDataModel) {
        view?.let { view ->
            view.addCreditCardNumber(dataModel.creditCardNumber)
            view.addExpiration(dataModel.expiryDate)
            view.addCvv(dataModel.securityCode)
            view.addNameOnCard(dataModel.nameOnCard)

            view.addSelectedAddress(SelectedAddressViewModel(dataModel.selectedAddress, this))

            dataModel.saveButton.buttonClickListener = Form(
                    mutableListOf(dataModel.creditCardNumber, dataModel.expiryDate, dataModel.securityCode, dataModel.nameOnCard)
            ) {
                interactor.saveCard()
            }

            view.addSaveButton(dataModel.saveButton)
            view.showKeyboard()
            view.topmostViewLoaded()
        }
    }

    override fun hideSoftKeyboard() {
        view?.hideSoftKeyboard()
    }

    override fun showLoadingIndicator() {
        view?.showLoadingIndicator()
    }

    override fun hideLoadingIndicator() {
        view?.hideLoadingIndicator()
    }

    override fun onBillingAddressClick() {
        view?.hideKeyboard()

        interactor.goToSelectBillingAddress()
    }
}
s

satyan

03/12/2020, 7:58 AM
The interactor/use case shouldn’t contains the presenter instance and be aware of the view’s lifecycle. This is presentation logic. I think usecases / interactors should only have start/dispose event to handle their lifecycle and dispatch responses using either the concurrency method of your liking (coroutines, RXJava, callbacks on executors or whatever).
1
j

Jeremy

03/13/2020, 7:00 PM
Yes or ideally just expose cold observables and avoid the start/dispose
o

Ofir Bar

03/14/2020, 1:35 PM
In my project I am doing MVVM, as a junior dev all the terminiology I am aware of includes: LifeCycles(Activity/Fragment), ViewModel, Repositories and Models (data classes for POJO/POKO or REST data classes). I have never heard terms like: interactor, usecases, presenter, contract, cold observables with start/dispose. So I assume the terms mentioned here are a part of bigger architecture standard or something? can anyone point me as to where all these terms comes from? Is that relevant to MVVM or the terms assumed I used MVP? @satyan @Jeremy @Anastasia Finogenova @Samuel Michael
a

Anastasia Finogenova

03/14/2020, 1:53 PM
So when people say Presenter I think it is a term related to MVP, I don't think it is a standard term for MVVM. UseCase aka Interactor is coming from clean architecture. So it is a layered architecture pattern to achieve testability and decoupling. Both MVP and MVVM are takes on the clean architecture. Just Google what is usecase in clean architecture. For observables it is reactive pattern terms, people meant using RxJava but you don't have to. Interactor should not be aware of implementation details imo like rx or coroutines.
👍 2
o

Ofir Bar

03/14/2020, 2:22 PM
Thank you @Anastasia Finogenova
j

Jeremy

03/14/2020, 2:23 PM
Yep. Observable is just a callback. In Kotlin you can just pass in a lambda if you want to avoid depending on a specific lib
3 Views