Освой Android играючи

Сайт Александра Климова

Шкодим

/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000

Жизненный цикл фрагментов

У фрагментов есть жизненный цикл, который во многом совпадает с жизненным циклом активности, внутри которой они находятся.

Жизненный цикл фрагментов

Список дополнительных методов жизненного цикла фрагментов, которых нет у активности:

onAttach(Activity)
Вызывается, когда фрагмент связывается с активностью. С этого момента мы можем получить ссылку на активность через метод getActivity()
onCreate()
В этом методе можно сделать работу, не связанную с интерфейсом. Например, подготовить адаптер.
onCreateView(LayoutInflater, ViewGroup, Bundle)
Вызывается для создания компонентов внутри фрагмента
onViewCreated()
Вызывается сразу после onCreateView()
onActivityCreated(Bundle)
Вызывается, когда отработает метод активности onCreate(), а значит фрагмент может обратиться к компонентам активности
onStart()
Вызывается, когда фрагмент видим для пользователя и сразу же срабатывает onStart() активности
onDestroyView()
onResume()
Вызываем после onResume() активности
Вызывается, когда набор компонентов удаляется из фрагмента
onDetach()
Вызывается, когда фрагмент отвязывается от активности

Одноимённые с методами активности методы фрагментов выполняют аналогичные функции. К примеру, метод onResume() вызывается, когда фрагмент вновь становится видимым.

Метод onStart() вызывается, когда фрагмент становится видимым после запуска такого же метода в родительской активности.

Фрагмент всегда связан с активностью. Отдельно фрагмент от активности существовать не может.

Если активность останавливается, то её фрагменты также останавливаются. Если активность уничтожается, то её фрагменты также уничтожаются.

Метод onCreateView() вызывается один раз, когда фрагмент должен загрузить на экран свой интерфейс. В этом методе вы можете "надуть" (inflate) разметку фрагмента через метод inflate() объекта Inflater, который задан в параметре метода. В фрагментах без интерфейса вы можете пропустить надувание.

Метод onActivityCreated() вызывается после метода onCreateView(), когда создаётся активность-хозяйка для фрагмента. Здесь можно объявить объекты, необходимые для Context.

Фрагменты не являются подклассами Context, вам следует использовать метод getActivity(), чтобы получить родительскую активность.

Создадим несколько фрагментов и с помощью логов посмотрим на срабатывание методов. Первоначально пример писался на Java, будет приведён аналог на Kotlin только для первого фрагмента, остальное придётся написать самостоятельно.

FirstFragment


// Kotlin
package ru.alexanderklimov.fragmentdemo

import android.content.Context
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment

class Fragment1 : Fragment() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        Log.d("Fragment1", "onCreate")
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val rootView = inflater.inflate(R.layout.fragment1, container, false)

        Log.d("Fragment1", "onCreateView")

        return rootView
    }

    override fun onAttach(context: Context) {
        super.onAttach(context)

        Log.d("Fragment1", "onAttach")
    }

    override fun onStart() {
        super.onStart()

        Log.d("Fragment1", "onStart")
    }

    override fun onResume() {
        super.onResume()

        Log.d("Fragment1", "onResume")
    }

    override fun onStop() {
        Log.d("Fragment1", "onStop")

        super.onStop()
    }

    override fun onDestroyView() {
        Log.d("Fragment1", "onDestroyView")

        super.onDestroyView()
    }

    override fun onDestroy() {
        Log.d("Fragment1", "onDestroy")

        super.onDestroy()
    }

    override fun onDetach() {
        Log.d("Fragment1", "onDetach")

        super.onDetach()
    }
}

