Breaking News Fragment

Learn how to load data to our fragments from the ViewModel

We'll cover the following...

Understanding the breaking news fragment

In this fragment, a list of articles is loaded into a RecyclerView. The adapter has an onClick listener set on the articles so that when an item is clicked, a WebView is opened within the application where the user can read the article.

The fragment has been optimized with various features to improve the application’s data handling, performance, and efficiency. These features include using ViewBinding and coroutines. These technologies help to improve the structure and organization of the code, as well as the efficiency and speed of the application. Let’s break it down for better comprehension.

Press + to interact
package com.example.ui.fragments
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AbsListView
import android.widget.Adapter
import android.widget.Toast
import androidx.activity.viewModels
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.newsapplication.R
import com.example.newsapplication.databinding.FragmentBreakingNewsBinding
import com.example.newsapplication.db.ArticleDatabase
import com.example.newsapplication.repository.NewsRepository
import com.example.newsapplication.util.Constants.Companion.QUERY_PAGE_SIZE
import com.example.newsapplication.util.Resource
import com.example.newsapplication.viewModel.NewsViewModel
import com.example.newsapplication.viewModel.NewsViewModelProvider
import com.example.ui.activities.NewsActivity
import com.example.ui.adapters.NewsAdapter
class BreakingNewsFragment : Fragment(R.layout.fragment_breaking_news) {
lateinit var viewModel: NewsViewModel
lateinit var newsAdapter: NewsAdapter
private lateinit var binding: FragmentBreakingNewsBinding
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentBreakingNewsBinding.bind(view)
setUpRecyclerView(binding)
val newsRepository = NewsRepository(ArticleDatabase(requireContext() as NewsActivity))
val viewModelProviderFactory =
NewsViewModelProvider(activity?.application!!, newsRepository)
viewModel = ViewModelProvider(this, viewModelProviderFactory).get(NewsViewModel::class.java)
newsAdapter.setOnItemClickListener {
val bundle = Bundle().apply {
putSerializable("article", it)
}
findNavController().navigate(
R.id.action_breakingNewsFragment2_to_articleFragment,
bundle
)
}
viewLifecycleOwner.lifecycleScope.launchWhenStarted {
viewModel.getBreakingNews.collect {
newsAdapter.differ.submitList(it?.data)
it ?: return@collect
showProgressBar(binding)
when (it.status) {
Resource.Status.SUCCESS -> {
hideProgressBar(binding)
hideErrorMessage()
Toast.makeText(activity, "Success", Toast.LENGTH_LONG).show()
}
Resource.Status.LOADING -> {
Toast.makeText(
activity,
"Wait for data. Data is loading...",
Toast.LENGTH_LONG
).show()
}
Resource.Status.ERROR -> {
showErrorMessage("Sorry!!!,Something went wrong")
}
Resource.Status.FAILURE -> {
showErrorMessage("Sorry!!!,Something went terribly wrong")
}
}
}
}
}
override fun onStart() {
super.onStart()
viewModel.onStart()
Toast.makeText(activity, "start", Toast.LENGTH_LONG).show()
}
private fun hideProgressBar(binding: FragmentBreakingNewsBinding) {
binding.paginationProgressBar.visibility = View.INVISIBLE
}
private fun showProgressBar(binding: FragmentBreakingNewsBinding) {
binding.paginationProgressBar.visibility = View.VISIBLE
}
private fun hideErrorMessage() {
binding.itemErrorMessage.visibility = View.INVISIBLE
}
private fun showErrorMessage(message: String) {
binding.itemErrorMessage.visibility = View.VISIBLE
binding.errorMessage.text = message
}
private fun setUpRecyclerView(binding: FragmentBreakingNewsBinding) {
newsAdapter = NewsAdapter()
binding.breakingNewsRecyclerView.apply {
adapter = newsAdapter
layoutManager = LinearLayoutManager(activity)
}
}
}

In the below code snippet, we declare class variables as references to the NewsAdapter and the ViewBinding classes.

All three variables are marked with the lateinit keyword. This means that the variables will be initialized later in the code, but they don’t have to be initialized when they’re declared.

lateinit var viewModel: NewsViewModel
    lateinit var newsAdapter: NewsAdapter
    private lateinit var binding: FragmentBreakingNewsBinding
    private val TAG = "BreakingNewsFragment"

We use ViewBinding to bind the views with the Android data ...