Афоризм
Ума палата с крышей набекрень.
Наталья Резник
Последние статьи

 • Ограничение доступа
Ограничение прав доступа к организациям на уровне БД
 • Ролевой механизм
Интегрирование ролей БД в приложениe JaBricks
 • Загрузка модулей
Динамическая загрузка модулей в приложениe
 • платформа JaBricks
Платформа OSGi-приложения JaBricks
 • Активности Android
Многоэкранные Android приложения
 • Fragment dynamic
Динамическая загрузка фрагментов в Android
 • Fragment lifecycle
Жизненный цикл Fragment'ов в Android
 • Fragment example
Пример Fragment'ов в Android
 • Data Binding
Описание и пример Data Binding
 • Пример MVVM
Пример использования MVVM в Android
 • Компонент TreeTable
Описание компонента TreeTable для Swing
 • Пример TreeTable
Пример использования TreeTable
 • Хранилища Android
Внутренние и внешние хранилища данных
 • Пример SQLite
Пример использования SQLite в Android
 • WebSocket
Описание и пример реализации WebSocket
 • APK-файл Android
Создание apk-файла для android устройств, .dex файлы
Поддержка проекта

Если Вам сайт понравился и помог, то будем признательны за Ваш «посильный» вклад в его поддержку и развитие
 • Yandex.Деньги
  410013796724260

Пример использования фрагментов

Фрагменты облегчают построение адаптивного интерфейса из «шаблонов», которые можно динамически отобразить на экране устройства, скрыть или заменить другим фрагментом. Рассмотрим пример использования двух фрагментов. Сначала рассмотрим формирование интерфейса из активности и фрагментов. После этого рассмотрим взаимодействие между отдельными частями интерфейса, т.е. между активностью и фрагментами.

Для работы с фрагментами создадим в Android Studio модуль (пример) fragment_01, представленный на следующем скриншоте. Модуль включает активность MainActivity и два фрагмента Fragment1/Fragment2, расположенные в пакете com.example.fragment. Шаблоны интерфейсов активности и фрагментов расположены в поддиректории res/layout (main_activity.xml, fragment1.xml, fragment2.xml). Ресурсный файл res/values/strings.xml содержит набор строк для определения заголовков примера и компонентов.

Интерфейс примера android-fragment

Сразу же необходимо отметить, что не вся функциональность фрагментов может быть доступна в модуле, поскольку используемая AndroidX Fragment Library располагается в отдельной библиотеке. Сначала необходимо подключить к модулю эту библиотеку в файле build.gradle.

...
dependencies {
    implementation "androidx.fragment:fragment:1.4.1"
    ...
}

Шаблоны интерфейса

Интерфейс примера разделим условно на 3 части : активность, статический фрагмент и динамический фрагмент. Стастический и динамический фрагменты, конечно же, включены в активность и они занимают часть общего интерфейса. Чтобы визуально можно было бы легко различать части интерфейса, раскрасим их (background) в разные цвета.

Каждая часть интерфейса будет включать текстовый компонент типа TextView и кнопку. Текстовые компоненты используем для отображения сообщений, а кнопки для передачи этих сообщений. Сообщения будем передавать как из активности во фрагменты, так и из фрагментов в активность, а также из одного фрагмента в другой фрагмент. Ниже в листинге main_activity.xml описан интерфейс (шаблон) главной активности. Комментарии к шаблону после листинга.

Листинг main_activity.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:id="@+id/LinearLayout1"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical">
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/activity_text"
        android:textStyle="bold">
    </TextView>
    <Button
        android:id="@+id/btnFind"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="onClick"
        android:text="@string/btn_activity"
        android:textAllCaps="false">
    </Button>
    <fragment
        android:id="@+id/fragment1"
        android:name="com.example.fragment.Fragment1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        tools:layout="@layout/fragment1">
    </fragment>
    <FrameLayout
        android:id="@+id/fragment2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1">
    </FrameLayout>
</LinearLayout>

Интерфейс активности включает текстовую метку TextView и кнопку Button. Тексты меток и кнопок (android:text) определены в ресурсном файле res/values/strings.xml. К кнопке подключен обработки события android:onClick.

Статический фрагмент в секции <fragment> содержит полное наименование класса (android:name) и шаблон интерфейса фрагмента, представленный атрибутом tools:layout.

Динамический fragment2 определен компонентом типа контейнер FrameLayout, в который в режиме run-time будет загружен Fragment2.

Таким образом, шаблон активности main_activity.xml включает метку с кнопкой, статический fragment1 и контейнер FrameLayout для динамической загрузки фрагмента. Каждый компонент интерфейса имеет идентификатор android:id.