// Java package ru.alexanderklimov.fragmentdemo; import android.app.Activity; import android.net.Uri; import android.os.Bundle; import android.app.Fragment; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; public class FirstFragment extends Fragment { public static FirstFragment newInstance(String param1, String param2) { FirstFragment fragment = new FirstFragment(); // Bundle args = new Bundle(); return fragment; } public FirstFragment() { // Required empty public constructor } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d("Fragment 1", "onCreate"); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_first, container, false); Log.d("Fragment 1", "onCreateView"); return rootView; } @Override public void onAttach(Activity activity) { super.onAttach(activity); Log.d("Fragment 1", "onAttach"); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); Log.d("Fragment 1", "onActivityCreated"); } @Override public void onStart() { super.onStart(); Log.d("Fragment 1", "onStart"); } @Override public void onResume() { super.onResume(); Log.d("Fragment 1", "onResume"); } @Override public void onPause() { super.onPause(); Log.d("Fragment 1", "onPause"); } @Override public void onStop() { super.onStop(); Log.d("Fragment 1", "onStop"); } @Override public void onDestroyView() { super.onDestroyView(); Log.d("Fragment 1", "onDestroyView"); } @Override public void onDestroy() { super.onDestroy(); Log.d("Fragment 1", "onDestroy"); } @Override public void onDetach() { super.onDetach(); //mListener = null; Log.d("Fragment 1", "onDetach"); } }

Разметка для первого фрагмента


<?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:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Первый фрагмент" />
    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/ic_launcher"/>
</LinearLayout>

По аналогии создайте второй фрагмент SecondFragment, заменив тексты и названия идентификаторов там, где это нужно.

Создадим разметку для главной активности с двумя кнопками для переключения между фрагментами.

activity_main.xml


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

    <LinearLayout
        android:layout_width="0px"
        android:layout_weight="1"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Выберите фрагмент:" />

        <Button
            android:id="@+id/buttonFragment1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Fragment 1" />

        <Button
            android:id="@+id/buttonFragment2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Fragment 2" />
    </LinearLayout>

    <FrameLayout
        android:id="@+id/container"
        android:layout_width="0px"
        android:layout_weight="3"
        android:layout_height="match_parent" />

</LinearLayout>

MainActivity.java

В главной активности можно переключаться между фрагментами при нажатии на кнопку, а также через кнопку BACK, чтобы увидеть транзакции фрагментов.


package ru.alexanderklimov.fragmentdemo;

import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;


public class MainActivity extends ActionBarActivity {

    Button fragment1Button, fragment2Button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        fragment1Button = (Button) findViewById(R.id.buttonFragment1);
        fragment2Button = (Button) findViewById(R.id.buttonFragment2);

        // get an instance of FragmentTransaction from your Activity
        FragmentManager fragmentManager = getFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

        //add a fragment
        FirstFragment firstFragment = new FirstFragment();
        fragmentTransaction.add(R.id.container, firstFragment);
        fragmentTransaction.commit();

        fragment1Button.setOnClickListener(onButtonClickListener);
        fragment2Button.setOnClickListener(onButtonClickListener);
    }

    Button.OnClickListener onButtonClickListener = new Button.OnClickListener() {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            Fragment newFragment = null;

            // Create new fragment
            if (v == fragment1Button) {
                newFragment = new FirstFragment();
            } else {
                newFragment = new SecondFragment();
            }

            // Create new transaction
            FragmentTransaction transaction = getFragmentManager().beginTransaction();

            // Replace whatever is in the fragment_container view with this fragment,
            // and add the transaction to the back stack
            transaction.replace(R.id.container, newFragment);
            transaction.addToBackStack(null);

            // Commit the transaction
            transaction.commit();
        }
    };
}

Смотрим сообщения. При запуске приложения запускается первый фрагмент, который загружается в контейнер. Последовательность следующая.

onAttach
onCreate
onCreateView
onActivityCreated
onStart
onResume

Метод onActivityCreated() теперь считается устаревшим.

Нажимаем на кнопку "Home":

onPause
onStop

Запустим из списка недавно запущенных программ:

onStart
onResume

Выходим из программы через кнопку "Back":

onPause
onStop
onDestroyView
onDestroy
onDetach

При замещении первого фрагмента вторым почти как при закрытии, только нет методов onDestroy и onDetach, а затем повторяются те же методы при старте фрагмента:

// Первый фрагмент onPause
onStop
onDestroyView
// Второй фрагмент onAttach
onCreate
onCreateView
onActivityCreated
onStart
onResume

Дополнительное чтение

xxv/android-lifecycle - схема жизненного цикла в SVG, PDF, PNG.

Реклама