Google announced the architecture components with falls into the same category as Ti. It has some feature where ThirtyInch lacks behind: Composition and multiple shared ViewModels per Activity/Fragment. But we can change that.
This is the first draft showing a proof of concept. Names and API are very likely to be changed.
ThirtyInch vs Architecture Components ViewModels
I don't want to write a big comparison, here's just a small summary:
Both libs allow devs to move code out of Activities and Fragments to a place where you can execute code when the Activity changes configuration. Architecture Components ViewModels is very Googlely, meaning they are using retained fragments and the nonConfigurationInstance to retain state. ThirtyInch on the other hand moved way from those APIs, putting everything in a Singleton and cleanup when we get the correct callbacks from the system. This allows ThirtyInch to overcome the "Don't keep Activities" case, where the Activity will be destroyed but our Presenters survive because we know the Activity will come back.
Another major difference is that AC ViewModels provide data and can provide state, but only when the view asks for it. Without registering for events a Activity never receives events. This is completely different from a passive View which is often used in MVP. It makes testing hard because you can only test if single methods of the ViewModel behave correctly. You can't test if the view shows all relevant data or sends correct events.
For testability MVP (and therefore ThirtyInch) wins but requires some boilerplate code and learning to get started. AC ViewModels are easier to use but don't move a lot of logic out of Activities.
What the AC ViewModels do very well is composition. One doesn't have to extend a ViewModelActivity. Every AppCompatActivity can have multiple ViewModels. The same ViewModel instance can also be shared between Fragments and the hosting Activity.
Composition in ThirtyInch
ThirtyInch already allows composition using CompositeAndroid. Because of that we already have extracted all logic out of the Framework Activity and Fragment classes into our delegates.
With the latest additions in the support library (FragmentLifecycleCallbacks) and tons of bugfixes thanks to the Architecture Components project (included in 26.0.0+) we are now able to control the delegates only using callbacks from the support library. This allows us to bind Presenters to Activities and Fragments without extending TiActivity or using CompositeAndroid.
Once this PR is merged we can remove the plugin subproject. It's not required anymore. Users using ThirtyInch with CompositeAndroid can then add Presenters to their Activities with an equally simple API.
What's open
[ ] check if multiple Presenters per Activity are possible
[ ] check if multiple Presenters per Fragment are possible
[ ] Is it possible to share state between Fragments and it's host Activity?
Shared Presenters
I really like the idea of a shared state (aka ViewModel) between Fragments and it's host Activity. But it doesn't really fit in the MVP approach. Right now we have a 1:1 relationship between Presenter und View. I'm not sure if we can and should solve this.
Current implementation limitations
Right now we have to initialise a PresenterBinder in onCreate and pass in the savedInstanceState. But I'm sure we could work around this limitation like ViewModels did.
What can't be changed it that PresenterBinder cannot be initialised as a member variable:
Fragments don't have access to the Activity and the FragmentManager until Fragment#onAttach was called.
Activities don't have a callback before super.onCreate like Fragments do (onFragmentPreCreated) where we can get the savedInstanceState.
Fragments and Activities don't allow us to get the most recent savedInstanceState at any time. Users have to use a callback where it is available anyways.
The savedInstanceState contains a id of the Activity to detect "same" ones after a configuration change.
Google announced the architecture components with falls into the same category as
Ti
. It has some feature where ThirtyInch lacks behind: Composition and multiple shared ViewModels per Activity/Fragment. But we can change that.This is the first draft showing a proof of concept. Names and API are very likely to be changed.
ThirtyInch vs Architecture Components ViewModels
I don't want to write a big comparison, here's just a small summary:
Both libs allow devs to move code out of Activities and Fragments to a place where you can execute code when the Activity changes configuration. Architecture Components ViewModels is very Googlely, meaning they are using retained fragments and the nonConfigurationInstance to retain state. ThirtyInch on the other hand moved way from those APIs, putting everything in a Singleton and cleanup when we get the correct callbacks from the system. This allows ThirtyInch to overcome the "Don't keep Activities" case, where the Activity will be destroyed but our Presenters survive because we know the Activity will come back.
Another major difference is that AC ViewModels provide data and can provide state, but only when the view asks for it. Without registering for events a Activity never receives events. This is completely different from a passive View which is often used in MVP. It makes testing hard because you can only test if single methods of the ViewModel behave correctly. You can't test if the view shows all relevant data or sends correct events. For testability MVP (and therefore ThirtyInch) wins but requires some boilerplate code and learning to get started. AC ViewModels are easier to use but don't move a lot of logic out of Activities.
What the AC ViewModels do very well is composition. One doesn't have to extend a
ViewModelActivity
. EveryAppCompatActivity
can have multiple ViewModels. The same ViewModel instance can also be shared between Fragments and the hosting Activity.Composition in ThirtyInch
ThirtyInch already allows composition using CompositeAndroid. Because of that we already have extracted all logic out of the Framework Activity and Fragment classes into our delegates.
With the latest additions in the support library (FragmentLifecycleCallbacks) and tons of bugfixes thanks to the Architecture Components project (included in 26.0.0+) we are now able to control the delegates only using callbacks from the support library. This allows us to bind Presenters to Activities and Fragments without extending
TiActivity
or using CompositeAndroid.Once this PR is merged we can remove the
plugin
subproject. It's not required anymore. Users using ThirtyInch with CompositeAndroid can then add Presenters to their Activities with an equally simple API.What's open
Shared Presenters
I really like the idea of a shared state (aka ViewModel) between Fragments and it's host Activity. But it doesn't really fit in the MVP approach. Right now we have a 1:1 relationship between Presenter und View. I'm not sure if we can and should solve this.
Current implementation limitations
Right now we have to initialise a
PresenterBinder
in onCreate and pass in thesavedInstanceState
. But I'm sure we could work around this limitation like ViewModels did.What can't be changed it that
PresenterBinder
cannot be initialised as a member variable:Fragment#onAttach
was called.super.onCreate
like Fragments do (onFragmentPreCreated
) where we can get thesavedInstanceState
.The
savedInstanceState
contains aid
of the Activity to detect "same" ones after a configuration change.