После размещения фрагмента, хотелось бы начать с ним взаимодействовать. Т.е. размещать View-компоненты и работать с ними, обращаться к фрагментам из Activity и наоборот. Попробуем это реализовать.
Для чистоты эксперимента будем работать с двумя фрагментами: статическим и динамическим.
Project name: P1061_FragmentActivity
Build Target: Android 4.1
Application name: FragmentActivity
Package name: ru.startandroid.develop.p1061fragmentactivity
Create Activity: MainActivity
В strings.xml добавим строки:
Fragment 1 Fragment 2 Log Find
Создаем layout и классы для двух фрагментов.
fragment1.xml:
fragment2.xml:
Fragment1.java:
package ru.startandroid.develop.p1061fragmentactivity; import android.app.Fragment; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.Button; public class Fragment1 extends Fragment < final String LOG_TAG = «myLogs»; 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»); >>); return v; > >
У фрагмента нет привычного для нас метода findViewById для поиска компонентов с экрана. Поэтому вызываем этот метод для View, которое будет содержимым фрагмента. В методе onCreateView мы создаем View и сразу же находим в нем кнопку и ставим ей обработчик. Затем отдаем View системе.
Element Exists and Find Element Activity
Fragment2.java:
package ru.startandroid.develop.p1061fragmentactivity; import android.app.Fragment; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.Button; public class Fragment2 extends Fragment < final String LOG_TAG = «myLogs»; 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.
Настраиваем основное Activity.
Кнопка, компонент fragment, в который помещен Fragment1, и контейнер FrameLayout, в который потом поместим Fragment2.
Обратите внимание на атрибут tools:layout. В нем указан layout-файл, и мы можем на этапе разработки видеть, как будет выглядеть статический фрагмент, когда приложение будет запущено.
UiPath — How to use On Element Appear Activity in UiPath | Example of On Element Appear UiPath
Для этого надо нажать правой кнопкой на компоненте fragment, и через пункт Fragment Layout указать нужный layout.
MainActivity.java:
Здесь мы просто добавляем Fragment2 в контейнер.
Все сохраняем, запускаем приложение.
Жмем кнопку Log в первом фрагменте и смотрим лог:
Button click in Fragment1
Жмем Log во втором фрагменте:
Button click in Fragment2
Все ок. Компоненты в фрагментах нашлись и обработчики среагировали на нажатия.
Атрибут onClick, который мы привыкли использовать для кнопки, здесь не прокатит. Указанный в этом атрибуте метод, будет вызван в Activity, а не в фрагменте.
Доступ к фрагменту из Activity
Разберемся, как получить доступ к фрагменту из Activity. Для этого у FragmentManager есть метод findFragmentById, который на вход принимает id компонента fragment (если фрагмент статический) или id контейнера (если динамический).
У нас в main.xml есть кнопка btnFind, вызывающая метод onClick при нажатии. Дорисуем в MainActivity.java метод onClick:
public void onClick(View v)
Используем метод findFragmentById. В первом случае на вход передаем id компонента fragment, т.к. Fragment1 у нас размещен именно так. При поиске Fragment2 указываем id контейнера, в который этот фрагмент был помещен. В результате метод findFragmentById возвращает нам объект Fragment.
Далее мы получаем доступ к его View с помощью метода getView, находим в нем TextView и меняем текст.
Все сохраняем, запускаем. Жмем кнопку Find
Тексты в фрагментах обновились. Тем самым из Activity мы достучались до фрагментов и их компонентов.
На всякий случай проговорю одну вещь из разряда «Спасибо кэп!». Если посмотреть на код MainActivity, то можно заметить, что работая с frag2 в методе onCreate и с frag2 в методе onClick мы работаем с текущим фрагментом Fragment2. Это так и есть. Оба frag2 в итоге будут ссылаться на один объект. Так что, если вы динамически добавили фрагмент, то у вас уже есть ссылка на него, и искать его через findFragmentById вам уже не надо.
Доступ к Activity из фрагмента
Теперь попробуем из фрагмента поработать с Activity. Для этого фрагмент имеет метод getActivity.
Давайте перепишем обработчик кнопки в первом фрагменте. Будем менять текст кнопки btnFind.
Fragment1.java:
package ru.startandroid.develop.p1061fragmentactivity; import android.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.Button; public class Fragment1 extends Fragment < 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) < ((Button)getActivity().findViewById(R.id.btnFind)).setText(«Access from Fragment1»); >>); return v; > >
Получаем Activity методом getActivity, ищем в нем кнопку и меняем текст.
Сохраняем, запускаем. Жмем кнопку в первом фрагменте:
Работает. Из фрагмента мы поменяли компонент Activity.
Обработка в Activity события из фрагмента
Рассмотрим механизм, который описан в хелпе: фрагмент генерирует некое событие и ставит Activity обработчиком.
Например, в Activity есть два фрагмента. Первый – список заголовков статей. Второй – отображает содержимое статьи, выбранной в первом. Мы нажимаем на заголовок статьи в первом фрагменте и получаем содержимое во втором. В этом случае, цель первого фрагмента – передать в Activity информацию о том, что выбран заголовок. А Activity дальше уже сама решает, что делать с этой информацией.
Если, например, приложение запущено на планшете в горизонтальной ориентации, то можно отобразить содержимое статьи во втором фрагменте. Если же приложение запущено на смартфоне, то экран маловат для двух фрагментов и надо запускать отдельное Activity со вторым фрагментом, чтобы отобразить статью.
Фишка тут в том, что первому фрагменту неинтересны все эти терзания Activity. Фрагмент – обособленный модуль. Его дело — проинформировать, что выбрана статья такая-то. Ему не надо искать второй фрагмент и работать с ним – это дело Activity.
Тут немного отвлекусь на небольшое лирическое отступление. Модульность, вообще, — очень важная и полезная штука. И ее надо использовать для универсальности, удобности и легкости в понимании работы своих приложений. Но уникальных рецептов, как правильно все организовать, конечно, нет. Каждый делает по-своему.
Именно по этим причинам я в своих уроках даю чисто технические вещи про отдельные компоненты и не рассказываю, как организовывать и писать целое приложение. Иначе, форум бы уже ломился от сообщений, что я все делаю не так и надо по-другому, и каждый бы излагал свое видение. И была бы куча споров, где одна сторона говорит, что крокодил зеленый, а другая сторона говорит, что он нифига не зеленый, а длинный ))
Вернемся к уроку. Фрагмент должен сообщить в Activity, что выбрана статья. Для этого он будет вызывать некий метод в Activity. И как нам сообщает хелп, лучший способ тут – это использовать интерфейс, который мы опишем в фрагменте и который затем будет реализован в Activity. Схема известная и распространенная.
Давайте реализуем. В нашем приложении никаких статей нет, поэтому будем просто передавать произвольную строку из второго фрагмента в Activity. А Activity уже будет отображать эту строку в первом фрагменте.
Перепишем Fragment2.java:
Описываем интерфейс onSomeEventListener. В нем метод someEvent, который на вход получает строку. Этот интерфейс будет реализовывать Activity.
В методе onAttach мы на вход получаем Activity, к которому присоединен фрагмент. Мы пытаемся привести это Activity к типу интерфейса onSomeEventListener, чтобы можно было вызывать метод someEvent и передать туда строку. Теперь someEventListener ссылается на Activity.
Далее, в onCreateView, в обработчике кнопки мы вызываем метод someEvent и передаем туда текст. Этот метод будет отработан в Activity.
Теперь меняем Activity.
MainActivity.java:
Дописываем интерфейс onSomeEventListener к описанию класса.
onCreate без изменений.
Реализуем метод someEvent. Просто ищем первый фрагмент и вставляем туда текст.
Все сохраняем и запускаем. Жмем кнопку во втором фрагменте:
Второй фрагмент передал через интерфейс строку в Activity, а оно нашло первый фрагмент и отобразило там эту строку.
На следующем уроке:
— размещаем элементы в ActionBar
Присоединяйтесь к нам в Telegram:
— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Compose, Kotlin, RxJava, Dagger, Тестирование, Performance
— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
Источник: startandroid.ru
Как получить элемент activity в программе
В прошлой теме было рассмотрено как вызывать новую Activity и передавать ей некоторые данные. Но мы можем не только передавать данные запускаемой activity, но и ожидать от нее некоторого результата работы.
К примеру, пусть у нас в проекте будут две activity: MainActivity и SecondActivity . А для каждой activity есть свой файл интерфейса: activity_main.xml и activity_second.xml соответственно.
В прошлой теме мы вызывали новую activity с помощью метода startActivity() . Для получения же результата работы запускаемой activity необходимо использовать Activity Result API .
Activity Result API предоставляет компоненты для регистрации, запуска и обработки результата другой Activity. Одним из преимуществ применения Activity Result API является то, что он отвязывает результат Activity от самой Activity. Это позволяет получить и обработать результат, даже если Activity, которая возвращает результат, в силу ограничений памяти или в силу других причин завершила свою работу. Вкратце рассмотрим основные моменты применения Activity Result API.
Регистрация функции для получения результата
Для регистрации функции, которая будет обрабатывать результат, Activity Result API предоставляет метод registerForActivityResult() . Этот метод в качестве параметров принимает объекты ActivityResultContract и ActivityResultCallback и возвращает объект ActivityResultLauncher , который применяется для запуска другой activity.
ActivityResultLauncher registerForActivityResult ( ActivityResultContract contract, ActivityResultCallback callback)
ActivityResultContract определяет контракт: данные какого типа будут подаваться на вход и какой тип будет представлять результат.
ActivityResultCallback представляет интерфейс с единственным методом onActivityResult() , который определяет обработку полученного результата. Когда вторая activity закончит работу и возвратит результат, то будет как раз вызываться этот метод. Результат передается в метод в качестве параметра. При этом тип параметра должен соответствовать типу результата, определенного в ActivityResultContract. Например:
Класс ActivityResultContracts предоставляет ряд встроенных типов контрактов. Например, в листинге кода выше применяется встроенный тип ActivityResultContracts.StartActivityForResult , который в качестве входного объекта устанавливает объект Intent , а в качестве типа результата — тип ActivityResult .
Запуск activity для получения результата
Метод registerForActivityResult() регистрирует функцию-колбек и возвращает объект ActivityResultLauncher . С помощью этого мы можем запустить activity. Для этого у объекта ActivityResultLauncher вызывается метод launch() :
mStartForResult.launch(intent);
В метод lauch() передается объект того типа, который определен объектом ActivityResultContracts в качестве входного.
Практическое применение Activity Result API
Итак, определим в файле activity_main.xml следующий интерфейс:
Для ввода данных здесь определен элемент EditText, а для отправки — кнопка.
Определим в классе MainActivity запуск второй activity:
Вкратце рассмотрим главные моменты этого кода. Прежде всего, мы определяем объект ActivityResultLauncher , с помощью которого будем запускать вторую activity и передавать ей данные:
Объект ActivityResultLauncher типизируется типом Intent , так как объект этого типа будет передаваться в метод launch() при запуске второй activity.
Тип контракта определяется типом ActivityResultContracts.StartActivityForResult , который и определяет тип Intent в качестве входного типа и тип ActivityResult в качестве типа результата.
Второй аргумент метода registerForActivityResult() — объект ActivityResultCallback типизируется типом результата — типом ActivityResult и определяет функцию-колбек onActivityResult() , которая получает результат и обрабатывает его. В данном случае обработка состоит в том, что мы выводим в текстовое поле ответ от второй activity.
При обработке мы проверяем полученный код результата:
if(result.getResultCode() == Activity.RESULT_OK)
В качестве результата, как правило, применяются встроенные константы Activity.RESULT_OK и Activity.RESULT_CANCELED . На уровне условностей Activity.RESULT_OK означает, что activity успешно обработала запрос, а Activity.RESULT_CANCELED — что activity отклонила обработку запроса.
С помощью метода getData() результата получаем переданные из второй activity данные в виде объекта Intent:
Intent intent = result.getData();
Далее извлекаем из Intent строку, которая имеют ключ ACCESS_MESSAGE, и выводим ее в текстовое поле.
Таким образом, мы определили объект ActivityResultLauncher . Далее в обработчике нажатия onClick с помощью этого объекта запускаем вторую activity — SecondActivity:
public void onClick(View view) < // получаем введенный возраст EditText ageBox = findViewById(R.id.age); String age = ageBox.getText().toString(); Intent intent = new Intent(this, SecondActivity.class); intent.putExtra(AGE_KEY, age); mStartForResult.launch(intent); >
В обработчике нажатия кнопки onClick() получаем введенный в текстовое поле возраст, добавляем его в объект Intent с ключем AGE_KEY и запускаем SecondActivity с помощью метода launch()
Теперь перейдем к SecondActivity и определим в файле activity_second.xml набор кнопок:
А в классе SecondActivity определим обработчики для этих кнопок:
Три кнопки вызывают метод sendMessage() , в который передают отправляемый ответ. Это и будет то сообщение, которое получить MainActivity в методе onActivityResult.
Для возврата результата необходимо вызвать метод setResult() , в который передается два параметра:
- числовой код результата
- отправляемые данные
После вызова метода setResult() нужно вызвать метод finish , который уничтожит текущую activity.
Одна кнопка вызывает обработчик onCancelClick() , в котором передается в setResult только код результата — RESULT_CANCELED.
То есть условно говоря, мы получаем в SecondActivity введенный в MainActivity возраст и с помощью нажатия определенной кнопки возвращаем некоторый результат в виде сообщения.
В зависимости от нажатой кнопки на SecondActivity мы будем получать разные результаты в MainActivity:
Источник: metanit.com
Как обратиться к элементам Activity через Java-код?
Отслеживать
1,722 1 1 золотой знак 22 22 серебряных знака 42 42 бронзовых знака
задан 27 фев 2013 в 15:46
5,109 10 10 золотых знаков 47 47 серебряных знаков 96 96 бронзовых знаков
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
TableRow row = (TableRow) findViewById(R.id.TableRow01); row.setBackgroundColor(0);
этот код установит черный фон для TableRow
К сожалению, применить в коде именно стиль нельзя. по крайней мере я нашел только такие высказывания.
Отслеживать
ответ дан 27 фев 2013 в 15:59
Vladyslav Matviienko Vladyslav Matviienko
20.4k 2 2 золотых знака 28 28 серебряных знаков 51 51 бронзовый знак
Description Resource Path Location Type TableRow cannot be resolved to a type MainActivity.java /PaperPlanes/src/dlp/app/content/paperplanes/free line 9 Java Problem
27 фев 2013 в 16:17
- activity
- android
- java
-
Важное на Мете
Похожие
Подписаться на ленту
Лента вопроса
Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.
Источник: ru.stackoverflow.com