This text provides a comprehensive guide on how to use Flow with Retrofit in Android development using Kotlin, including step-by-step instructions and code examples.
Abstract
The article is a complete guide on how to use Flow with Retrofit in Android development using Kotlin. It begins by listing the necessary dependencies and plugins required for the project, followed by adding permissions to the AndroidManifest.xml file. The guide then covers creating layout XML files, packages, model classes, API services, and repository classes. It also explains how to create a ViewModel class and an adapter, and how to work with HomeFragment and MainActivity. The article concludes by providing a link to the GitHub source code and encouraging readers to join Medium to read more valuable stories.
Opinions
The author believes that using Flow with Retrofit provides a more scalable and maintainable way of handling data fetching in an application.
The author suggests that using a repository class can help shield the data for a UI controller and keep the data intact through configuration adjustments.
The author recommends using a Diff Util callback to manage the differences between two lists in an adapter.
The author encourages readers to use extension functions to simplify code and improve readability.
The author emphasizes the importance of managing the result of a request in a ViewModel and observing the changes in the UI.
The author suggests that using a ViewModel can help manage the lifecycle of an activity or fragment and prevent data loss.
The author recommends using a navigation controller to handle navigation events and update the app bar title and navigation icon based on the current destination.
How to use Flow with Retrofit (Complete Guide — Part 1)
In some previous articles we discussed fundamentals of Flow API and also using it in Room Database in Kotlin , Here is the list of those articles :
if you know nothing about how to work with response and how it can be created , please read this article [or video] first , 7th Step of this article can help you better understand what is response and how you can create :
I want to create this repository class because I don’t want to use my ApiServices’s function directly. The repository class provides information for me. And it needs to @Inject ApiServices here in the constructor to define these functions here like these :
Here , I provided a suspending function that returns a Flow which emits DataStatus objects representing the current state of the data being fetched from an API . The DataStatus object contains information such as loading, success or error state.
The reason for handling the Flow in this way is to provide a more robust and flexible way of handling data fetching in our application. By using a Flow, you can easily switch between different data sources or implement caching strategies without modifying the calling code. Additionally, Flow allows for easy transformation and manipulation of data, making it ideal for use in a reactive programming model.
Overall, using a Flow in this way provides a more scalable and maintainable way of handling data fetching in our application.
Step 9 — Create a ViewModel class
We should divide our business logic from the UI logic. The ViewModel is used for that, with the intent of shielding the data for an UI controller so the data can stay intact through configuration adjustments.
2-The library that I used for showing our data on Chart , just accept the pair of <String ,Float> and the response for this chart that came from the API is Double, so I should convert these data into <String ,Float> , so I wrote this extension function :
fun List<Double?>?.toDoubleFloatPairs(): List<Pair<String, Float>> {
returnthis!!.map { d ->
val f = d!!.toFloat()
val s = d.toString()
Pair(s, f)
}
}
viewModel.coinsList.observe(viewLifecycleOwner) {
when (it.status) {
DataStatus.Status.LOADING -> {
//show loading before load data
pBarLoading.isVisible(true,rvCrypto)
}
DataStatus.Status.SUCCESS -> {
//here the request was success and we have our list//and can submith the data into our differ
pBarLoading.isVisible(false,rvCrypto)
cryptosAdapter.differ.submitList(it.data)
}
DataStatus.Status.ERROR -> {
pBarLoading.isVisible(true,rvCrypto)
Toast.makeText(requireContext(), "There is something wrong!", Toast.LENGTH_SHORT).show()
}
}
}
and also I created a fun for managing my recyclerview :
Here, we just need to find the navigation controller associated with the fragmentContainerView in the current activity, which is where the app's navigation will take place.
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.homeFragment,
R.id.detailsFragment
)
)
In this step, i just create an instance of the AppBarConfiguration class, which specifies the top-level destinations in the app's navigation graph that should be considered "top-level" destinations. and set our fragment here.
And here, I set up the navigation controller with the app’s action bar, allowing the app bar to automatically update its title and navigation icon based on the current destination of the navigation controller.
Last step , i should handle navigation events when the user presses the back button in the app bar. When this button is pressed, the navigateUp() method is called on the NavController to handle the navigation event.