Шаблоны фрагментов

Шаблоны фрагментов fragment1 и fragment2 имеют одинаковый контент/интерфейс и также, как и шаблон активности, включают метку типа TextView и кнопку. Отличия фрагментов касаются только цвета фона android:background. Необходимо отметить, что к кнопкам не подключены обработчики (onClick); подключение обработчиков событий нажатия кнопок выполнено в java-коде. Ниже представлен листинг шаблона fragment1.xml.

Листинг 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="#8822aaff"
  android:orientation="vertical">
  <TextView
      android:id="@+id/textView"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="@string/frag1_text"
      android:textStyle="bold">
  </TextView>
  <Button
      android:id="@+id/button"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="@string/btn_fragment"
      android:textAllCaps="false">
  </Button>
</LinearLayout>

На следующем скриншоте представлен интерфейс примера после старта, в котором наглядно обозначены 3 части интерфейса различными фоновыми цветами.

Интерфейс примера android-fragment

Контент ресурсного файла strings.xml, строки которого используются в метках и заголовках кнопок, представлен ниже в свернутом виде.

Листинг strings.xml

<resources>
    <string name="app_name">fragment_01</string>
    <string name="activity_text">MainActivity</string>
    <string name="frag1_text">Static Fragment</string>
    <string name="frag2_text">Dynamic Fragment</string>
    <string name="btn_fragment">Button</string>
    <string name="btn_activity">Button Activity</string>
</resources>

Класс активности

Класс акивности использует шаблон R.layout.main_activity для формирования интерфейса. При динамической загрузке фрагмента в интерфейс примера используются классы FragmentManager и FragmentTransaction. Метод добавления фрагмента в интерфейс FragmentTransaction.add в качестве параметров получает значение идентификатора R.id.fragment2 (расположение в интерфейсе/шаблоне) и объект реализации Fragment2. В методе onClick, вызываемый при нажатии на кнопку активности, выводится отладочное сообщение Logcat с тегом LOG_TAG. Листинг активности представлен ниже в свернутом виде.

Листинг MainActive.java


package com.example.fragment;


import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.View;

public class MainActivity extends AppCompatActivity
{
    final String LOG_TAG = "DEVELOPMENT";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_activity);

        // Классы управления фрагментами
        FragmentManager     fm;
        FragmentTransaction ft;

        // Динамическая загрузка fragment2
        fm = getSupportFragmentManager();
        ft = fm.beginTransaction();
        
        Fragment fr = new Fragment2();
        ft.add(R.id.fragment2, fr);
        ft.commit();
    }
    public void onClick(View v)
    {
        Log.d(LOG_TAG, "Button click in Activity");
    }
}
 

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

//  Альтернативная запись загрузки динамического фрагмента
		
getSupportFragmentManager()
    .beginTransaction()
    .add(R.id.fragment2, new Fragment2())
    .commitNow();

Классы фрагментов

Классы фрагментов также, как и их интерфейсные шаблоны (fragment[1|2].xml), идентичны. Они наследуют свойства и методы базового класса androidx.fragment.app.Fragment. Переопределенный метод onCreateView формирует интерфейс фрагмента. К кнопке подключается обработчик события onClick, который выводит отладочное сообщение.

Листинг Fragment2.java


package com.example.fragment;

import android.os.Bundle;
import android.util.Log;

import android.content.Context;
import android.widget.Button;

import android.view.View;
import android.view.ViewGroup;
import android.view.LayoutInflater;
import android.view.View.OnClickListener;

import androidx.fragment.app.Fragment;

public class Fragment2 extends Fragment {

    final String LOG_TAG = "DEVELOPMENT";
    //-----------------------------------------------------
    @Override
    public View onCreateView(LayoutInflater inflater, 
                             ViewGroup container,
                             Bundle savedInstanceState) {
        View v =inflater.inflate(R.layout.fragment2, null);

        Button button=(Button) v.findViewById(R.id.button);
        button.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                Log.d(LOG_TAG, "Button click in Fragment2");
            }
        });
        return v;
    }
}

Отличие кода Fragment1 от Fragment2 связано с переопределением всех методов жизненного цикла фрагмента, в которых выводятся отладочные сообщения. Листинг Fragment1 представлен ниже в свернутом виде.

Листинг Fragment1.java

package com.example.fragment;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.LayoutInflater;
import android.view.View.OnClickListener;

import android.widget.Button;

import androidx.fragment.app.Fragment;

public class Fragment1 extends Fragment {

