Consume Activity result directly in the ViewModel

Nikola Despotoski
2 min readMar 31, 2020

Most common implementation of Delegation pattern is when the responsibility of the class is delegated to a real object of a concrete implementation of the same interface.

class HomeAcrobat implements Acrobat {
private final Acrobat mProAcrobat = new CircusAcrobat();
@Override
public void doAmazingStuff(){
mProAcrobat.doAmazingStuff();
}
}

Kotlin gives amazing and neat way to implement Delegation pattern using the keyword by. This gives impression of having multiple inheritance, it is still a polymorphisms in a sense.

In activity-ktx:1.3.+, requesting and receiving results where taken to a new level with introduction of ActivityResultContract<I, O> and ActivityResultCallback. ActivityResultContract<I, O> is an interface that performs how and who will get the request for result, and ActivityResultCallback is how the consumer will consume the result.

But Google left us with ActivityResultContract abstract class which is the only obstacle we have to jump.

Consider we are advocates of separation of concerns and we want to take take the parsing of the result in another class.

You may notice the interface ActivityResultContractor<I, O>, this is extracted interface from ActivityResultContract.

With a minor tweak to the prepareCall() function, we can wrap our contractor to work as library providedActivityResultContract.

This function will be called from the Fragment or Activity, since they are only able to launch another Activity.

Our goal is to make the ViewModel be able to parse and receive the result. You may notice that now the ProductViewModelalso acts like a contractor but the parsing of the result is delegated to the activityResultContract using this syntax ActivityResultContractor<Nothing, String> by activityResultContractor.

Final call to the tweaked prepareCall() would be:

 chooseProductFilter.setOnClickListener {
prepareCall(productViewModel, productViewModel)
}

Another example of calling launch(), when the input type is not Unit:


textLiveData.observe(viewLifecycle){
prepareCall(productViewModel, productViewModel).launch(it)
}

Thank you and #StayAtHome!

--

--