Освой Android играючи
/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000
У фрагментов есть жизненный цикл, который во многом совпадает с жизненным циклом активности, внутри которой они находятся.
Список дополнительных методов жизненного цикла фрагментов, которых нет у активности:
Одноимённые с методами активности методы фрагментов выполняют аналогичные функции. К примеру, метод onResume() вызывается, когда фрагмент вновь становится видимым.
Метод onStart() вызывается, когда фрагмент становится видимым после запуска такого же метода в родительской активности.
Фрагмент всегда связан с активностью. Отдельно фрагмент от активности существовать не может.
Если активность останавливается, то её фрагменты также останавливаются. Если активность уничтожается, то её фрагменты также уничтожаются.
Метод onCreateView() вызывается один раз, когда фрагмент должен загрузить на экран свой интерфейс. В этом методе вы можете "надуть" (inflate) разметку фрагмента через метод inflate() объекта Inflater, который задан в параметре метода. В фрагментах без интерфейса вы можете пропустить надувание.
Метод onActivityCreated() вызывается после метода onCreateView(), когда создаётся активность-хозяйка для фрагмента. Здесь можно объявить объекты, необходимые для Context.
Фрагменты не являются подклассами Context, вам следует использовать метод getActivity(), чтобы получить родительскую активность.
Создадим несколько фрагментов и с помощью логов посмотрим на срабатывание методов. Первоначально пример писался на Java, будет приведён аналог на Kotlin только для первого фрагмента, остальное придётся написать самостоятельно.
// 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, заменив тексты и названия идентификаторов там, где это нужно.
Создадим разметку для главной активности с двумя кнопками для переключения между фрагментами.
<?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>
В главной активности можно переключаться между фрагментами при нажатии на кнопку, а также через кнопку 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.