=====Communication===== [[https://developer.android.com/guide/fragments/communicate?hl=fr#java|Communiquer avec des fragments]] {{ :lang:android:fragment:communiquer_avec_des_fragments_android_developers_22_08_2023_16_08_14_.html |Archive du 30/05/2023 le 22/08/2023}} Le respect des bonnes pratiques de communication devrait permettre de ne pas avoir besoin d'utiliser ''runOnUiThread(...)''. ====Événements==== Seulement en Kotlin. [[https://developer.android.com/topic/architecture/ui-layer/events?hl=fr|Événements de l'UI]] {{ :lang:android:fragment:v_nements_de_l_ui_android_developers_23_08_2023_09_20_10_.html |Archive du 27/07/2023 le 23/08/2023}} ====FragmentResult==== Communication en temps réel. On stocke dans le ''FragmentManager'' une action a effectuée quand une clé est appelée. Puis on génère une événement avec cette clé avec éventuellement des données associées (ou un ''Bundle'' vide à défaut). * Génération de l'événement : getParentFragmentManager().setFragmentResult("key", new Bundle()) * Observateur : getSupportFragmentManager().setFragmentResultListener("key", this, (requestKey, result) -> {...}); On utilise ''getSupportFragmentManager()'' depuis une activity et ''getParentFragmentManager'' depuis un fragment. Il est aussi possible d'appeler ''clearFragmentResultListener'' depuis l'action de ''setFragmentResultListener'' si on souhaite, par exemple, que le listener n'écoute que le premier appel. [[https://medium.com/e-legion/getting-the-result-right-part-2-fragment-result-api-1a17f99490dc|The right way to get a result. Part 2. Fragment Result API]] {{ :lang:android:fragment:the_right_way_to_get_a_result._part_2._fragment_result_api_by_leonid_belyakov_e-legion_medium_22_08_2023_16_29_27_.html |Archive du 31/05/2021 le 22/08/2023}} ====LiveData==== Communication en temps réel. LiveData est un champ qui peut être observé. Il s'implémente sur la base d'une classe ViewModel. public class ItemViewModel extends ViewModel { private final MutableLiveData selectedItem = new MutableLiveData(); public void selectItem(Item item) { selectedItem.setValue(item); } public LiveData getSelectedItem() { return selectedItem; } } Ici, ''Item'' est soit une classe contenant une ou plusieurs données, soit la version classe d'un type primitif (''Boolean'', ''Float'', ...). Les données ''LiveData'' sont perdues à la fermeture de l'application. Si un observateur commence à surveiller un ''LiveData'' et qu'une valeur a déjà été assignée, la callback est immédiatement appelée (depuis le thread de l'UI). Un ''LiveData'' est commun à tous les éléments ayant le même cycle de vue du constructeur. * Observateur Depuis une activity, on utilise ''this'' avec ''ViewModelProvider'' car tous les fragments vont avoir la même Activity. Depuis un fragment, il faut utiliser ''requireActivity()'' avec ''ViewModelProvider''. Pour ''observe'', il faut utiliser ''this'' avec ''onCreate'' et ''getViewLifecycleOwner()'' avec ''onViewCreated'' et ''onActivityCreated''. [[https://stackoverflow.com/questions/57081763/livedata-observing-in-fragment|LiveData observing in Fragment]] {{ :lang:android:fragment:android_-_livedata_observing_in_fragment_-_stack_overflow_23_08_2023_09_05_56_.html |Archive du 17/07/2019 le 23/08/2023}} [[https://developer.android.com/guide/components/activities/activity-lifecycle#oncreate|The activity lifecycle#oncreate]] {{ :lang:android:fragment:the_activity_lifecycle_android_developers_23_08_2023_09_08_25_.html |Archive du 24/04/2023 le 23/08/2023}} [[https://developer.android.com/reference/androidx/fragment/app/Fragment.html#getViewLifecycleOwner()|Fragment#getViewLifecycleOwner]] {{ :lang:android:fragment:fragment_android_developers_23_08_2023_09_08_50_.html |Archive du 11/08/2023 le 23/08/2023}} public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); viewModel = new ViewModelProvider(this).get(ItemViewModel.class); viewModel.getSelectedItem().observe(this, item -> { // Perform an action with the latest item data. }); } * Modificateur Ici, depuis un fragment, on utilise ''requireActivity'' pour les mêmes raisons que ci-dessus. public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); viewModel = new ViewModelProvider(requireActivity()).get(ItemViewModel.class); ... viewModel.selectItem(item); } * Notes ''LiveData'' (avec ses méthodes ''observe'', ''setValue'') s'utilise depuis le thread de l'UI. Sinon, il existe ''postValue'' si on est en dehors du thread de l'UI. Il n'est pas possible de modifier ou d'observer uniquement un champ d'un item. Si c'est nécessaire, il faut passer par 2 variables ''LiveData'' différentes. Si un ''LiveData'' est modifié 2 fois avant qu'un observateur soit notifié, l'observateur ne verra que la dernière valeur. Il n'est pas possible d'enlever une valeur à un ''LiveData''. Donc si un observateur observe un ''LiveData'' qui n'a jamais été écrit, aucun événement instantané ne sera généré. Mais si une valeur a déjà été assignée, un événement instantané sera systématiquement généré.
If LiveData already has data set, it will be delivered to the observer[[https://developer.android.com/reference/androidx/lifecycle/LiveData#observe(androidx.lifecycle.LifecycleOwner,androidx.lifecycle.Observer%3C?%20super%20T%3E)|LiveData]] {{ :lang:android:fragment:livedata_android_developers_23_08_2023_11_46_53_.html |Archive du 11/08/2023 le 23/08/2023}}
====setArguments==== Passage de l'information avant le chargement du fragment. Depuis l'activity ou le fragment parent : final Bundle bundle = new Bundle(); bundle.putBoolean("param", true); fragment.setArguments(bundle); Depuis le fragment enfant : requireArguments().getBoolean("param"); =====Bouton back===== ====Appel manuel==== mainActivity.getSupportFragmentManager().popBackStack(); ====Changement de fragment==== Le comportement du bouton back se définit dans le ''FragmentManager'' au moment du chargement du nouveau fragment. fragmentManager.beginTransaction()... .addToBackStack(null) .commit(); Puis quand le bouton back sera appelé, les transactions seront inversées jusqu'au précédent appel à ''addToBackStack''. Evidemment, il est possible de faire plusieurs ''addToBackStack''. Il sera alors possible d'appuyer sur le bouton back autant de fois qu'il y aura eu de ''addToBackStack''. Chaque bouton back remontera d'un cran la pile des transactions. ====Depuis onBackPressed event==== Dans l'activity, il est possible de surcharger la méthode ''onBackPressed''. Mais cette méthode est dépréciée. Il faut utiliser : getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) { @Override public void handleOnBackPressed() { // Back is pressed... Finishing the activity finish(); } }); [[https://stackoverflow.com/questions/72634225/onbackpressed-is-deprecated-what-is-the-alternative|onBackPressed() is deprecated. What is the alternative?]] {{ :lang:android:fragment:android_-_onbackpressed_is_deprecated._what_is_the_alternative_-_stack_overflow_23_08_2023_09_36_51_.html |Archive du 27/07/2023 le 23/08/2023}} =====Binding===== Il existe ''View binding'' et ''Data binding''. Si l'objectif est seulement de remplacer les ''findViewById'', il faut utiliser ''View binding'' car plus léger. Si l'objectif est également de maîtriser les données lors de la reconstruction d'un fragment, ''Data binding'' est nécessaire. ====View binding==== ====Data binding==== * Chargement du fragment @Override @Nullable public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); binding = NameFragmentBinding.inflate(inflater, container, false); binding.setLifecycleOwner(getViewLifecycleOwner()); // Uniquement nécessaire si le binding est lié à un LiveData. return binding.getRoot(); } [[https://stackoverflow.com/questions/63336247/must-i-set-lifecycleowner-for-a-data-binding-in-android-studio)|Must I set lifecycleOwner for a data binding in Android Studio?]] {{ :lang:android:fragment:must_i_set_lifecycleowner_for_a_data_binding_in_android_studio_-_stack_overflow_23_08_2023_12_07_42_.html |Archive du 10/08/2020 le 23/08/2023}} [[https://developer.android.com/topic/libraries/data-binding/architecture|Bind layout views to Architecture Components]] {{ :lang:android:fragment:bind_layout_views_to_architecture_components_android_developers_23_08_2023_12_06_13_.html |Archive du 12/07/2023 le 23/08/2023}} * Utilisation des LiveData [[https://medium.com/swlh/basic-form-validation-in-android-with-live-data-and-data-binding-cb6b1d073717|Basic Form Validation in Android with Live Data and Data Binding]] {{ :lang:android:fragment:basic_form_validation_in_android_with_live_data_and_data_binding_by_brandon_wever_the_startup_medium_23_08_2023_12_12_03_.html |Archive du 07/10/2019 le 23/08/2023}} ====Problèmes===== Si une ressource ne génère pas le binding, il faut entourer la ressource par ''''.