Мы продолжаем разработку под Android и в этой статье познакомимся с Android Fragment. Наша программа будет состоять из двух фрагментов и одного активити.
Что такое Fragment в Android?
Класс Fragment
используется для построения динамического интерфейса андроид приложений и взаимодействуют с Activity. Главным преимуществом фрагментов является упрощение работы с UI (пользовательским интерфейсом) на экранах разных размеров. Одна Activity может взаимодействовать с неограниченным количеством фрагментов.
Android Fragment не является подклассом View
, как большинство других компонентов пользовательского интерфейса. Вместо этого фрагмент содержит объект view внутри себя. Этот view отображается в Activity, к которой прикреплен фрагмент. Поскольку Android Fragment не является view, то и добавление его к Activity происходит не так, как какой-то TextView
. Фрагмент добавляется в ViewGroup внутри Activity и view фрагмента отображается внутри этого ViewGroup.
Как Fragment работает с Activity?
Давайте рассмотрим последовательность взаимодействия активити с фрагментом:
- Activity получает ссылку на фрагмент.
- Затем она получает ссылку на ViewGroup, в котором будет отрисовываться view фрагмента.
- После этого активность добавляет фрагмент.
- Фрагмент создает свой view и возвращает его Activity.
- Этот view вставляется в ViewGroup и фрагмент начинает работу.
Как фрагмент связан с другими классами
Класс Fragment
был добавлен еще в Android API 11
вместе с другими тесно связанными классами:
- Класс
android.app.Fragment
— базовый класс для работы с фрагментами - Класс
android.app.FragmentManager
— класс для работы c фрагментами внутриActivity
. - Класс
android.app.FragmentTransaction
предоставляет набор операций для работы с фрагментами
Также в распоряжении программиста пакет библиотек совместимости, предоставляемых Google для поддержки версий меньше Android API 11
. Например, класс android.support.v4.app.FragmentActivity
является подклассом Activity, который обеспечивает работу с фрагментами.
Жизненный цикл фрагмента
Жизненный цикл Fragment управляется 10 методами:
- Метод
onAttach()
будет вызван самым первым еще до методаonCreate()
, тем самым присоединив фрагмент к активити. - Метод
onCreateView()
. Система вызывает этот метод, когда фрагмент прорисовывается в первый раз. - Метод
onViewCreated()
будет вызван сразу послеonCreateView()
. - Метод
onActivityCreated()
будет вызван после методовonCreate()
иonCreateView()
. Он может быть использован для инициализации объектов фрагмента. - Метод
onStart()
вызывается один раз — фрагмент становится видимым для пользователя. - Метод
onPause()
вызывается системой, когда пользователь уходит с фрагмента. В этом методе обычно сохраняют результаты работы пользователя. - Метод
onStop()
. Работа фрагмента будет остановлена вызовом методаonStop()
. - Метод
onDestroyView()
вызывается перед методомonDestroy()
. Метод является противоположностьюonCreateView()
, в котором мы создавали пользовательский интерфейс. - Метод
onDestroy()
вызывается для очистки состояния фрагмента, но система Android не гарантирует его вызов. - Метод
onDetach()
будет вызван послеonDestroy()
, чтобы уведомить нас о том, что фрагмент был окончательно отделен от Activity.
Пример работы с Android Fragment
Сейчас мы напишем приложение с одной MainActivity и двумя фрагментами: MainFragment и DetailsFragment. Для этого нам подойдет базовый Hello World проект (кто не знает как создать новый проект в Android Studio, советую сначала начать с него).
А начнем мы с макета activity_main.xml
для MainActivity:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<?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:baselineAligned="false" android:orientation="horizontal" android:weightSum="1.0"> <fragment android:layout_height="match_parent" android:layout_width="match_parent" class="ua.com.prologistic.helloandroidapp.fragments.MainFragment" android:id="@+id/mainfragment" android:layout_weight="0.5"/> <fragment android:layout_width="match_parent" android:layout_height="match_parent" class="ua.com.prologistic.helloandroidapp.fragments.DetailsFragment" android:id="@+id/detailsfragment" android:layout_weight="0.5"/> </LinearLayout> |
Обратите внимание: с помощью атрибута class
мы явно задаем принадлежность макета фрагмента определенному классу.
С помощью атрибута layout_weight
мы определяем вес каждого фрагмента, а точнее сколько места на экране получит тот или другой фрагмент.
Код класса MainActivity представлен ниже:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
package ua.com.prologistic.helloandroidapp; import android.support.v7.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); } } |
В самом коде MainActivity мы ниже не меняли. Установка фрагментов происходила в макете activity_main
, поэтому при старте приложения мы сразу будем видеть фрагменты.
Альтернативой этому способу является явная работа с FragmentManager
в классе MainActivity. С этим способом мы познакомимся в следующих статьях. Сейчас же мы просто должны понять как работают фрагменты.
Макет main_fragment.xml
представлен ниже:
1 2 3 4 5 6 7 8 9 10 11 |
<?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"> <ListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout> |
Листинг класса MainFragment.java
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
package ua.com.prologistic.helloandroidapp.fragments; import android.os.Bundle; import android.support.v4.app.ListFragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ListView; import ua.com.prologistic.helloandroidapp.R; public class MainFragment extends ListFragment { // это наш захардкоденый массив языков программирования String[] languages = new String[]{ "Java", "PHP", "C#", "Python" }; // массив версий: каждый элемент соответствует языку программирования String[] versions = new String[]{ "1.9", "5.6", "7.0", "3.5" }; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // устанавливаем макет View view = inflater.inflate(R.layout.main_fragment, container, false); // создаем простой ArrayAdapter со стандартным макетом и входными данными в виде массива языков ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_1, languages); setListAdapter(adapter); return view; } @Override public void onListItemClick(ListView l, View v, int position, long id) { // заменяем текст в другом фрагменте по нажатию на элемент списка DetailsFragment detailsFragment = (DetailsFragment) getFragmentManager().findFragmentById(R.id.detailsfragment); detailsFragment.change(languages[position], versions[position]); getListView().setSelector(android.R.color.holo_blue_bright); } } |
Макет details_fragment.xml
представлен ниже:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<?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="#ff00ddff" android:gravity="center" android:orientation="vertical"> <TextView android:id="@+id/languages" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:textColor="#f0f0f0" android:textSize="25pt" /> <TextView android:id="@+id/versions" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:textColor="#f1f1f1" android:textSize="25pt" /> </LinearLayout> |
Класс DetailsFragment.java
на листинге ниже:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
package ua.com.prologistic.helloandroidapp.fragments; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import ua.com.prologistic.helloandroidapp.R; public class DetailsFragment extends Fragment { TextView languages, versions; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.details_fragment, container, false); languages = (TextView) view.findViewById(R.id.languages); versions = (TextView) view.findViewById(R.id.versions); return view; } // заменяем текст в TextView этого фрагмента public void change(String text, String text2) { languages.setText(text); versions.setText(text2); } } |
Теперь давайте запустим приложение и посмотрим результаты работы:
Как видим, нажимая на пункты в фрагменте MainFragment
, мы изменяем текст на TextView
во фрагменте DetailsFragment
. Следите за обновлениями раздела Разработка приложений на Android.
К сожалению многое устарело — не работает…
Например,
import android.support.v4.app.Fragment
import android.support.v7.app.AppCompatActivity;
Устарели зависимости, принцип рабочий.