    final String LOG_TAG = "DEVELOPMENT";
    //-----------------------------------------------------
    @Override
    public View onCreateView(LayoutInflater inflater,
                             ViewGroup container,
                             Bundle savedInstanceState)
    {
        View v = inflater.inflate(R.layout.fragment1, null);

        Button button=(Button) v.findViewById(R.id.button);
        button.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                Log.d(LOG_TAG,"Button click in Fragment1");
            }
        });
        Log.d(LOG_TAG, "fragment onCreateView");
        return v;
    }
    //-----------------------------------------------------
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        Log.d(LOG_TAG, "fragment onAttach");
    }
    //-----------------------------------------------------
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(LOG_TAG, "fragment onCreate");
    }
    //-----------------------------------------------------
    @Override
    public void onViewCreated(View view, 
                              Bundle savedInstanceState)
    {
        super.onStart();
        Log.d(LOG_TAG, "fragment onViewCreated");
    }
    //-----------------------------------------------------
    @Override
    public void onStart() {
        super.onStart();
        Log.d(LOG_TAG, "fragment onStart");
    }
    //-----------------------------------------------------
    @Override
    public void onResume() {
        super.onResume();
        Log.d(LOG_TAG, "fragment onResume");
    }
    //-----------------------------------------------------
    @Override
    public void onPause() {
        super.onPause();
        Log.d(LOG_TAG, "fragment onPause");
    }
    //-----------------------------------------------------
    public void onSaveInstanceState(Bundle outState){
        super.onSaveInstanceState(outState);
        Log.d(LOG_TAG, "fragment saveInstanceState");
    }
    //-----------------------------------------------------
    @Override
    public void onStop() {
        super.onStop();
        Log.d(LOG_TAG, "fragment onStop");
    }
    //-----------------------------------------------------
    @Override
    public void onDestroyView() {
        super.onDestroyView();
        Log.d(LOG_TAG, "fragment onDestroyView");
    }
    //-----------------------------------------------------
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(LOG_TAG, "fragment onDestroy");
    }
    //-----------------------------------------------------
    @Override
    public void onDetach() {
        super.onDetach();
        Log.d(LOG_TAG, "fragment onDetach");
    }
}

Старт примера

После старта примера (скриншот выше) и нажатии на кнопки мы увидим следующие отладочные сообщения в консоли (дата и время убраны). Чтобы вызвать callback-методы жизненного цикла, связанные с остановкой и выгрузкой фрагмента, можно выполнить рестарт приложения.


com.example.fragment DEVELOPMENT: fragment onAttach
com.example.fragment DEVELOPMENT: fragment onCreate
com.example.fragment DEVELOPMENT: fragment onCreateView
com.example.fragment DEVELOPMENT: fragment onViewCreated
com.example.fragment DEVELOPMENT: fragment onStart
com.example.fragment DEVELOPMENT: fragment onResume

com.example.fragment DEVELOPMENT: Button click in Activity
com.example.fragment DEVELOPMENT: Button click in Fragment1
com.example.fragment DEVELOPMENT: Button click in Fragment2

// рестарт приложения 
com.example.fragment DEVELOPMENT: fragment onPause
com.example.fragment DEVELOPMENT: fragment onStop
com.example.fragment DEVELOPMENT: fragment saveInstanceState
com.example.fragment DEVELOPMENT: fragment onDestroyView
com.example.fragment DEVELOPMENT: fragment onDestroy
com.example.fragment DEVELOPMENT: fragment onDetach

 

Взаимодействие активности и фрагментов

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

Доступ к фрагментам из активности

Ниже представлен расширенный код метода onClick активности. В исходном варианте в методе выводилось в консоль сообщение о нажатии на кнопку (последняя строка). В обновленном варианте определяются переменные фрагментов frgm1/frgm2 с использованием менеджера фрагментов getSupportFragmentManager и его метода findFragmentById, который в качестве параметра должен получить идентификатор фрагмента. Мы помним, что в шаблоне активности main_activity.xml статический фрагмент и контейнер фрагмента имеют идентификаторы (android:id). Текстовые компоненты TextView фрагментов определяются методами getView и findViewById. После того, как компонент метки определен, её текстовое значение изменяется.

Метод onClick активности MainActive.java

public void onClick(View v)
{
    TextView tv   ;
    Fragment frgm1;
    Fragment frgm2;

    frgm1 = getSupportFragmentManager()
           .findFragmentById(R.id.fragment1);
    tv = ((TextView) frgm1.getView()
                    .findViewById(R.id.textView));
    tv.setText("Access to Fragment 1 from Activity");
    //------------
    frgm2 = getSupportFragmentManager()
            .findFragmentById(R.id.fragment2);
    tv = ((TextView) frgm2.getView()
                    .findViewById(R.id.textView));
    tv.setText("Access to Fragment 2 from Activity");

    Log.d(LOG_TAG, "Button click in Activity");
}

