Server Side Layouting is an idea where client, like Android, can render a markup file to a native view.
Similar to how HTML is rendered nicely on browser, regardless of the browser's operating system.
This repository is a proof of concept that we can render a markup file (JSON) to Android's RecyclerView.
I tried to make the code as agnostic as possible so that you can apply it in your project.
In order to improve clarity, I use a fictional news reading app use case that has different type of view.
Such as divider and the article for the news in the form of grid and list.
Convert this JSON:
[
{
"layoutType": "DIVIDER",
"data": {}
},
{
"layoutType": "LIST",
"data": {
"articleList": [
{
"articleHash": "articleHash",
"articleId": 0,
"commentCount": 0,
"publishTime": 0,
"publisher": "publisher",
"thumbnailHash": "thumbnail hash",
"title": "Title 1"
},
{
"articleHash": "articleHash",
"articleId": 0,
"commentCount": 0,
"publishTime": 0,
"publisher": "publisher",
"thumbnailHash": "thumbnail hash",
"title": "Title 2"
},
{
"articleHash": "articleHash",
"articleId": 0,
"commentCount": 0,
"publishTime": 0,
"publisher": "publisher",
"thumbnailHash": "thumbnail hash",
"title": "Title 3"
},
{
"articleHash": "articleHash",
"articleId": 0,
"commentCount": 0,
"publishTime": 0,
"publisher": "publisher",
"thumbnailHash": "thumbnail hash",
"title": "Title 4"
}
],
"title": "#title"
}
},
{
"layoutType": "DIVIDER",
"data": {}
},
{
"layoutType": "GRID",
"data": [
{
"articleHash": "articleHash",
"articleId": 0,
"commentCount": 0,
"publishTime": 0,
"publisher": "publisher",
"thumbnailHash": "thumbnail hash",
"title": "Title 1"
},
{
"articleHash": "articleHash",
"articleId": 0,
"commentCount": 0,
"publishTime": 0,
"publisher": "publisher",
"thumbnailHash": "thumbnail hash",
"title": "Title 2"
},
{
"articleHash": "articleHash",
"articleId": 0,
"commentCount": 0,
"publishTime": 0,
"publisher": "publisher",
"thumbnailHash": "thumbnail hash",
"title": "Title 3"
},
{
"articleHash": "articleHash",
"articleId": 0,
"commentCount": 0,
"publishTime": 0,
"publisher": "publisher",
"thumbnailHash": "thumbnail hash",
"title": "Title 4"
}
]
}
]To this:
@Test
fun jsonToViewItem() {
// Given
val json = ResponseJson.get()
val repository = ViewItemStubRepository()
// When
val viewItems = repository.getViewItems(json)
// Then - Correct View Item
assertTrue(viewItems.first() is DividerViewItem)
assertTrue(viewItems[1] is ListViewItem)
assertTrue(viewItems[2] is DividerViewItem)
assertTrue(viewItems[3] is GridViewItem)
// Then - Correct Data Type 1
val listViewItem = viewItems[1] as ListViewItem
assertTrue(listViewItem.title == "#title")
assertTrue(listViewItem.articleList.first().title == "Title 1")
// Then - Correct Data Type 2
val gridViewItem = viewItems[3] as GridViewItem
assertTrue(gridViewItem.articleList.first().title == "Title 1")
}
@Test
fun screenSectionListToViewItem() {
// Given
val screenSectionList = StubResponseCreator.getScreenSectionList()
val repository = ViewItemStubRepository()
// When
val viewItems = repository.convertScreenSectionToViewItem(screenSectionList)
// Then - Correct View Item
assertTrue(viewItems.first() is DividerViewItem)
assertTrue(viewItems[1] is ListViewItem)
assertTrue(viewItems[2] is DividerViewItem)
assertTrue(viewItems[3] is GridViewItem)
// Then - Correct Data Type 1
val listViewItem = viewItems[1] as ListViewItem
assertTrue(listViewItem.title == "#title")
assertTrue(listViewItem.articleList.first().title == "Title 1")
// Then - Correct Data Type 2
val gridViewItem = viewItems[3] as GridViewItem
assertTrue(gridViewItem.articleList.first().title == "Title 1")
}data class ScreenSection(
val layoutType: ScreenSectionLayoutType,
val data: Any = Any()
)
enum class ScreenSectionLayoutType {
DIVIDER,
LIST,
GRID
}
@VisibleForTesting
fun convertScreenSectionToViewItem(screenSectionList: List<ScreenSection>): List<ViewItem> {
return screenSectionList.map { section ->
when (section.layoutType) {
ScreenSectionLayoutType.DIVIDER -> DividerViewItem()
ScreenSectionLayoutType.GRID -> getGridViewItem(section.data)
ScreenSectionLayoutType.LIST -> getListViewItem(section.data)
}
}
}
private fun getGridViewItem(data: Any): GridViewItem {
return GridViewItem(
articleList = data as List<ArticleResponse>
)
}
private fun getListViewItem(data: Any): ListViewItem {
val titleAndArticlesResponse: TitleAndArticlesResponse = data as TitleAndArticlesResponse
return ListViewItem(
title = titleAndArticlesResponse.title,
articleList = titleAndArticlesResponse.articleList
)
}