How to show generic list in Fragment in Android

Issue #378

After having a generic RecyclerView, if we want to show multiple kinds of data in Fragment, we can use generic.

We may be tempted to use interface or protocol, but should prefer generic.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class FeedFragment() : Fragment() {
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)

val mainViewModel: MainViewModel = ViewModelProviders.of(activity!!).get(MainViewModel::class.java)
mainViewModel.resId.observe(viewLifecycleOwner, Observer {
when (it) {
R.id.gitHub -> { handleGitHub() }
R.id.hackerNews -> { handleHackerNews() }
R.id.reddit -> { handleReddit() }
R.id.dev -> { handleDev() }
R.id.productHunt -> { handleProductHunt() }
else -> {}
}
})

recyclerView.layoutManager = LinearLayoutManager(context)
}
}

The difference between each kind are

  • The type of model
  • The type of Adapter
  • How to observe from viewModel
  • How to load from viewModel

Here we also use lifecycleScope from lifecycle runtime ktx

1
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0-alpha01"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private fun <T> handle(
makeResId: () -> Int,
makeAdapter: () -> com.myapp.Adapter<T>,
observe: ((ArrayList<T>) -> Unit) -> Unit,
load: suspend () -> Unit
) {
(activity as AppCompatActivity).toolbar.title = getString(makeResId())
val adapter = makeAdapter()
recyclerView.adapter = adapter
observe {
adapter.update(it)
}
fun doLoad() {
viewLifecycleOwner.lifecycleScope.launch {
progressBar.visibility = View.VISIBLE
load()
progressBar.visibility = View.GONE
swipeRefreshLayout.isRefreshing = false
}
}
doLoad()
swipeRefreshLayout.setOnRefreshListener {
doLoad()
}
}

Then we just need to provide the required data

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private fun handleDev() {
val viewModel: com.myapp.ViewModel by viewModel()
handle(
{ R.string.menu_dev },
{ com.myapp.Adapter(items = arrayListOf()) },
{ completion ->
viewModel.items.observe(viewLifecycleOwner, Observer {
completion(it)
})
},
{
viewModel.load()
}
)
}

Read more

Comments