Details on Sofa's internals - dextorer/Sofa GitHub Wiki
Prologue
Sofa is the result of my hacky, hacky solution on having custom fragments working alongside Leanback components. I have written 4 articles on this subject, but ever since the first one came out, I knew how unstable and unreliable it was. This wrong feeling kept adding up until I decided it was time to tidy things up and find a nicer solution to this very problem.
Structure
This is a rough schematics of Sofa's structure.
com.sgottard.sofa
.support
|- BrowseSupportFragment
|- RowsSupportFragment
|- HeadersSupportFragment
|- BaseRowSupportFragment
|- BaseSupportFragment
|- BrandedSupportFragment
|- BrowseFragment
|- RowsFragment
|- HeadersFragment
|- BaseRowFragment
|- BaseFragment
|- BrandedFragment
|- ContentFragment
As you can see, 6 Leanback classes (plus other 6 for the support version) had to be 'brutally' migrated to Sofa. However, 8 of them are untouched, and had to be imported only to avoid ugly hacks to access hidden components (such as Reflection). In particular:
BrowseFragment
(and, in turn,BrowseSupportFragment
) have been modified in several parts in order to allow custom content to be correctly loaded and handledRowsFragment
(and, in turn,RowsSupportFragment
) now only implement theContentFragment
interface, which I introduced to generalize the concept of 'custom content'; in addition, all the implemented methods are basically NOPs
Considerations
Sofa is built with two concepts in mind:
- Reuse as many Leanback components as possible, without modifying them
- Allow any kind custom content, up to a certain level
I started analyzing the Leanback source code to see if there was any way of extending the existing components (by using Java's inheritance) in order to fulfil the aforementioned requirements. Unfortunately, due to final methods and package-local visibility, I realized that this was not the way to go.
For this reason, I had to manually migrate the Leanback classes to Sofa (I obviously moved those that were strictly needed). I am aware that this solution is not suitable for several different reasons, but I am open to suggestions ;)