Organizing an application based on multiple activities may not always be optimal. The Android OS world is quite fragmented and consists of many devices. And if for mobile devices with small screens the interaction between different activities looks pretty good, then on large screens - tablets, TVs, activity windows would not look very good due to the large screen size. That's why the concept of fragments appeared.
A fragment represents a piece of the application's visual interface that can be reused and reused. A fragment can have its layout file, fragments have their lifecycle. A fragment exists in the context of activity and has its life cycle; it cannot exist outside the activity in isolation. Each activity can have multiple fragments.
Fragments cannot live on their own-they must be hosted by activity or another fragment. The Fragment also has its life cycle:
Let’s create Fragment. To do this, we need to create layout files for them and classes with an ancestor androidx.fragment.app.Fragment
fragment1.xml:
<?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:background="#77ff0000"
android:orientation="vertical">
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Fragment 1">
</TextView>
</LinearLayout>
Fragment1.kt:
class Fragment1: Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
Log.e(TAG, "onCreateView: ")
return inflater.inflate(R.layout.fragment1, container, false)
}
}
In the onCreateView method, the system asks us what to display inside the fragment. We tell the system that we want to see the contents of the corresponding layout file in the fragment. To do this, we ourselves create a View using inflater and give it to the system. Those. in meaning, this is an analog of the setContentView method, which we call in the Activity. Only here do we have to create the View ourselves, and not just pass the layout file ID.
For interaction between fragments, the androidx.fragment.app.FragmentManager
class is used - a special fragment manager.
FragmentManager uses FragmentTransaction for adding, deleting, and other actions with a fragment to conduct a transaction
Before starting a transaction, you need to get an instance of FragmentTransaction via the FragmentManager.beginTransaction() method. Next, various methods are called to manage the fragments.
At the end of any transaction, which may consist of a chain of the above methods, the commit() method should be called.
val fragmentManager = supportFragmentManager
fragmentManager.beginTransaction()
.remove(fragment1)
.add(R.id.fragment_container, fragment2)
.show(fragment3)
.hide(fragment4)
.commit()
add()
Adds a fragment to an activity
remove() Removes a fragment from an activity
replace() Replaces one fragment with another
hide() Hides the fragment (makes it invisible on the screen)
show() Displays a hidden fragment on the screen
detach() (API 13) Detaches the fragment from the GUI, but the class instance is retained
attach() (API 13) Attaches a fragment that has been detached by the detach() method
Now we add the Fragment to Activity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val fragmentManager = supportFragmentManager
fragmentManager.beginTransaction()
.add(R.id.fragment_container, Fragment1())
.commit()
}
}
A fragment must have only one empty constructor with no arguments. But you can create a static newInstance with arguments via the setArguments() method.
class Fragment1 : Fragment() {
...
companion object {
private const val KEY = "VALUE_KEY"
fun newInstance(value: String) = Fragment1().apply {
arguments = Bundle().apply {
putString(KEY, value)
}
}
}
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val fragmentManager = supportFragmentManager
fragmentManager.beginTransaction()
.replace(R.id.fragment_container, Fragment1.newInstance("some text "))
.commit()
}
}
The arguments can be accessed in the onCreate() method of the fragment:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val text = requireArguments().getString(KEY, "")
}
Fragments, like activities, can be controlled by the Back button. You can add several fragments, and then use the Back button to return to the first fragment. If no fragments remain on the stack, then the next button press will close the activity.
To add a transaction to the stack, call the FragmentTransaction.addToBackStack(String) method before committing the transaction. The string argument is an optional name to identify the stack, or null. The FragmentManager class has a popBackStack() method that returns the previous stack state by that name.
val fragmentManager = supportFragmentManager
fragmentManager.beginTransaction()
.replace(R.id.fragment_container, Fragment1.newInstance("some text "))
.addToBackStack(null)
.commit()
If you call the addToBackStack() method when removing or replacing a fragment, then the fragment methods onPause(), onStop(), onDestroyView() will be called.
When the user presses the back button, the fragment methods onCreateView(), onActivityCreated(), onStart() and onResume() are called.
Let's consider an example of reacting to the Back button in a fragment without using the stack. The activity has an onBackPressed() method that responds to the button being pressed. We can refer to the desired fragment in this method and call it the fragment method.
The Fragment is a very interesting Android component and is quite easy to use and fast. I hope the article helped to understand the main points and how to use Fragment. In the first part of the article, I briefly talked about the main points on Fragments, in the next part of the article we will talk about the new Fragment API and its methods.