Каждый класс фрагмента наследуется от базового класса Fragment и имеет свой жизненный цикл, состоящий из ряда этапов:
Каждый этап жизненного цикла описывается одной из констант перечисления Lifecycle.State:
INITIALIZED
CREATED
STARTED
RESUMED
DESTROYED
Стоит отметить, что представление фрагмента (его визуальный интерфейс или View) имеет отдельный жизненный цикл.
При создании фрагмент находится в состоянии INITIALIZED. Чтобы фрагмент прошел все остальные этапы жизненного цикла, фрагмент необходимо передать в объект FragmentManager, который далее определяет состояние фрагмента и переводит фрагмент из одного состояния в другое.
onCreate(): происходит создание фрагмента. В этом методе мы можем получить ранее сохраненное состояние фрагмента
через параметр метода Bundle savedInstanceState
. (Если фрагмент создается первый раз, то этот объект имеет значение null
)
Этот метод вызывается после вызова соответствующего метода onCreate() у activity.
public void onCreate(Bundle savedInstanceState)
onCreateView(): фрагмент создает представление (View или визуальный интерфейс). В этом методе мы можем установить, какой именно изуальный интерфейс будет использовать фрагмент. При выполнении этого метода представление фрагмента переходит в состояние INITIALIZED. А сам фрагмент все еще находится в состоянии CREATED
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
Первый параметр - объект LayoutInflater позволяет получить содержимое ресурса layout и передать его во фрагмент.
Второй параметр - объект ViewGroup представляет контейнер, в которой будет загружаться фрагмент.
Третий параметр - объект Bundle представляет состояние фрагмента. (Если фрагмент загружается первый раз, то равен null)
На выходе метод возвращает созданное с помощью LayoutInflater представление в виде объекта View - собственно представление фрагмента
onViewCreated(): вызывается после создания представления фрагмента.
public void onViewCreated (View view, Bundle savedInstanceState)
Первый параметр - объект View - представление фрагмента, которое было создано посредством метода onCreateView.
Второй параметр - объект Bundle представляет состояние фрагмента. (Если фрагмент загружается первый раз, то равен null)
onViewStateRestored(): получает состояние представления фрагмента. После выполнения этого метода представление фрагмента переходит в состояние CREATED
public void onViewStateRestored (Bundle savedInstanceState)
onStart(): вызывается, когда фрагмент становится видимым и вместе с представлением переходит в состояние STARTED
public void onStart ()
onResume(): вызывается, когда фрагмент становится активным, и пользователь может с ним взаимодействовать. При этом фрагмент и его представление переходят в состояние RESUMED
public void onResume ()
onPause(): фрагмент продолжает оставаться видимым, но уже не активен и вместе с представлением переходит в состояние STARTED
public void onPause ()
onStop(): фрагмент больше не является видимым и вместе с представлением переходит в состояние CREATED
public void onStop ()
На этом этапе жизненного цикла мы можем сохранить состояние фрагмента с помощью метода onSaveInstanceState(). Однако стоит учитывать,
что вызов этого метода зависит от версии API. До API 28 onSaveInstanceState()
вызывается до onStop()
,
а начиная API 28 после onStop()
.
onDestroyView(): уничтожается представление фрагмента. Представление переходит в состояние DESTROYED
onDestroy(): окончательно уничтожение фрагмента - он также переходит в состояние DESTROYED
Дополнительно для фрагмента определено два метода обратного вызова, которые связаны с прикреплением фрагмента к activity:
Когда фрагмент добавляется в FragmentManager и прикрепляется к определенному классу Activity, у фрагмента вызывается метод onAttach(). Данный метод вызывается до всех остальных методов жизненного цикла. Начиная с этого момента фрагмент становится активным, и FragmentManager начинает управлять его жизненным циклом.
Метод onDetach() вызывается, когда фрагмент удаляется из FragmentManager и открепляется от класса Activity. Этот метод вызывается после всех остальных методов жизненного цикла.
В коде класса фрагмента мы можем переопределить все или часть из этих методов. Например, пусть у нас будет определен следующий проект:
В каталоге res/layout определен файл layout для фрагмента - fragment_content.xml со следующей разметкой:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/updateButton" android:layout_width="0dp" android:layout_height="wrap_content" android:text="Обновить" app:layout_constraintBottom_toTopOf="@+id/dateTextView" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/dateTextView" android:layout_width="0dp" android:layout_height="wrap_content" android:textSize="26sp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/updateButton" /> </androidx.constraintlayout.widget.ConstraintLayout>
Класс фрагмента использует данный файл для установки представления, а также определяет методы для управления жизненным циклом:
package com.example.fragmentapp; import android.content.Context; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import android.util.Log; import java.util.Date; public class ContentFragment extends Fragment { private final static String TAG = "ContentFragment"; public ContentFragment(){ Log.d(TAG, "Constructor"); } @Override public void onAttach(@NonNull Context context) { super.onAttach(context); Log.d(TAG, "onAttach"); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d(TAG, "onCreate"); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Log.d(TAG, "onCreateView"); return inflater.inflate(R.layout.fragment_content, container, false); } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); Button updateButton = view.findViewById(R.id.updateButton); TextView updateBox = view.findViewById(R.id.dateTextView); updateButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String curDate = new Date().toString(); updateBox.setText(curDate); } }); Log.d(TAG, "onViewCreated"); } @Override public void onViewStateRestored(@Nullable Bundle savedInstanceState) { super.onViewStateRestored(savedInstanceState); Log.d(TAG, "onViewStateRestored"); } @Override public void onStart() { super.onStart(); Log.d(TAG, "onStart"); } @Override public void onResume() { super.onResume(); Log.d(TAG, "onResume"); } @Override public void onPause() { super.onPause(); Log.d(TAG, "onPause"); } @Override public void onStop() { super.onStop(); Log.d(TAG, "onStop"); } @Override public void onDestroyView() { super.onDestroyView(); Log.d(TAG, "onDestroyView"); } @Override public void onDestroy() { super.onDestroy(); Log.d(TAG, "onDestroy"); } @Override public void onDetach() { super.onDetach(); Log.d(TAG, "onDetach"); } }
В отличие от прошлой статьи, где рассматривалось создание фрагмента, здесь фрагмент устанавливает представление в методе
onCreateView. Для этого в метод inflate()
объекта LayoutInflater передается идентификатор ресурса layout и контейнер - объект ViewGroup,
в который будет загружаться фрагмент. В итоге метод inflate()
возвращает созданное представление.
return inflater.inflate(R.layout.fragment_content, container, false);
При выполнении метода onViewCreated() представление уже создано и оно передается в качестве первого параметра - объекта View, через который с помощью идентификаторов мы можем получить визуальные элементы - TextView и Button, которые определены в представлении.
Для остальных методов жизненного цикла установлено простое логгирование с помощью метода Log.d()
.
Пусть в файле activity_main.xml происходит добавление фрагмента:
<?xml version="1.0" encoding="utf-8"?> <androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/fragment_container_view" android:layout_width="match_parent" android:layout_height="match_parent" android:name="com.example.fragmentapp.ContentFragment" />
И класс MainActivity:
package com.example.fragmentapp; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
Если мы запустим проект, то на экране устройства мы увидим визуальный интерфейс, определенный для фрагмента.
А в окне Logcat в Android Studio можно будет наблюдать логгирование методов жизненного цикла