{"id":29459,"date":"2024-11-22T05:00:00","date_gmt":"2024-11-22T04:00:00","guid":{"rendered":"https:\/\/sii.pl\/blog\/?p=29459"},"modified":"2024-11-07T14:27:49","modified_gmt":"2024-11-07T13:27:49","slug":"jetpack-compose-navigation-w-pigulce","status":"publish","type":"post","link":"https:\/\/sii.pl\/blog\/jetpack-compose-navigation-w-pigulce\/","title":{"rendered":"Jetpack Compose Navigation w pigu\u0142ce"},"content":{"rendered":"\n<p>Jetpack Compose jest nowoczesn\u0105 bibliotek\u0105 do tworzenia natywnych aplikacji na platform\u0119 Android. W znacznym stopniu usprawnia ona proces tworzenia interfejs\u00f3w u\u017cytkownika (UI), umo\u017cliwiaj\u0105c przygotowywanie ekran\u00f3w i komponent\u00f3w przy wykorzystaniu deklaratywnego kodu napisanego w j\u0119zyku Kotlin. Compose oferuje r\u00f3wnie\u017c w\u0142asny zestaw rozwi\u0105za\u0144 do zarz\u0105dzania nawigacj\u0105 w aplikacji.<\/p>\n\n\n\n<p>W artykule przyjrzymy si\u0119 temu, jak funkcjonuje nawigacja w Jetpack Compose, jak j\u0105 poprawnie zaimplementowa\u0107 oraz w jaki spos\u00f3b przekazywa\u0107 z\u0142o\u017cone struktury pomi\u0119dzy ekranami.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Implementacja w projekcie<\/strong><\/h2>\n\n\n\n<p>Aby zaimplementowa\u0107 w projekcie bibliotek\u0119 <em>navigation-compose<\/em>, musimy doda\u0107 odpowiedni\u0105 zale\u017cno\u015b\u0107 do pliku <em>build.gradle<\/em>:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image1.png\"><img decoding=\"async\" width=\"814\" height=\"172\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image1.png\" alt=\"Dodawanie zale\u017cno\u015bci do pliku build.gradle\" class=\"wp-image-29460\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image1.png 814w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image1-300x63.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image1-768x162.png 768w\" sizes=\"(max-width: 814px) 100vw, 814px\" \/><\/a><figcaption class=\"wp-element-caption\">Ryc. 1 Dodawanie zale\u017cno\u015bci do pliku <em>build.gradle (<\/em>\u0179r\u00f3d\u0142o: <a href=\"https:\/\/developer.android.com\/develop\/ui\/compose\/navigation#kts\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >developer.android.com<\/a>)<\/figcaption><\/figure>\n\n\n\n<p>Dok\u0142adny spos\u00f3b implementacji mo\u017ce si\u0119 r\u00f3\u017cni\u0107 zale\u017cnie od zastosowanego sposobu konfiguracji projektu.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Komponenty nawigacyjne Jetpack Compose<\/strong><\/h2>\n\n\n\n<p>Do zarz\u0105dzania nawigacj\u0105 przy z u\u017cyciem biblioteki <em>navigation-compose<\/em> wykorzystuje si\u0119 nast\u0119puj\u0105ce komponenty:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td class=\"has-text-align-center\" data-align=\"center\"><strong>Komponent<\/strong><strong><\/strong><\/td><td class=\"has-text-align-center\" data-align=\"center\"><strong>Charakterystyka<\/strong><strong><\/strong><\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\"><strong>NavHost<\/strong><\/td><td class=\"has-text-align-center\" data-align=\"center\">Komponent definiuj\u0105cy miejsce, w kt\u00f3rym odbywa si\u0119 nawigacja. Wy\u015bwietla aktualn\u0105 destynacj\u0119 aplikacji.<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\"><strong>NavController<\/strong><\/td><td class=\"has-text-align-center\" data-align=\"center\">Centralny komponent zarz\u0105dzaj\u0105cy nawigacj\u0105 pomi\u0119dzy destynacjami. Dysponuje metodami pozwalaj\u0105cy m.in na nawigowanie, obs\u0142ug\u0119 <em>deep link\u00f3w <\/em>i cofanie po destynacjach.<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\"><strong>NavGraph<\/strong><\/td><td class=\"has-text-align-center\" data-align=\"center\">Struktura danych definiuj\u0105ca wszystkie destynacje w aplikacji oraz okre\u015blaj\u0105ca jak s\u0105 ze sob\u0105 powi\u0105zane.<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\"><strong>Destination<\/strong><\/td><td class=\"has-text-align-center\" data-align=\"center\">W\u0119ze\u0142 w grafie nawigacyjnym, okre\u015blaj\u0105ce \u201emiejsce\u201d w aplikacji, do kt\u00f3rego chcemy nawigowa\u0107. W wi\u0119kszo\u015bci przypadk\u00f3w b\u0119dzie to ekran <em>composable\u2019owy<\/em>, chocia\u017c biblioteka umo\u017cliwia r\u00f3wnie\u017c stosowanie jako destynacji dialog\u00f3w oraz zagnie\u017cd\u017conych graf\u00f3w nawigacyjnych.<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\"><strong>Route<\/strong><\/td><td class=\"has-text-align-center\" data-align=\"center\">Komponent, kt\u00f3ry w spos\u00f3b unikatowy definiuje destynacj\u0119 (cel) nawigacji oraz wszelkie dane przez ni\u0105 wymagane.<\/td><\/tr><\/tbody><\/table><figcaption class=\"wp-element-caption\">Tab. 1 Komponenty do zarz\u0105dzania nawigacj\u0105<\/figcaption><\/figure>\n\n\n\n<p>Poni\u017cej przedstawiono przyk\u0142ad podstawowej struktury nawigacji:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image2.png\"><img decoding=\"async\" width=\"516\" height=\"326\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image2.png\" alt=\"Przyk\u0142ad podstawowej struktury nawigacji\" class=\"wp-image-29462\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image2.png 516w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image2-300x190.png 300w\" sizes=\"(max-width: 516px) 100vw, 516px\" \/><\/a><figcaption class=\"wp-element-caption\">Ryc. 2 Przyk\u0142ad podstawowej struktury nawigacji<\/figcaption><\/figure>\n\n\n\n<p>W powy\u017cszym przyk\u0142adzie:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Utworzony obiekt <em>navController<\/em> zarz\u0105dza nawigacj\u0105.<\/li>\n\n\n\n<li><em>NavHost<\/em> inicjuje struktur\u0119 nawigacji. Przekazane mu argumenty to utworzony wcze\u015bniej <em>navController<\/em> oraz <em>startDestination<\/em>, wskazuj\u0105ce na ekran pocz\u0105tkowy aplikacji (w tym przypadku <em>screenA<\/em>).<\/li>\n\n\n\n<li>W ciele <em>NavHosta<\/em> zdefiniowano <em>NavigationGraph<\/em>, wskazuj\u0105c poszczeg\u00f3lne destynacje aplikacji. W tym przypadku wyst\u0119puj\u0105 dwie destynacje <em>composable<\/em>: <em>screenA <\/em>oraz <em>screenB.<\/em><\/li>\n\n\n\n<li>Destynacje <em>composable<\/em> zawieraj\u0105 w sobie okre\u015blone ekrany w formie funkcji <em>composable.<\/em><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Przekazywanie danych w trakcie nawigacji \u2013 \u015bcie\u017cki z argumentami<\/strong><\/h2>\n\n\n\n<p>Cz\u0119stym scenariuszem w przypadku przygotowywania aplikacji mobilnej jest konieczno\u015b\u0107 przekazywania danych pomi\u0119dzy r\u00f3\u017cnymi ekranami. Jednym ze sposob\u00f3w realizacji tego zadania przy u\u017cyciu Jetpack Compose Navigation jest skorzystanie wykorzystanie \u015bcie\u017cek z argumentami.<\/p>\n\n\n\n<p>W celu przedstawienia tego konceptu zaplanowano scenariusz, w kt\u00f3rym z destynacji <em>screenA <\/em>nale\u017cy przekaza\u0107 do destynacji <em>screenB<\/em> takie dane jak <em>userId<\/em> oraz <em>userName<\/em>.<\/p>\n\n\n\n<p>Poni\u017cej przedstawiono przyk\u0142ad implementacyjny, b\u0119d\u0105cy rozszerzeniem wcze\u015bniej przygotowanego kodu:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image3.png\"><img decoding=\"async\" width=\"703\" height=\"759\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image3.png\" alt=\"Przyk\u0142ad implementacyjny \u2013 rozszerzenie\" class=\"wp-image-29464\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image3.png 703w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image3-278x300.png 278w\" sizes=\"(max-width: 703px) 100vw, 703px\" \/><\/a><figcaption class=\"wp-element-caption\"><span style=\"font-size:11.0pt;line-height:107%;\nfont-family:&quot;Arial&quot;,sans-serif;mso-fareast-font-family:Calibri;mso-fareast-theme-font:\nminor-latin;mso-ansi-language:PL;mso-fareast-language:EN-US;mso-bidi-language:\nAR-SA\">Ryc. 3 Przyk\u0142ad implementacyjny \u2013 rozszerzenie<\/span><\/figcaption><\/figure>\n\n\n\n<p>W powy\u017cszym przyk\u0142adzie:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><em>route<\/em> destynacji <em>screenB <\/em>zosta\u0142 rozszerzony o 2 argumenty: <em>userId <\/em>oraz <em>userName.<\/em><\/li>\n\n\n\n<li>Argumenty <em>userId<\/em> oraz <em>userName<\/em> zosta\u0142y wylistowane w polu <em>arguments<\/em>. Poza okre\u015bleniem nazw poszczeg\u00f3lnych argument\u00f3w wskazywany jest r\u00f3wnie\u017c ich typ \u2013 odpowiednio <em>NavType.IntType <\/em>dla <em>userId<\/em> oraz <em>NavType.StringType<\/em> dla <em>userName.<\/em><\/li>\n\n\n\n<li>W ciele destynacji <em>composable <\/em>nast\u0119puje pr\u00f3ba pobrania okre\u015blonych wcze\u015bniej argument\u00f3w z <em>NavBackStackEntry<\/em> poprzez podanie ich kluczy (<em>userId <\/em>oraz <em>userName<\/em>).<\/li>\n\n\n\n<li>Pobrane dane s\u0105 nast\u0119pnie przekazywane do ekranu <em>ScreenB.<\/em><\/li>\n<\/ul>\n\n\n\n<p>Wywo\u0142anie funkcji do nawigacji na <em>navControllerze<\/em> przy wykorzystaniu \u015bcie\u017cek z argumentami jest widoczne na poni\u017cszym przyk\u0142adzie prezentuj\u0105cym <em>@Composable<\/em> <em>ScreenA<\/em>:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image4.png\"><img decoding=\"async\" width=\"686\" height=\"478\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image4.png\" alt=\"Wywo\u0142anie funkcji do nawigacji \u2013 @Composable ScreenA\" class=\"wp-image-29466\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image4.png 686w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image4-300x209.png 300w\" sizes=\"(max-width: 686px) 100vw, 686px\" \/><\/a><figcaption class=\"wp-element-caption\">Ryc. 4 Wywo\u0142anie funkcji do nawigacji \u2013 @Composable ScreenA<\/figcaption><\/figure>\n\n\n\n<p>W powy\u017cszym przyk\u0142adzie:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Zadeklarowano argumenty <em>userId<\/em> oraz <em>userName<\/em> warto\u015bciami <em>123<\/em> oraz <em>Jacek.<\/em><\/li>\n\n\n\n<li>Nawigacja do destynacji screenB nast\u0119puje poprzez wywo\u0142anie ca\u0142ej \u015bcie\u017cki z argumentami: &#8222;<em>screenB\/${userId}\/${userName}&#8221;.<\/em><\/li>\n<\/ul>\n\n\n\n<p>Nawigacja przy wykorzystaniu \u015bcie\u017cek z argumentami jest prosta w implementacji i \u0142atwo rozszerzalna. Potencjalne problemy mog\u0105 by\u0107 spowodowane tym, i\u017c ten spos\u00f3b nie zapewnia <em>type<\/em> <em>safety<\/em>. Typ ka\u017cdegoz argument\u00f3w jest ustalany r\u0119cznie przez dewelopera, a ich poprawno\u015b\u0107 nie jest sprawdzana w trakcie kompilacji aplikacji. Wyst\u0119powanie b\u0142\u0119d\u00f3w podczas <em>runtime\u2019u<\/em> wyd\u0142u\u017ca proces developmentu. Dodatkowo podej\u015bcie \u015bcie\u017cek z argumentami wymusza pisanie du\u017cych ilo\u015bci kodu <em>boilerplate<\/em> w celu okre\u015blenia dok\u0142adnych adres\u00f3w destynacji oraz typ\u00f3w poszczeg\u00f3lnych argument\u00f3w.<\/p>\n\n\n\n<p>W przygotowanym przyk\u0142adzie do adres\u00f3w wykorzystano route\u2019y w postaci czystych obiekt\u00f3w <em>String.<\/em> W zastosowaniach komercyjnych korzysta si\u0119 z tego sposobu, zabezpieczaj\u0105c stringowe <em>route\u2019y<\/em> np. poprzez utworzenie <em>sealed<\/em> <em>class<\/em> i zapis adres\u00f3w w ich polach.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Przekazywanie danych w trakcie nawigacji \u2013 obiekty <em>typesafe @Serializable<\/em><\/strong><\/h2>\n\n\n\n<p>Google w swojej oficjalnej dokumentacji proponuje korzystanie z innej metody nawigacji w nowych projektach. Polega ona na wykorzystaniu obiekt\u00f3w i\/lub klas oznaczonych jako <em>@Serializable<\/em>, kt\u00f3re zast\u0119puj\u0105 om\u00f3wione wcze\u015bniej stringowe <em>route\u2019y.<\/em><\/p>\n\n\n\n<p>Aby m\u00f3c skorzysta\u0107 z tagowania <em>@Serializable <\/em>do nawigacji, konieczne jest dodanie odpowiedniej zale\u017cno\u015bci do pliku <em>build.gradle<\/em>:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" width=\"838\" height=\"138\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image5.png\" alt=\"\" class=\"wp-image-29468\" style=\"object-fit:cover\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image5.png 838w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image5-300x49.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image5-768x126.png 768w\" sizes=\"(max-width: 838px) 100vw, 838px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image6.png\"><img decoding=\"async\" width=\"836\" height=\"156\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image6.png\" alt=\"Dodanie zale\u017cno\u015bci do pliku build.gradle (\u0179r\u00f3d\u0142o: proandroiddev.com) \" class=\"wp-image-29470\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image6.png 836w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image6-300x56.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image6-768x143.png 768w\" sizes=\"(max-width: 836px) 100vw, 836px\" \/><\/a><figcaption class=\"wp-element-caption\">Ryc. 5 Dodanie zale\u017cno\u015bci do pliku <em>build.gradle<\/em> (\u0179r\u00f3d\u0142o: <a href=\"https:\/\/proandroiddev.com\/introduction-to-using-kotlin-serialization-5bbfcf735aba\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >proandroiddev.com<\/a>)<\/figcaption><\/figure>\n\n\n\n<p>Po synchronizacji mo\u017cliwe b\u0119dzie skorzystanie z tag\u00f3w <em>@Serializable<\/em> w celu przygotowania unikalnych obiekt\u00f3w i klas, kt\u00f3re pos\u0142u\u017c\u0105 w celach nawigacyjnych.<\/p>\n\n\n\n<p>Przyk\u0142ad implementacyjny przygotowa\u0142em poni\u017cej.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image7.png\"><img decoding=\"async\" width=\"418\" height=\"336\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image7.png\" alt=\"Przyk\u0142ad implementacyjny \u2013 @Serializable\" class=\"wp-image-29472\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image7.png 418w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image7-300x241.png 300w\" sizes=\"(max-width: 418px) 100vw, 418px\" \/><\/a><figcaption class=\"wp-element-caption\">Ryc. 6 Przyk\u0142ad implementacyjny \u2013 <em>@Serializable<\/em><\/figcaption><\/figure>\n\n\n\n<p>W powy\u017cszym przyk\u0142adzie:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Zadeklarowano <em>object ScreenA<\/em> pe\u0142ni\u0105cy funkcj\u0119 identyfikatora ekranu <em>@Composable ScreenA<\/em>. Nawigacja do ekranu <em>ScreenA<\/em> nie wymaga przekazania argument\u00f3w, dlatego wykorzystanie struktury <em>object<\/em> jest wystarczaj\u0105ce.<\/li>\n\n\n\n<li>Zadeklarowano <em>data class ScreenB<\/em> b\u0119d\u0105cy identyfikatorem ekranu <em>@Composable ScreenB.<\/em> Jak we wcze\u015bniej om\u00f3wionym przyk\u0142adzie, <em>ScreenB<\/em> oczekuje przekazania mu dw\u00f3ch argument\u00f3w: <em>userId <\/em>oraz <em>userName<\/em>. Z tego powodu indentyfikatorem jest <em>data class<\/em> z dwoma polami. Pole <em>userName<\/em> jest opcjonalne, dlatego zosta\u0142o oznaczone jako <em>nullable<\/em> z domy\u015bln\u0105 warto\u015bci\u0105.<\/li>\n<\/ul>\n\n\n\n<p>Po przygotowaniu identyfikator\u00f3w ekran\u00f3w w postaci klas i obiekt\u00f3w <em>@Serializable<\/em> mo\u017cliwe jest utworzenie nowego grafu nawigacyjnego. Wykorzystanie tego sposobu znacznie upraszcza struktur\u0119 grafu, co jest widoczne na za\u0142\u0105czonym przyk\u0142adzie:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image8.png\"><img decoding=\"async\" width=\"776\" height=\"572\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image8.png\" alt=\"Utworzenie nowego grafu nawigacyjnego\" class=\"wp-image-29474\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image8.png 776w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image8-300x221.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image8-768x566.png 768w\" sizes=\"(max-width: 776px) 100vw, 776px\" \/><\/a><figcaption class=\"wp-element-caption\">Ryc. 7 Utworzenie nowego grafu nawigacyjnego<\/figcaption><\/figure>\n\n\n\n<p>W powy\u017cszym przyk\u0142adzie:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><em>navController <\/em>zosta\u0142 utworzony w taki sam spos\u00f3b, jak przy nawigacji z <em>route\u2019ami.<\/em><\/li>\n\n\n\n<li>Jako <em>startDestination<\/em> wskazano <em>@Serializable object ScreenA.<\/em><\/li>\n\n\n\n<li>Destynacje <em>composable<\/em> maj\u0105 bezpo\u015brednio przekazany identyfikator <em>ScreenA <\/em>\/ <em>ScreenB.<\/em><\/li>\n\n\n\n<li>Dost\u0119p do przekazanych argument\u00f3w odbywa si\u0119 poprzez wywo\u0142anie metody <em>toRoute&lt;&gt;()<\/em> z okre\u015bleniem typu (w tym przypadku <em>ScreenB<\/em>).<\/li>\n<\/ul>\n\n\n\n<p>Wywo\u0142anie funkcji do nawigacji na <em>navControllerze<\/em> przy wykorzystaniu \u015bcie\u017cek z argumentami jest widoczny na poni\u017cszym przyk\u0142adzie prezentuj\u0105cym odpowiednio zmodyfikowany <em>@Composable<\/em> <em>ScreenA<\/em>:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image9.png\"><img decoding=\"async\" width=\"701\" height=\"725\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image9.png\" alt=\"Wywo\u0142anie funkcji do nawigacji na navControllerze \" class=\"wp-image-29476\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image9.png 701w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image9-290x300.png 290w\" sizes=\"(max-width: 701px) 100vw, 701px\" \/><\/a><figcaption class=\"wp-element-caption\">Ryc. 8 Wywo\u0142anie funkcji do nawigacji na <em>navControllerze<\/em><\/figcaption><\/figure>\n\n\n\n<p>W powy\u017cszym przyk\u0142adzie:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Nawigacja do ekranu <em>ScreenB<\/em> odbywa si\u0119 poprzez wywo\u0142anie metody <em>navigate()<\/em> na <em>navController<\/em>, z przekazaniem nowo utworzonego obiektu klasy <em>ScreenB<\/em> z odpowiednio okre\u015blonymi parametrami <em>userId <\/em>oraz <em>userName.<\/em><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Korzy\u015bci z wykorzystania obiekt\u00f3w i klas otagowanych jako <em>@Serializable<\/em><\/strong><\/h3>\n\n\n\n<p>Nawigacja przy wykorzystaniu obiekt\u00f3w i klas otagowanych jako <em>@Serializable<\/em> niesie za sob\u0105 wiele korzy\u015bci.<\/p>\n\n\n\n<p>Przede wszystkim jest to rozwi\u0105zanie <em>type safe<\/em>. Deweloper nie musi si\u0119 obawia\u0107 pope\u0142nienia pomy\u0142ki przy okre\u015blaniu typu argumentu w sytuacji, je\u017celi jest niezb\u0119dne przekazanie danych do kolejnego ekranu. Argumenty, jako pola <em>data class,<\/em> maj\u0105 z g\u00f3ry okre\u015blony typ, zatem w przypadku pomy\u0142ki niemo\u017cliwe b\u0119dzie skompilowanie aplikacji. Dodatkowo, opisane rozwi\u0105zanie jest zdecydowanie bardziej czytelne dzi\u0119ki braku konieczno\u015bci pisania kodu <em>boilerplate<\/em> okre\u015blaj\u0105cego typ i nazw\u0119 ka\u017cdego z argument\u00f3w nawigacyjnych.<\/p>\n\n\n\n<p><em>Type safe navigation<\/em> jest domy\u015blnym rozwi\u0105zaniem wskazywanym w dokumentacji Android do nawigacji pomi\u0119dzy ekranami jak i do przekazywania danych pomi\u0119dzy nimi. Nale\u017cy jednocze\u015bnie pami\u0119ta\u0107 o tym, \u017ce nie zaleca si\u0119 przekazywania skomplikowanych struktur w trakcie nawigacji. Dobr\u0105 praktyk\u0105 jest przekazywanie maksymalnie prostych informacji, jak np. klucz ID, a odczyt pozosta\u0142ych danych powinien nast\u0105pi\u0107 z oddzielnego \u017ar\u00f3d\u0142a, np. repozytorium. Dzi\u0119ki pojedynczemu \u017ar\u00f3d\u0142u prawdy b\u0119dziemy mieli pewno\u015b\u0107, \u017ce wymagane dane w naszej destynacji s\u0105 aktualne.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Nawigacja wstecz<\/strong><\/h2>\n\n\n\n<p>W Jetpack Compose nawigacja wstecz jest obs\u0142ugiwana za pomoc\u0105 funkcji <em>popBackStack(),<\/em> wywo\u0142ywanej<br>na <em>navControllerze.<\/em> Umo\u017cliwia ona cofni\u0119cie si\u0119 do poprzedniego ekranu poprzez usuni\u0119cie aktualnego ekranu ze stosu \u2013 w efekcie nast\u0119puje powr\u00f3t do poprzedniego widoku.<\/p>\n\n\n\n<p>W celu wykonania nawigacji wstecz do konkretnego ekranu znajduj\u0105cego si\u0119 na stosie nawigacyjnym mo\u017cliwe jest wywo\u0142anie jednej z metod b\u0119d\u0105cej przeci\u0105\u017ceniem <em>popBackStack()<\/em>. Identyfikator docelowej destynacji mo\u017cna przekaza\u0107 w formie <em>route<\/em> b\u0119d\u0105cej obiektem typu <em>String<\/em> lub przy wykorzystaniu obiekt\u00f3w i klas <em>@Serialized<\/em>, co zaprezentowano na poni\u017cszym przyk\u0142adzie:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image10.png\"><img decoding=\"async\" width=\"874\" height=\"717\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image10.png\" alt=\"Wywo\u0142anie jednej z metod b\u0119d\u0105cej przeci\u0105\u017ceniem popBackStack()\" class=\"wp-image-29478\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image10.png 874w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image10-300x246.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image10-768x630.png 768w\" sizes=\"(max-width: 874px) 100vw, 874px\" \/><\/a><figcaption class=\"wp-element-caption\"><span style=\"font-size:11.0pt;line-height:107%;\nfont-family:&quot;Arial&quot;,sans-serif;mso-fareast-font-family:Calibri;mso-fareast-theme-font:\nminor-latin;mso-ansi-language:PL;mso-fareast-language:EN-US;mso-bidi-language:\nAR-SA\">Ryc. 9 Wywo\u0142anie jednej z metod b\u0119d\u0105cej przeci\u0105\u017ceniem <i>popBackStack()<\/i><\/span><\/figcaption><\/figure>\n\n\n\n<p>W powy\u017cszym przyk\u0142adzie:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Na <em>navController<\/em> nast\u0119puje wywo\u0142anie przeci\u0105\u017conej metody <em>popBackStack()<\/em> z przekazaniem typu naszej destynacji <em>@Serialized ScreenA.<\/em><\/li>\n\n\n\n<li>Parametr <em>inclusive<\/em> w metodzie <em>popBackStack()<\/em> okre\u015bla, czy ze stosu nawigacyjnego ma r\u00f3wnie\u017c zosta\u0107 usuni\u0119ta destynacja, do kt\u00f3rej nast\u0119puje nawigacja wstecz.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Nawigacja wstecz z przekazywaniem argumentu<\/strong><\/h2>\n\n\n\n<p>Biblioteka nawigacyjna zapewnia narz\u0119dzia, kt\u00f3re umo\u017cliwiaj\u0105 nawigowanie wstecz do poprzednich ekran\u00f3w z przekazaniem informacji zwrotnej. Przes\u0142anie informacji obywa si\u0119 poprzez aktualizacj\u0119 <em>previousBackStackEntry <\/em>i <em>savedStateHandle <\/em>oraz odczyt przekazywanych danych na poziomie grafu nawigacyjnego<em>.<\/em><\/p>\n\n\n\n<p>Poni\u017cej znajdziecie wcze\u015bniejszy przyk\u0142ad zmodyfikowany o mo\u017cliwo\u015b\u0107 przes\u0142ania informacji podczas nawigacji wstecz:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image11.png\"><img decoding=\"async\" width=\"840\" height=\"818\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image11.png\" alt=\"Przesy\u0142ania informacji podczas nawigacji wstecz\" class=\"wp-image-29480\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image11.png 840w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image11-300x292.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image11-768x748.png 768w\" sizes=\"(max-width: 840px) 100vw, 840px\" \/><\/a><figcaption class=\"wp-element-caption\">Ryc. 10 Przesy\u0142ania informacji podczas nawigacji wstecz<\/figcaption><\/figure>\n\n\n\n<p>W powy\u017cszym przyk\u0142adzie:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><em>navController <\/em>umo\u017cliwia dost\u0119p do <em>previousBackStackEntry<\/em>, sk\u0105d mo\u017cliwe jest wywo\u0142anie <em>savedStateHandle.<\/em><\/li>\n\n\n\n<li>W <em>savedStateHandle <\/em>mo\u017cliwe jest ustawienie argumentu w postaci <em>klucz-warto\u015b\u0107 (key-value)<\/em>, w tym przypadku kluczem jest <em>numer<\/em>, a warto\u015b\u0107 to <em>456.<\/em><\/li>\n\n\n\n<li>Nast\u0119pnie nast\u0119puje faktyczna nawigacja poprzez wywo\u0142anie metody <em>popBackStack() <\/em>na <em>navControllerze.<\/em><\/li>\n<\/ul>\n\n\n\n<p>W celu pozyskania danych przekazywanych wstecz konieczna by\u0142a aktualizacja grafu nawigacyjnego, co przedstawiono poni\u017cej:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image12.png\"><img decoding=\"async\" width=\"802\" height=\"583\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image12.png\" alt=\"Aktualizacja grafu nawigacyjnego\" class=\"wp-image-29482\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image12.png 802w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image12-300x218.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/image12-768x558.png 768w\" sizes=\"(max-width: 802px) 100vw, 802px\" \/><\/a><figcaption class=\"wp-element-caption\">Ryc. 11 Aktualizacja grafu nawigacyjnego<\/figcaption><\/figure>\n\n\n\n<p>W powy\u017cszym przyk\u0142adzie:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>W <em>composable&lt;ScreenA&gt;<\/em> poprzez odwo\u0142anie do <em>savedStateHandle<\/em> i odniesienie si\u0119 do klucza <em>number<\/em> tworzony jest obiekt <em>number<\/em> \u2013 maj\u0105cy warto\u015b\u0107 przekazan\u0105 z ekranu <em>ScreenB (456).<\/em><\/li>\n\n\n\n<li>Pozyskana informacja w postaci obiektu <em>number<\/em> jest przekazywana do ekranu <em>ScreenA.<\/em><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Podsumowanie<\/strong><\/h2>\n\n\n\n<p>Nawigowanie mi\u0119dzy ekranami to nieod\u0142\u0105czny element niemal ka\u017cdej aplikacji mobilnej. Poznanie i zrozumienie narz\u0119dzi, kt\u00f3re to umo\u017cliwiaj\u0105, jest <strong>kluczowe do tworzenia nowoczesnych aplikacji na platform\u0119 Android szybko i efektywnie.<\/strong><\/p>\n\n\n\n<p>Nawigacja w Jetpack Compose jak i w samym systemie Android to bardzo obszerne zagadnienia, kt\u00f3rych sam opis techniczny w dokumentacji jest zawarty w kilkudziesi\u0119ciu stronach. W artykule przedstawi\u0142em jedynie podstawowe koncepty i przyk\u0142ady dotycz\u0105ce implementacji nawigacji w Jetpack Compose. Stanowi\u0105 one jednak solidn\u0105 podstaw\u0119 do dalszego poznawania technologii, pr\u00f3bowania rozwi\u0105za\u0144 i wykorzystywania jej w praktyce.<\/p>\n\n\n\n<p>***<\/p>\n\n\n\n<p>Je\u015bli interesuje Ci\u0119 obszar mobile, zajrzyj r\u00f3wnie\u017c <a href=\"https:\/\/sii.pl\/blog\/wyszukiwarka\/mobile\/\" target=\"_blank\" aria-label=\"do innych artyku\u0142\u00f3w naszych specjalist\u00f3w (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\">do innych artyku\u0142\u00f3w naszych specjalist\u00f3w<\/a>. <\/p>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;29459&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;12&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;11&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;5\\\/5 ( votes: 12)&quot;,&quot;size&quot;:&quot;18&quot;,&quot;title&quot;:&quot;Jetpack Compose Navigation w pigu\u0142ce&quot;,&quot;width&quot;:&quot;139.5&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} ( {votes}: {count})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 139.5px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 14.4px;\">\n            5\/5 ( votes: 12)    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>Jetpack Compose jest nowoczesn\u0105 bibliotek\u0105 do tworzenia natywnych aplikacji na platform\u0119 Android. W znacznym stopniu usprawnia ona proces tworzenia interfejs\u00f3w &hellip; <a class=\"continued-btn\" href=\"https:\/\/sii.pl\/blog\/jetpack-compose-navigation-w-pigulce\/\">Continued<\/a><\/p>\n","protected":false},"author":683,"featured_media":29485,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_editorskit_title_hidden":false,"_editorskit_reading_time":0,"_editorskit_is_block_options_detached":false,"_editorskit_block_options_position":"{}","inline_featured_image":false,"footnotes":""},"categories":[1314],"tags":[2739,2427,1546,1512,275],"class_list":["post-29459","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development-na-twardo","tag-jetpack-compose-navigation","tag-digital","tag-przeglad-narzedzi","tag-poradnik","tag-mobile"],"acf":[],"aioseo_notices":[],"republish_history":[],"featured_media_url":"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/11\/Jetpack-Compose-Navigation-w-pigulce.jpg","category_names":["Development na twardo"],"_links":{"self":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/29459"}],"collection":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/users\/683"}],"replies":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/comments?post=29459"}],"version-history":[{"count":3,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/29459\/revisions"}],"predecessor-version":[{"id":29488,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/29459\/revisions\/29488"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media\/29485"}],"wp:attachment":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media?parent=29459"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/categories?post=29459"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/tags?post=29459"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}