kotlin android app development course, fragment – view that acts like an activity

In Android app development, a fragment is a very important component. Fragments are modules that make up part of the user interface (UI) and can manage their own lifecycle independently. By using fragments, you can transition between different screens and create reusable UI components. This tutorial will explore how to utilize fragments using Kotlin in detail.

The Concept of Fragments

A fragment is a component that includes a small part of the UI within an activity. An activity represents a single screen that interacts with the user, but various fragments can be used to compose multiple UIs within a single activity. Fragments are very useful for the following reasons:

  • Reusable: The same fragment can be used in various activities.
  • Modular: Specific parts of the UI can be created as separate classes.
  • Flexibility: They can be added, removed, or replaced dynamically based on screen size and orientation.

The Lifecycle of Fragments

Fragments have their own lifecycle. The lifecycle of a fragment depends on the activity, but lifecycle methods are called independently. The main lifecycle methods of a fragment include:

  • onAttach(): Called when the fragment is attached to the activity.
  • onCreate(): Called to perform initialization tasks for the fragment.
  • onCreateView(): Called to create the UI for the fragment.
  • onActivityCreated(): Called after the activity’s creation is complete.
  • onStart(): Called when the fragment starts becoming visible to the user.
  • onResume(): Called when the fragment is interacting with the user.
  • onPause(): Called when the fragment stops interacting with the user.
  • onStop(): Called when the fragment is no longer visible to the user.
  • onDestroyView(): Called when the fragment’s UI is destroyed.
  • onDetach(): Called when the fragment is detached from the activity.

Creating a Basic Fragment

Now, let’s create a simple fragment using Kotlin. Start a new project and follow the steps below.

1. Create a Fragment Class

Create a Kotlin class for the fragment that inherits from Fragment. For example, let’s create a fragment named SampleFragment:

package com.example.myapp

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment

class SampleFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, 
        container: ViewGroup?, 
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout file to be used in the fragment.
        return inflater.inflate(R.layout.fragment_sample, container, false)
    }
}

2. Create a Layout File

Create a layout XML file used by the fragment. Write the res/layout/fragment_sample.xml file as follows:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/sampleTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello, Fragment!" />

</LinearLayout>

3. Use the Fragment in an Activity

Now the created fragment is ready to be used in an activity. Add a FrameLayout to the activity’s layout file to create space for the fragment:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <FrameLayout
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

4. Add the Fragment to the Activity

In the activity’s onCreate method, dynamically add the fragment:

package com.example.myapp

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.FragmentManager

class MainActivity : AppCompatActivity() {

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

        // Add the Fragment using FragmentManager.
        if (savedInstanceState == null) {
            val fragment = SampleFragment()
            supportFragmentManager.beginTransaction()
                .add(R.id.fragment_container, fragment)
                .commit()
        }
    }
}

Switching Between Fragments

Now let’s create multiple fragments and learn how to switch between them. As a simple example, we will implement a feature that switches to another fragment when a button is clicked.

1. Create a Second Fragment

Create a second fragment named SecondFragment and add a layout that includes a button:

package com.example.myapp

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import kotlinx.android.synthetic.main.fragment_second.*

class SecondFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, 
        container: ViewGroup?, 
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_second, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        // Switch the fragment on button click.
        button.setOnClickListener {
            val firstFragment = SampleFragment()
            fragmentManager?.beginTransaction()
                ?.replace(R.id.fragment_container, firstFragment)
                ?.addToBackStack(null)
                ?.commit()
        }
    }
}

2. Create a Layout File for the Second Fragment

Create the layout file for the second fragment as follows:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Back to Sample Fragment"/>

</LinearLayout>

3. Add Fragment Switching

In the existing SampleFragment, add a method for switching to the second fragment when a button is clicked:

class SampleFragment : Fragment() {
    // omitted...

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        // Switch to the second fragment on button click.
        val button = view.findViewById

Sending Data and Using Collections

Let’s learn how to transfer data between fragments and use collections. A common way to pass data to a fragment is by using a Bundle. In the example below, we will take user input for a search term and use it to create a new fragment.

1. Add EditText for User Input

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <EditText
        android:id="@+id/searchEditText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Enter search term"/>

    <Button
        android:id="@+id/searchButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Search"/>

</LinearLayout>

2. Write a Method to Pass the Search Term

Write a method to take the keyword input and pass it to the second fragment:

searchButton.setOnClickListener {
    val keyword = searchEditText.text.toString()
    val searchFragment = SearchFragment()
    
    // Use Bundle to pass data
    val bundle = Bundle()
    bundle.putString("keyword", keyword)
    searchFragment.arguments = bundle
    
    // Fragment switch
    fragmentManager?.beginTransaction()
        ?.replace(R.id.fragment_container, searchFragment)
        ?.addToBackStack(null)
        ?.commit()
}

3. Receive and Display the Data

Receive and display the data passed in SearchFragment:

class SearchFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, 
        container: ViewGroup?, 
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_search, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        // Receive data from Bundle
        val keyword = arguments?.getString("keyword")

        // Display data
        val textView = view.findViewById(R.id.resultTextView)
        textView.text = if (keyword != null) "Search term: $keyword" else "No search term entered."
    }
}

Managing Data with ViewModel and Fragments

Let’s learn how to manage data in fragments using ViewModel. ViewModel is a class that can store and manage UI-related data in activities and fragments, and is useful for maintaining data according to the lifecycle.

1. Create a ViewModel Class

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel

class MyViewModel : ViewModel() {
    val data: MutableLiveData = MutableLiveData()
}

2. Use ViewModel in the Fragment

Show how to create a ViewModel in the fragment and observe data to update the UI:

import androidx.fragment.app.activityViewModels

class SampleFragment : Fragment() {
    private val viewModel: MyViewModel by activityViewModels()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        // Observe data from ViewModel
        viewModel.data.observe(viewLifecycleOwner) { newData ->
            // Update UI
            textView.text = newData
        }

        // Change data to update UI
        button.setOnClickListener {
            viewModel.data.value = "New data"
        }
    }
}

Navigation with Fragments

Using the Android Navigation component, you can more easily manage transitions between fragments. The Navigation component simplifies transitions between fragments and activities.

1. Set Up Navigation Graph

Create a navigation graph and add fragments. Define transitions between fragments in the graph. This definition helps reduce code complexity and automatically handles transition animations and back stack management.

2. Switch Fragments Using Navigation Architecture

val navHostFragment = supportFragmentManager
        .findFragmentById(R.id.nav_host_fragment) as NavHostFragment
    val navController = navHostFragment.navController

    // Switch fragments on button click
    button.setOnClickListener {
        navController.navigate(R.id.action_sampleFragment_to_secondFragment)
    }

Conclusion

In this tutorial, we learned about the concept and usage of fragments in Android app development. Fragments allow us to structure the UI in a reusable and modular manner while managing lifecycles, transferring data, and leveraging ViewModels for data management. Using the navigation component makes switching between fragments easier. Based on this knowledge, try applying these concepts in real projects.

References