12. Using Fragments

A fragment is a modular section of an activity, it represents a particular operation or interface that is running within a larger Activity. Fragment defines its own lifecycle, however that lifecycle is dependent on its activity.

The advantages of fragments are as follows:

  • Modularity: Instead of writing all the code in one Activity, we can separate out the code for distinct parts of the UI into different fragments

  • Reusability: Fragments encapsulate views and logic so that it is easier to reuse these views and logic within activities

  • Adaptability: Depending on the screen size of the hardware and the orientation of the screen, different layouts can be easily implemented, hence user experience is better

The core series of lifecycle methods that are called to bring a fragment up to resumed state are:

  1. onAttach(Activity): called once the fragment is associated with its activity.

  2. onCreateView(LayoutInflater, ViewGroup, Bundle): creates and returns the view hierarchy associated with the fragment.

  3. onActivityCreated(Bundle): tells the fragment that its activity has completed its own Activity onCreate.

  4. onViewStateRestored(Bundle): tells the fragment that all of the saved state of its view hierarchy has been restored.

  5. onStart(): makes the fragment visible to the user.

  6. onResume(): makes the fragment begin interacting with the user.

When a fragment is no longer being used, it goes through a reverse series of callbacks:

  1. onPause(): fragment is no longer interacting with the user either because its activity is being paused or a fragment operation is modifying it in the activity.

  2. onStop(): fragment is no longer visible to the user either because its activity is being stopped or a fragment operation is modifying it in the activity.

  3. onDestroyView(): allows the fragment to clean up resources associated with its View.

  4. onDestroy(): called to do final cleanup of the fragment’s state.

  5. onDetach(): called immediately prior to the fragment no longer being associated with its activity.

12.1. Create Fragments

  1. Create a new empty project, and remove the Hello World TextView in activity_main.xml.

  2. Add a button to the layout and change Text to “Change Fragment”. Then add a FrameLayout with id = “fragment_holder”.

  3. Create a new Kotlin file under same folder as MainActivity, name it FirstFragment. Override all functions in the fragment’s life cycle:

    class FirstFragment : Fragment(){
    
      override fun onAttach(context: Context?) {
        super.onAttach(context)
      }
      override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
      }
      override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return super.onCreateView(inflater, container, savedInstanceState)
      }
        override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
      }
        override fun onStart() {
        super.onStart()
      }
        override fun onResume() {
        super.onResume()
      }
        override fun onPause() {
        super.onPause()
      }
        override fun onStop() {
        super.onStop()
      }
        override fun onDestroy() {
        super.onDestroy()
      }
        override fun onDetach() {
        super.onDetach()
      }
    }
    
  4. Create a new layout resource file, with Root element is RelativeLayout and File Name is first_fragment. Then add a TextView at center of the design and change Text to “First Fragment”.

  5. Go back to FirstFragment.kt, in onCreateView function, rewrite return to the following:

    return inflater.inflate(R.layout.first_fragment,container,false)
    

    Then, create a val to represent FirstFragment such as:

    val f = "FIRST"
    

    And add a Log to every function, when the app runs, it will show the functions that `FirstFragment called, which will provide a clearer view of a fragment’s lifecycle. Write the following code to all functions:

    Log.d(f, "functionName")
    
  6. Duplicate FirstFragment.kt to SecondFragment.kt and first_fragment.xml to second_fragment.xml. Then change any references to “first” in the code to “second”.

12.2. Use and Swap Between Fragments

  1. In MainActivity.kt, declare the following variables:

    var isFirstFragmentLoaded = true
    val manager = supportFragmentManager
    

    In onCreate function, declare a variable:

    val change_fragment = findViewById<Button>(R.id.button)
    
  2. Create a function called showFirstFragment() under MainActivity and write the following code which will load FirstFragment:

    val transaction = manager.beginTransaction()
    val fragment = FirstFragment()
    transaction.replace(R.id.fragment_holder,fragment)
    transaction.addToBackStack(null)
    transaction.commit()
    isFirstFragmentLoaded = true
    

    Then duplicate the function to showSecondFragment() with some changes in the code:

    ...
    val fragment = SecondFragment()
    ...
    isFirstFragmentLoaded = false
    
  3. Now go back to onCreate function and set up a setOnClickListener. Whenever the button is clicked, switch to another Fragment. The App starts with FirstFragment.

    showFirstFragment()
    
    change_fragment.setOnClickListener({
      if (isFirstFragmentLoaded) {
        showSecondFragment()
      }
      else {
        showFirstFragment()
      }
    })
    
  4. Now install and run the app. It should look like the pictures below on the Lenovo tablet.

    ../_images/fragment_screenshot.jpg
  5. Under Run at the bottom of Android Studio, you should see the following:

    When the app starts:

    ../_images/runApp.jpg

    When the click the button once:

    ../_images/swapToSecond.jpg

    When click the button another time:

    ../_images/swapToFirst.jpg