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.

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

implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0-alpha01"
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

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