Доступ к Activity из фрагмента

Попробуем из фрагмента достучаться до Activity. Метод фрагмента getActivity возвращает связанную с ним активность. После того, как активность получена можно получить доступ к визуальным компонентам View активности. Для реализации данного подхода внесем изменения в метод onClick первого фрагмента, как это представлено в следующем листинге.

Метод onClick фрагмента Fragment1.java

public void onClick(View v)
{
    TextView tv = (TextView)getActivity()
                           .findViewById(R.id.textView);
    tv.setText("Access from Fragment");
    Log.d(LOG_TAG, "Button click in Fragment1");
}

Взаимодействие фрагментов между собой

Как могут "достучаться" друг до друга два фрагмента, если они ничего друг о друге не знают? Но они хорошо "знакомы" с активностью, с которой они ассоциированы. Вот через эту активность и могут друг другу "передавать привет" фрагменты. Для этого в одном из фрагментов определяется интерфейс с одним или несколькими методами. Активность же должна имплементировать данный интерфейс, переопределяя его методы. Вызов соответствующего метода активности позволяет через неё отправить сообщение другому фрагменту. Схема такого подхода известная и распространенная. Таким образом, можно организовать навигацию, когда один из фрагментов используется в качестве меню, а второй фрагмент отображает связанный с пунктами меню контенты; активность же выступает в роли посредника.

Ниже представлен листинг модифицированного Fragment2 с выделенными изменениями. Как видим из кода, в класс Fragment2 добавлены интерфейс onEventListener и метод onAttach, вызываемый при "присоединении" фрагмента к активности. В методе onAttach сначала определяется активность activity, после чего интерфейсная переменная eventListener (родитель). Активность должна реализовать интерфейс onEventListener с методом sendText. При нажатии на кнопку фрагмента (метод onClick) вызывается родительский метод активности sendText. Всё довольно просто и прозрачно.

Листинг Fragment2.java

package com.example.fragment;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.LayoutInflater;
import android.view.View.OnClickListener;

import android.widget.Button;

import androidx.fragment.app.Fragment;

public class Fragment2 extends Fragment
{
    onEventListener eventListener = null;

    final String LOG_TAG = "DEVELOPMENT";
    //-----------------------------------------------------

    public interface onEventListener
    {
        public void sendText(String s);
    }
    //-----------------------------------------------------
    @Override
    public void onAttach(Context context)
    {
        super.onAttach(context);
        AppCompatActivity activity = null;

        if (context instanceof AppCompatActivity)
            activity = (AppCompatActivity) context;

        try {
            eventListener = (onEventListener) activity;
        } catch (ClassCastException e) {
          throw new ClassCastException(activity.toString()+
                         " must implement onEventListener");
        }
    }
    //-----------------------------------------------------
    @Override
    public View onCreateView(LayoutInflater inflater,
                             ViewGroup container,
                             Bundle savedInstanceState)
    {
        View v =inflater.inflate(R.layout.fragment2, null);

        Button button =(Button)v.findViewById(R.id.button);
        button.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
               eventListener.sendText("Text to Fragment1");
               Log.d(LOG_TAG, "Button click in Fragment2");
            }
        });
        return v;
    }
}

В заключении мы должны модифицировать активность, чтобы она могла передать сообщение из второго фрагмента первому. Для этого в описание класса вносим имплементацию интерфейса (Fragment2.onEventListener) и добавляем метод sendText. А дальше по знакомому сценарию в методе определяем фрагмент и меняем текст метки TextView. Методы активности onCreate и onClick остались без изменений.

Листинг MainActivity.java

public class MainActivity extends AppCompatActivity 
                          implements Fragment2.onEventListener
{
    final String LOG_TAG = "DEVELOPMENT";
    //-----------------------------------------------------
    @Override
    public void sendText(String s)
    {
        Fragment frgm1;
        frgm1 = getSupportFragmentManager()
                       .findFragmentById(R.id.fragment1);

        TextView tv;
        tv = (TextView)frgm1.getView()
                            .findViewById(R.id.textView);
        tv.setText("Text from Fragment 2 : " + s);
    }
    //-----------------------------------------------------
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
      . . .
    }
    //-----------------------------------------------------
    public void onClick(View v)
    {
      . . .
    }
}
  Рейтинг@Mail.ru