[Разработка под Android] Android Fragment Result Listener
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
В Android передача данных между фрагментами может осуществляться разными способами: передача через родительскую Activity, используя ViewModel или даже Fragments API. Fragment Target API с недавних пор получил статус Deprecated и вместо него Google рекомендует использовать Fragment result API.
Что такое Fragment result API? Это новый инструмент от Google который позволяет передавать данные между фрагментами по ключу. Для этого используется FragmentManager, который в свою очередь реализует интерфейс FragmentResultOwner. FragmentResultOwner выступает в качестве центрального хранилища для данных, которые мы передаем между фрагментами.
Как это работает?
Как упоминалось выше, наш FragmentManager реализует интерфейс FragmentResultOwner, который хранит в себе ConcurrentHashMap<String, Bundle>. Эта HashMap хранит наши Bundle-ы по строковому ключу. Как только один из фрагментов подписывается (или уже подписан) то он получает результат по тому самому ключу.
Что важно знать:
- Если какой-либо фрагмент подписывается на результат методом setResultFragmentListener() после того, как отправляющий фрагмент вызовет setFragmentResult(), то он немедленно получит результат
- Каждую связку “Key + Result (Bundle)“ фрагмент получает только 1 раз
- Фрагменты которые находятся в бек стеке получат результат только после того как перейдут в состояние STARTED
- После того как фрагмент перейдет в состояние DESTROYED мы больше не сможем подписываться на ResultListener
Как это выглядит в коде?
Передача данных
Для передачи данных в другой фрагмент нам необходимо вызвать метод:
FragmentManager.setFragmentResult(key: String, bundle: Bundle)
В параметры метода мы кладем ключ, который и будет нашим идентификатором для получения данных и сам Bundle. Этот Bundle будет содержать в себе передаваемые данные.
Kotlin
button.setOnClickListener {
val result = "result"
// Здесь мы можем использовать Kotlin экстеншен функцию из fragment-ktx
setFragmentResult("requestKey", bundleOf("bundleKey" to result))
}
Java
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Bundle result = new Bundle();
result.putString("bundleKey", "result");
getParentFragmentManager().setFragmentResult("requestKey", result);
}
});
Получение данных
Для получения данных через FragmentManager мы регистрируем наш FragmentResultListener и задаем ключ по которому мы будем получать данные. Тот самый ключ который мы указывали в методе FragmentManager.setFragmentResult()
Kotlin
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Здесь так же используется Kotlin экстеншен
setFragmentResultListener("requestKey") { key, bundle ->
// Здесь можно передать любой тип, поддерживаемый Bundle-ом
val result = bundle.getString("bundleKey")
}
}
Java
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getParentFragmentManager().setFragmentResultListener("key", this, new FragmentResultListener() {
@Override
public void onFragmentResult(@NonNull String key, @NonNull Bundle bundle) {
String result = bundle.getString("bundleKey");
}
});
}
Здесь мы видим 2 аргумента: key: String и bundle: Bundle.
Первый — это тот самый ключ, по которому мы передаем сюда данные. Второй — Bundle, в котором лежат переданные данные.
Parent Fragment Manger
Выбор FragmentManager-а для передачи данных между фрагментами зависит от принимающего фрагмента:
- Если оба фрагмента находятся в одном и том же FragmentManager (например оба фрагмента находятся в Activity), то мы должны использовать родительский FragmentManager, который хранит в себе Activity
- Если у нас один фрагмент вложен в другой фрагмент, то для передачи данных мы используем childFragmentManager (он же родительский фрагмент для принимающего фрагмента)
Важно понимать, что наш FragmentResultListener должен находиться в общем для двух фрагментов FragmentManager-е.
Тестирование
Для тестирования отправки/получения данных через FragmentResultListener, мы можем использовать FragmentScenario API, который предоставляет нам все преимущества тестирования фрагментов в изоляции.
Передача данных
Как мы можем протестировать, что наш фрагмент корректно отправляет данные через родительский FragmentManager? Для этого нам необходимо внутри теста отправить результат и проверить, что наш FragmentResultListener получил корректные данные:
@Test
fun testFragmentResult() {
val scenario = launchFragmentInContainer<ResultFragment>()
lateinit var actualResult: String?
scenario.onFragment { fragment ->
fragment.parentFragmentManagager.setResultListener("requestKey") { key, bundle ->
actualResult = bundle.getString("bundleKey")
}
}
onView(withId(R.id.result_button)).perform(click())
assertThat(actualResult).isEqualTo("result")
}
class ResultFragment : Fragment(R.layout.fragment_result) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
view.findViewById(R.id.result_button).setOnClickListener {
val result = "result"
setResult("requestKey", bundleOf("bundleKey" to result))
}
}
}
Получение данных
Для проверки корректности получения данных мы можем симулировать отправку данных, используя родительский FragmentManager. Если в отправляющем фрагменте корректно установлен FragmentResultListener мы должны получить корректные данные проверяя сам листенер или последствие их получения.
@Test
fun testFragmentResultListener() {
val scenario = launchFragmentInContainer<ResultListenerFragment>()
scenario.onFragment { fragment ->
val expectedResult = "result"
fragment.parentFragmentManagager.setResult("requestKey", bundleOf("bundleKey" to expectedResult))
assertThat(fragment.result).isEqualTo(expectedResult)
}
}
class ResultListenerFragment : Fragment() {
var result : String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setResultListener("requestKey") { key, bundle ->
result = bundle.getString("bundleKey")
}
}
}
Вывод
В данный момент FragmentResultListener находится в альфе, а это значит что возможно еще будут изменения со стороны Google. Но уже сейчас видно, что это достаточно крутой инструмент, для передачи данных между фрагментами, не создавая дополнительных интерфейсов и классов. Единственным нюансом остается, пожалуй то, что не совсем понятно, как и где лучше хранить ключи где, но это не кажется таким уж большим минусом.
Для того чтоб получить возможность использовать FragmentResultListener нам нужно подключить в зависимостях версию фрагментов 1.3.0-alpha04 или новее:
- Версия для Java: androidx.fragment:fragment:1.3.0-alpha04
- Версия для Kotlin: androidx.fragment:fragment-ktx:1.3.0-alpha04
- Тесты: androidx.fragment:fragment-testing:1.3.0-alpha04
===========
Источник:
habr.com
===========
Похожие новости:
- [Информационная безопасность, Гаджеты] В чипе Qualcomm Snapdragon нашли более 400 уязвимостей
- [Смартфоны, Будущее здесь, IT-компании] Google утверждает, что создала самую большую сеть обнаружения землетрясений
- [Смартфоны, Социальные сети и сообщества, IT-компании] WSJ: TikTok собирал MAC-адреса смартфонов пользователей на Android
- [Разработка под Android, Браузеры] Vivaldi 3.2 для Android — Ещё ближе к идеалу
- [Разработка под Android] Hilt еще один DI?
- [Разработка под Android, Обработка изображений, Машинное обучение, DIY или Сделай сам] Как с помощью HUAWEI ML Kit самостоятельно создать апплет для фото на документы
- [Разработка игр, Разработка под Android, Хакатоны] Делаем игру с управлением улыбкой
- [Разработка мобильных приложений, Разработка под Android] Top 5 Android App Development Companies To Seek in 2020
- [Программирование, Разработка мобильных приложений, Проектирование и рефакторинг, Управление разработкой] Какие навыки можно прокачать на проекте c большой кодовой базой
- [Разработка под iOS, Разработка под Android, Смартфоны, Накопители] Почему iPhone хватает 4 ГБ ОЗУ, а Android — нет?
Теги для поиска: #_razrabotka_pod_android (Разработка под Android), #_android, #_fragments, #_razrabotka_pod_android (
Разработка под Android
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 15:39
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
В Android передача данных между фрагментами может осуществляться разными способами: передача через родительскую Activity, используя ViewModel или даже Fragments API. Fragment Target API с недавних пор получил статус Deprecated и вместо него Google рекомендует использовать Fragment result API. Что такое Fragment result API? Это новый инструмент от Google который позволяет передавать данные между фрагментами по ключу. Для этого используется FragmentManager, который в свою очередь реализует интерфейс FragmentResultOwner. FragmentResultOwner выступает в качестве центрального хранилища для данных, которые мы передаем между фрагментами. Как это работает? Как упоминалось выше, наш FragmentManager реализует интерфейс FragmentResultOwner, который хранит в себе ConcurrentHashMap<String, Bundle>. Эта HashMap хранит наши Bundle-ы по строковому ключу. Как только один из фрагментов подписывается (или уже подписан) то он получает результат по тому самому ключу. Что важно знать:
Как это выглядит в коде? Передача данных Для передачи данных в другой фрагмент нам необходимо вызвать метод: FragmentManager.setFragmentResult(key: String, bundle: Bundle)
В параметры метода мы кладем ключ, который и будет нашим идентификатором для получения данных и сам Bundle. Этот Bundle будет содержать в себе передаваемые данные. Kotlin button.setOnClickListener {
val result = "result" // Здесь мы можем использовать Kotlin экстеншен функцию из fragment-ktx setFragmentResult("requestKey", bundleOf("bundleKey" to result)) } Java button.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) { Bundle result = new Bundle(); result.putString("bundleKey", "result"); getParentFragmentManager().setFragmentResult("requestKey", result); } }); Получение данных Для получения данных через FragmentManager мы регистрируем наш FragmentResultListener и задаем ключ по которому мы будем получать данные. Тот самый ключ который мы указывали в методе FragmentManager.setFragmentResult() Kotlin override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) // Здесь так же используется Kotlin экстеншен setFragmentResultListener("requestKey") { key, bundle -> // Здесь можно передать любой тип, поддерживаемый Bundle-ом val result = bundle.getString("bundleKey") } } Java @Override
public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); getParentFragmentManager().setFragmentResultListener("key", this, new FragmentResultListener() { @Override public void onFragmentResult(@NonNull String key, @NonNull Bundle bundle) { String result = bundle.getString("bundleKey"); } }); } Здесь мы видим 2 аргумента: key: String и bundle: Bundle. Первый — это тот самый ключ, по которому мы передаем сюда данные. Второй — Bundle, в котором лежат переданные данные. Parent Fragment Manger Выбор FragmentManager-а для передачи данных между фрагментами зависит от принимающего фрагмента:
Важно понимать, что наш FragmentResultListener должен находиться в общем для двух фрагментов FragmentManager-е. Тестирование Для тестирования отправки/получения данных через FragmentResultListener, мы можем использовать FragmentScenario API, который предоставляет нам все преимущества тестирования фрагментов в изоляции. Передача данных Как мы можем протестировать, что наш фрагмент корректно отправляет данные через родительский FragmentManager? Для этого нам необходимо внутри теста отправить результат и проверить, что наш FragmentResultListener получил корректные данные: @Test
fun testFragmentResult() { val scenario = launchFragmentInContainer<ResultFragment>() lateinit var actualResult: String? scenario.onFragment { fragment -> fragment.parentFragmentManagager.setResultListener("requestKey") { key, bundle -> actualResult = bundle.getString("bundleKey") } } onView(withId(R.id.result_button)).perform(click()) assertThat(actualResult).isEqualTo("result") } class ResultFragment : Fragment(R.layout.fragment_result) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { view.findViewById(R.id.result_button).setOnClickListener { val result = "result" setResult("requestKey", bundleOf("bundleKey" to result)) } } } Получение данных Для проверки корректности получения данных мы можем симулировать отправку данных, используя родительский FragmentManager. Если в отправляющем фрагменте корректно установлен FragmentResultListener мы должны получить корректные данные проверяя сам листенер или последствие их получения. @Test
fun testFragmentResultListener() { val scenario = launchFragmentInContainer<ResultListenerFragment>() scenario.onFragment { fragment -> val expectedResult = "result" fragment.parentFragmentManagager.setResult("requestKey", bundleOf("bundleKey" to expectedResult)) assertThat(fragment.result).isEqualTo(expectedResult) } } class ResultListenerFragment : Fragment() { var result : String? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setResultListener("requestKey") { key, bundle -> result = bundle.getString("bundleKey") } } } Вывод В данный момент FragmentResultListener находится в альфе, а это значит что возможно еще будут изменения со стороны Google. Но уже сейчас видно, что это достаточно крутой инструмент, для передачи данных между фрагментами, не создавая дополнительных интерфейсов и классов. Единственным нюансом остается, пожалуй то, что не совсем понятно, как и где лучше хранить ключи где, но это не кажется таким уж большим минусом. Для того чтоб получить возможность использовать FragmentResultListener нам нужно подключить в зависимостях версию фрагментов 1.3.0-alpha04 или новее:
=========== Источник: habr.com =========== Похожие новости:
Разработка под Android ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 15:39
Часовой пояс: UTC + 5