DEV Community

AhsanAhmed03
AhsanAhmed03

Posted on

Understanding Flows in Android: A Simple Guide with Examples

When building Android apps, you often deal with data that changes over time — like user input, API responses, or database updates. Handling these changes efficiently and reactively can be tricky. That’s where Kotlin Flows come in!

Kotlin Flows are a powerful tool for working with streams of data asynchronously. They’re part of Kotlin’s coroutines framework, designed to handle data that flows over time, making your code clean, efficient, and reactive.

What Are Flows?

Think of Flows as a stream of data that emits values over time. For example:

  • A flow might emit values when a database gets updated.
  • It could emit a new value every time a user enters text in a search bar.

Flows are cold by default, meaning they don’t start emitting values until they are collected. This makes them efficient since no work is done unless there’s a listener (collector).

Why Use Flows?

Simplify Asynchronous Tasks: Flows make it easier to handle data that updates over time without writing complex callback code.

Efficient & Reactive: They only do work when needed, saving resources.

Built for Coroutines: Since Flows are part of Kotlin’s coroutine library, they play well with other coroutine features like launch and async.

Flows in Android: Some Practical Examples

Imagine you want to fetch and display a list of items from a database that updates in real time. Here’s how you might use a Flow:

Steps:

  • Create a Fake Database with a method to return a Flow of items.
  • Use a Repository to provide the data from the fake database.
  • Collect the data in your ViewModel and expose it as a StateFlow or LiveData.
  • Observe the data in the Activity/Fragment
// Fake Database
object FakeDatabase {
    // Simulate fetching a list of items from a database
    fun getItems(): Flow<List<String>> = flow {
        emit(emptyList()) // Emit an empty list initially
        delay(1000) // Simulate a delay for fetching data
        emit(listOf("Item 1", "Item 2", "Item 3", "Item 4")) // Emit the actual list
    }
}
Enter fullscreen mode Exit fullscreen mode

Repository Implementation:

class FakeRepository {
    // Fetch items from the fake database
    fun fetchItems(): Flow<List<String>> = FakeDatabase.getItems()
}
Enter fullscreen mode Exit fullscreen mode

ViewModel Implementation:

class ItemViewModel : ViewModel() {
    private val repository = FakeRepository()

    // StateFlow to hold the list of items
    private val _items = MutableStateFlow<List<String>>(emptyList())
    val items: StateFlow<List<String>> get() = _items

    init {
        fetchItems()
    }

    private fun fetchItems() {
        viewModelScope.launch {
            repository.fetchItems().collectLatest { fetchedItems ->
                _items.value = fetchedItems
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Activity/Fragment Implementation

class MainActivity : AppCompatActivity() {

    private val viewModel: ItemViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Collect items and update the RecyclerView adapter
        lifecycleScope.launch {
            viewModel.items.collectLatest { items ->
                Log.d("LOG_TAG","Data from Database: $items")
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Key Points in This Example:

  • Fake Database: Provides data using a Flow. Simulates asynchronous fetching.
  • Repository: Acts as a bridge between the database and ViewModel.
  • ViewModel: Uses a StateFlow to expose the fetched data.
  • Activity/Fragment: Collects the StateFlow and print it on logcat

Monitor network connection Using Flows

Steps:

  • Use ConnectivityManager to monitor the network connection.
  • Create a Flow to emit connection status updates.
  • Collect the Flow in your activity or fragment and show the toast accordingly.

Code Implementation:

// Create a Flow to emit internet connectivity status
    fun observeNetworkStatus(context: Context): Flow<Boolean> = callbackFlow {
        val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager

        val networkCallback = object : ConnectivityManager.NetworkCallback() {
            override fun onAvailable(network: Network) {
                trySend(true) // Emit 'true' when connected
            }

            override fun onLost(network: Network) {
                trySend(false) // Emit 'false' when disconnected
            }
        }

        // Register network callback
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            connectivityManager.registerDefaultNetworkCallback(networkCallback)
        } else {
            val networkRequest = android.net.NetworkRequest.Builder()
                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                .build()
            connectivityManager.registerNetworkCallback(networkRequest, networkCallback)
        }

        awaitClose {
            // Unregister callback when Flow collection is canceled
            connectivityManager.unregisterNetworkCallback(networkCallback)
        }
    }.distinctUntilChanged(
Usage in an Activity or Fragment:

// Observe network status and show toast
        lifecycleScope.launch {
            observeNetworkStatus(this@MainActivity).collectLatest { isConnected ->
                val message = if (isConnected) {
                    "Internet Connected"
                } else {
                    "Internet Disconnected"
                }
                Toast.makeText(this@MainActivity, message, Toast.LENGTH_SHORT).show()
            }
        }
Enter fullscreen mode Exit fullscreen mode

Conclusion

Kotlin Flows make managing asynchronous data streams a breeze. They simplify your code, eliminate callback hell, and make your apps more reactive. Whether you’re handling user interactions or real-time updates, Flows are a go-to solution for modern Android development.

Start exploring Flows today and take your Android apps to the next level!

Feel free to reach out to me with any questions or opportunities at (aahsanaahmed26@gmail.com)
LinkedIn (https://www.linkedin.com/in/ahsan-ahmed-39544b246/)
Facebook (https://www.facebook.com/profile.php?id=100083917520174).
YouTube (https://www.youtube.com/@mobileappdevelopment4343)
Instagram (https://www.instagram.com/ahsanahmed_03/)

Top comments (0)