Intencje – Intent
Jak przechodzić między ekranami aplikacji Android, przekazywać dane oraz przesyłać całe obiekty. Każdy nowy ekran tworzony ręcznie – zobaczysz dokładnie jak pliki są ze sobą powiązane.
Jak zbudowana jest aplikacja Android
Aplikacja Android składa się z wielu ekranów. Każdy ekran to osobna aktywność (ang. Activity). Żeby przejść z jednego ekranu na drugi, wysyłamy intencję (ang. Intent).
Intent to obiekt klasy Androida, który pełni rolę wiadomości lub rozkazu. Możesz powiedzieć Androidowi: „otwórz ekran X” albo „otwórz ekran X i przekaż mu te dane„. Android odbierze wiadomość, znajdzie właściwy ekran i go uruchomi.
Jawna (explicit) – wskazujesz konkretną klasę aktywności. Używana wewnątrz swojej aplikacji: Intent(this, DrugaActivity.class).
Niejawna (implicit) – mówisz tylko co chcesz zrobić, np. „wyświetl URL”. Android sam wybiera aplikację, która to obsłuży.
Trzy pliki składające się na jeden ekran
Zanim napiszemy pierwszy Intent, musisz zrozumieć jak Android „składa” ekran z trzech niezależnych plików. Każdy z nich odpowiada za coś innego i pliki te są ze sobą ściśle powiązane.
| Plik | Do czego służy | Gdzie w projekcie |
|---|---|---|
activity_xxx.xml | Wygląd – rozmieszczenie przycisków, pól, tekstów na ekranie | res/layout/ |
XxxActivity.java/.kt | Logika – co się dzieje po kliknięciu, jak reaguje na zdarzenia | java/ lub kotlin/ |
AndroidManifest.xml | Rejestracja – informuje Android OS że taka aktywność istnieje w aplikacji | app/manifests/ |
Te trzy pliki łączą się ze sobą w konkretnych miejscach. Poniżej widać gdzie dokładnie:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" ...> <Button android:id="@+id/btnPrzejdz" android:text="Przejdź" ... /> </LinearLayout>
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // ← łączy klasę z plikiem XML } }
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // ← łączy klasę z plikiem XML } }
<application ...> <activity android:name=".MainActivity"> <!-- ← rejestruje klasę w OS --> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application>
Powiązanie XML ↔ Klasa tworzy setContentView(R.layout.activity_main) – nazwa po R.layout. musi być identyczna z nazwą pliku XML.
Powiązanie Klasa ↔ Manifest tworzy android:name=".MainActivity" – nazwa po kropce musi być identyczna z nazwą klasy Java/Kotlin.
Każdy nowy ekran wymaga wszystkich trzech powiązań. Brak któregokolwiek to błąd lub crash aplikacji.
Przykład – aplikacja z dwoma ekranami
Zbudujemy aplikację krok po kroku: kliknięcie przycisku na pierwszym ekranie przenosi użytkownika na drugi ekran. Każdy plik tworzymy ręcznie, żebyś widział jak zbudowane jest powiązanie między nimi.
Kreator „New → Activity” tworzy wszystkie pliki automatycznie i ukrywa połączenia między nimi. Robiąc to ręcznie, widzisz każde powiązanie: plik XML, klasę Activity i wpis w Manifeście tworzysz osobno i rozumiesz, czemu każdy z nich jest potrzebny.
Krok 1 – tworzymy layout drugiego ekranu
W panelu projektu kliknij prawym przyciskiem myszy folder res/layout, wybierz New → Layout Resource File. W polu File name wpisz activity_druga i kliknij OK.
Wpisz samo activity_druga – Android Studio doda .xml automatycznie. Wpisanie activity_druga.xml spowoduje, że plik będzie miał podwójne rozszerzenie.
Kiedy plik się otworzy, przełącz edytor na widok kodu (zakładka Code w prawym górnym rogu) i wpisz:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:gravity="center" android:padding="24dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="To jest drugi ekran!" android:textSize="22sp" android:layout_marginBottom="32dp" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Wróć" android:onClick="wrocWstecz" /> <!-- musi istnieć metoda o tej nazwie w klasie --> </LinearLayout>
Krok 2 – tworzymy klasę DrugaActivity
Kliknij prawym przyciskiem myszy na pakiet z klasami (np. java/com/example/apka), wybierz New → Java Class (lub Kotlin Class/File). Wpisz nazwę DrugaActivity.
Otwiera się pusty plik. Wpisz poniższy kod. Zwróć uwagę na dwa kluczowe powiązania:
package com.example.apka; // wpisz nazwę pakietu swojego projektu import android.os.Bundle; import android.view.View; import androidx.appcompat.app.AppCompatActivity; public class DrugaActivity extends AppCompatActivity { // każdy ekran dziedziczy po AppCompatActivity @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_druga); // ← połączenie: klasa ↔ plik XML } // Metoda o nazwie identycznej z android:onClick="wrocWstecz" w XML public void wrocWstecz(View v) { finish(); // zamknij ten ekran – Android wróci do poprzedniego } }
package com.example.apka import android.os.Bundle import android.view.View import androidx.appcompat.app.AppCompatActivity class DrugaActivity : AppCompatActivity() { // każdy ekran dziedziczy po AppCompatActivity override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_druga) // ← połączenie: klasa ↔ plik XML } // Metoda o nazwie identycznej z android:onClick="wrocWstecz" w XML fun wrocWstecz(v: View) { finish() // zamknij ten ekran – Android wróci do poprzedniego } }
Metoda wskazana w android:onClick musi spełniać trzy warunki: być publiczna (public), zwracać void (nic nie zwracać) i przyjmować jeden parametr View v. Android przekazuje w tym parametrze referencję do widoku który kliknięto. Brak któregokolwiek warunku = crash w trakcie działania aplikacji.
Krok 3 – rejestrujemy DrugaActivity w Manifeście
Otwórz plik AndroidManifest.xml (znajdziesz go w app/manifests/). Wewnątrz tagu <application> dopisz jeden wiersz dla nowego ekranu.
To najczęstszy błąd początkujących. Klasa DrugaActivity istnieje, layout istnieje – ale Android OS nie wie że ta klasa jest ekranem tej aplikacji. Manifest to oficjalna lista ekranów aplikacji. Bez wpisu aplikacja kompiluje się bez błędów, ale w chwili uruchomienia intencji wyrzuca wyjątek: ActivityNotFoundException.
<application android:allowBackup="true" android:label="@string/app_name" android:theme="@style/Theme.Apka"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <!-- NOWY WIERSZ: rejestracja drugiego ekranu --> <activity android:name=".DrugaActivity" /> <!-- kropka + nazwa klasy --> </application>
Zapis ".DrugaActivity" to skrót. Android uzupełnia go pełną nazwą pakietu z atrybutu package na początku pliku Manifest, np. com.example.apka.DrugaActivity. Możesz też wpisać pełną nazwę – efekt ten sam. Ważne: nazwa po kropce musi być identyczna z nazwą klasy.
Krok 4 – wysyłamy Intent z MainActivity
Teraz uzupełniamy activity_main.xml o przycisk i MainActivity o metodę która wyśle intencję. Layout główny zapewne już masz – dopisz lub zmień przycisk tak, żeby wskazywał na metodę przejdz.
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Przejdź na drugi ekran" android:onClick="przejdz" /> <!-- nazwa metody musi istnieć w MainActivity -->
public void przejdz(View v) { // Intent(kontekst, klasa docelowa) // kontekst = aktywność w której jesteśmy (this) // klasa docelowa = ekran który chcemy otworzyć Intent intent = new Intent(this, DrugaActivity.class); // przekaż intencję systemowi – Android otworzy DrugaActivity startActivity(intent); }
fun przejdz(v: View) { // ::class.java – Kotlin wymaga tego zapisu zamiast .class val intent = Intent(this, DrugaActivity::class.java) startActivity(intent) }
Uruchom aplikację. Kliknięcie przycisku otworzy drugi ekran. Przycisk „Wróć” oraz systemowy przycisk Back zamkną drugi ekran i wrócą do pierwszego.
activity_main.xml → android:onClick="przejdz" → metoda przejdz() w MainActivity
MainActivity → setContentView(R.layout.activity_main) → plik activity_main.xml
MainActivity → Intent(this, DrugaActivity.class) → klasa DrugaActivity
DrugaActivity → setContentView(R.layout.activity_druga) → plik activity_druga.xml
AndroidManifest.xml → android:name=".DrugaActivity" → klasa DrugaActivity
Przekazywanie danych między ekranami
Intent może nieść ze sobą dane – jak koperta z listem. Metoda putExtra() „wkłada” dane do intencji, a metoda getExtras() je „wyjmuje” po drugiej stronie. Każda wartość jest opisana kluczem – unikalnym Stringiem który musi być ten sam po obu stronach.
Wysyłanie – putExtra(klucz, wartość)
Rozbudujemy poprzedni przykład: na pierwszym ekranie użytkownik wpisuje imię i wiek, na drugim ekranie te dane są wyświetlane.
Klucz w putExtra("KLUCZ_IMIE", imie) i w getString("KLUCZ_IMIE") musi być dokładnie ten sam. Wpisujemy go bezpośrednio jako tekst w obu miejscach. Jeśli się pomylisz w literowaniu – dane po prostu nie dotrą (getString zwróci null), bez żadnego błędu kompilacji. Dlatego warto pisać klucze wielkimi literami – wizualnie wyróżniają się w kodzie i łatwiej je zauważyć.
Zaktualizuj layout główny – dodaj pola EditText:
<LinearLayout ...orientation="vertical" android:padding="24dp"> <EditText android:id="@+id/etImie" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Wpisz imię" android:inputType="textPersonName" android:layout_marginBottom="12dp" /> <EditText android:id="@+id/etWiek" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Wpisz wiek" android:inputType="number" android:layout_marginBottom="24dp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Pokaż profil" android:onClick="przejdz" /> </LinearLayout>
Zaktualizuj layout drugiego ekranu – dodaj pola TextView do wyświetlenia danych:
<LinearLayout ...orientation="vertical" android:gravity="center" android:padding="32dp"> <TextView android:id="@+id/tvImie" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="20sp" android:layout_marginBottom="8dp" /> <TextView android:id="@+id/tvWiek" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="20sp" android:layout_marginBottom="32dp" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Wróć" android:onClick="wrocWstecz" /> </LinearLayout>
Teraz zaktualizuj MainActivity – metoda przejdz pobiera dane z pól i pakuje je do intencji:
public class MainActivity extends AppCompatActivity { // Pola klasy – dostępne we wszystkich metodach, nie tylko w onCreate EditText etImie; EditText etWiek; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initUI(); // inicjalizacja widoków w osobnej metodzie – porządek w kodzie } // Metoda przypisana do przycisku android:onClick="zapiszDane" w XML public void zapiszDane(View v) { String imie = etImie.getText().toString(); int wiek = Integer.parseInt(etWiek.getText().toString()); Intent intencja = new Intent(this, DrugaActivity.class); // Dodajemy do intencji klucz-wartość – pakujemy dane intencja.putExtra("KLUCZ_IMIE", imie); intencja.putExtra("KLUCZ_WIEK", wiek); startActivity(intencja); } public void initUI() { etImie = findViewById(R.id.etImie); etWiek = findViewById(R.id.etWiek); } }
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } fun przejdz(v: View) { val imie = findViewById<EditText>(R.id.etImie).text.toString() val wiek = findViewById<EditText>(R.id.etWiek).text.toString().toInt() val intent = Intent(this, DrugaActivity::class.java) // putExtra(klucz, wartość) – klucz musi być identyczny przy odbieraniu intent.putExtra("KLUCZ_IMIE", imie) intent.putExtra("KLUCZ_WIEK", wiek) startActivity(intent) } }
Odbieranie – getIntent().getExtras()
W DrugaActivity pobieramy dane które zostały spakowane przez putExtra(). Używamy dokładnie tych samych kluczy – te same stringi które wpisaliśmy w putExtra().
public class DrugaActivity extends AppCompatActivity { // Pola klasy – dostępne we wszystkich metodach TextView tvImie; TextView tvWiek; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_druga); tvImie = findViewById(R.id.tvImie); tvWiek = findViewById(R.id.tvWiek); // getIntent() zwraca intencję która uruchomiła ten ekran // getExtras() zwraca Bundle – paczkę ze wszystkimi danymi z putExtra() Bundle dane = getIntent().getExtras(); // getExtras() może zwrócić null gdy nikt nie wysłał danych // Sprawdzamy null żeby nie dostać NullPointerException if (dane != null) { // Odczytaj wartości – TEN SAM klucz co przy putExtra() String imie = dane.getString("KLUCZ_IMIE"); int wiek = dane.getInt("KLUCZ_WIEK"); tvImie.setText("Imię: " + imie); tvWiek.setText("Wiek: " + wiek); } } public void wrocWstecz(View v) { finish(); // zamknięcie ekranu – Android wraca do poprzedniego } }
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_druga) // Kotlin: intent.extras zamiast getIntent().getExtras() val dane = intent.extras // dane?.let { } – wykonaj blok TYLKO gdy dane nie jest null dane?.let { val imie = it.getString("KLUCZ_IMIE") val wiek = it.getInt("KLUCZ_WIEK") findViewById<TextView>(R.id.tvImie).text = "Imię: $imie" findViewById<TextView>(R.id.tvWiek).text = "Wiek: $wiek lat" } }
Dostępne typy w putExtra i getXxxExtra
| Typ | putExtra | odczyt z Bundle |
|---|---|---|
String | putExtra("k", "tekst") | bundle.getString("k") |
int | putExtra("k", 42) | bundle.getInt("k") |
double | putExtra("k", 3.14) | bundle.getDouble("k") |
boolean | putExtra("k", true) | bundle.getBoolean("k") |
long | putExtra("k", 100L) | bundle.getLong("k") |
| własna klasa | wymaga Serializable lub Parcelable → sekcja 5 | – |
Przekazywanie całego obiektu
Gdy danych jest więcej, wygodniej spakować je w obiekt własnej klasy i przesłać go jako jedną wartość. Intent transportuje dane jako ciąg bajtów, więc obiekt musi umieć się na bajty zamienić (serializacja) i z powrotem (deserializacja).
Mamy dwa sposoby na nauczenie klasy serializacji. Opisane poniżej.
Sposób 1 – Serializable (proste, zero kodu)
Tworzymy nowy plik klasy: prawy klik na pakiet → New → Java Class / Kotlin Class, nazwa: Uczen. Jedyną zmianą jest dodanie implements Serializable (Java) lub : Serializable (Kotlin) do deklaracji klasy. Żadnego dodatkowego kodu – Java i Kotlin same wiedzą jak serializować pola.
package com.example.apka; import java.io.Serializable; // Jedyna zmiana względem zwykłej klasy: "implements Serializable" public class Uczen implements Serializable { private String imie; private int wiek; private String klasa; public Uczen(String imie, int wiek, String klasa) { this.imie = imie; this.wiek = wiek; this.klasa = klasa; } public String getImie() { return imie; } public int getWiek() { return wiek; } public String getKlasa() { return klasa; } }
package com.example.apka // data class generuje automatycznie gettery, equals, toString, copy // Jedyna zmiana: ": Serializable" – nic więcej nie trzeba pisać data class Uczen( val imie : String, val wiek : Int, val klasa : String ) : Serializable
Wysyłanie i odbieranie obiektu wygląda tak samo jak dla zwykłych typów, tylko metoda odczytu jest inna:
public void przejdz(View v) { String imie = ((EditText) findViewById(R.id.etImie)).getText().toString(); int wiek = Integer.parseInt(((EditText) findViewById(R.id.etWiek)).getText().toString()); String klasa = ((EditText) findViewById(R.id.etKlasa)).getText().toString(); // Tworzymy obiekt i pakujemy go jako jedną wartość – putExtra działa tak samo jak dla String Uczen uczen = new Uczen(imie, wiek, klasa); Intent intent = new Intent(this, DrugaActivity.class); intent.putExtra("KLUCZ_UCZEN", uczen); // działa bo Uczen implements Serializable startActivity(intent); }
fun przejdz(v: View) { val imie = findViewById<EditText>(R.id.etImie).text.toString() val wiek = findViewById<EditText>(R.id.etWiek).text.toString().toInt() val klasa = findViewById<EditText>(R.id.etKlasa).text.toString() val uczen = Uczen(imie, wiek, klasa) val intent = Intent(this, DrugaActivity::class.java) intent.putExtra("KLUCZ_UCZEN", uczen) startActivity(intent) }
Bundle dane = getIntent().getExtras(); if (dane != null) { // getSerializable() zwraca typ Serializable – potrzebne rzutowanie (cast) na Uczen Uczen u = (Uczen) dane.getSerializable("KLUCZ_UCZEN"); if (u != null) { ((TextView) findViewById(R.id.tvImie)) .setText("Imię: " + u.getImie()); ((TextView) findViewById(R.id.tvWiek)) .setText("Wiek: " + u.getWiek() + " lat"); ((TextView) findViewById(R.id.tvKlasa)).setText("Klasa: " + u.getKlasa()); } }
intent.extras?.let { // as? – bezpieczne rzutowanie: null zamiast wyjątku gdy typ się nie zgadza val u = it.getSerializable("KLUCZ_UCZEN") as? Uczen u?.let { findViewById<TextView>(R.id.tvImie).text = "Imię: ${it.imie}" findViewById<TextView>(R.id.tvWiek).text = "Wiek: ${it.wiek} lat" findViewById<TextView>(R.id.tvKlasa).text = "Klasa: ${it.klasa}" } }
Sposób 2 – Parcelable (wydajne, zalecane przez Android)
Parcelable to interfejs natywny dla Androida. Jest szybszy od Serializable bo nie korzysta z refleksji – Android wie dokładnie jak czytać i zapisywać każde pole. W Javie trzeba to opisać ręcznie. W Kotlinie adnotacja @Parcelize generuje cały wymagany kod automatycznie.
public class Uczen implements Parcelable { private String imie; private int wiek; private String klasa; // Zwykły konstruktor – tworzymy obiekt normalnie public Uczen(String imie, int wiek, String klasa) { this.imie = imie; this.wiek = wiek; this.klasa = klasa; } // Specjalny konstruktor – Android wywołuje go PO STRONIE ODBIORCY // Odczytuje dane z Parcel w tej samej kolejności co writeToParcel protected Uczen(Parcel in) { imie = in.readString(); // 1. wiek = in.readInt(); // 2. klasa = in.readString(); // 3. } // Android wywołuje tę metodę PO STRONIE NADAWCY // Kolejność write MUSI być identyczna z kolejnością read powyżej @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(imie); // 1. dest.writeInt(wiek); // 2. dest.writeString(klasa); // 3. } @Override public int describeContents() { return 0; } // Wymagana fabryka – Android używa jej żeby odtworzyć obiekt ze strumienia bajtów public static final Creator<Uczen> CREATOR = new Creator<Uczen>() { @Override public Uczen createFromParcel(Parcel in) { return new Uczen(in); } @Override public Uczen[] newArray(int size) { return new Uczen[size]; } }; public String getImie() { return imie; } public int getWiek() { return wiek; } public String getKlasa() { return klasa; } }
Jeśli w writeToParcel() zapiszesz kolejno imie → wiek → klasa, to w konstruktorze Uczen(Parcel in) musisz odczytywać w tej samej kolejności. Przestawienie kolejności spowoduje, że pola dostaną złe wartości – i to bez żadnego błędu kompilacji.
import android.os.Parcelable import kotlinx.android.parcel.Parcelize // @Parcelize generuje automatycznie cały kod który Java wymaga pisać ręcznie: // konstruktor Parcel, writeToParcel, describeContents, CREATOR @Parcelize data class Uczen( val imie : String, val wiek : Int, val klasa : String ) : Parcelable
W pliku build.gradle (Module: app) w sekcji plugins { } dopisz wiersz i kliknij Sync Now:
id("kotlin-parcelize")Bez tego pluginu Android Studio nie rozpozna adnotacji @Parcelize i zgłosi błąd kompilacji.
Wysyłanie jest identyczne jak przy Serializable. Przy odbieraniu używamy getParcelable() zamiast getSerializable():
// Tylko ta jedna linia różni się od wersji Serializable // Nie potrzeba rzutowania – getParcelable jest generyczne Uczen u = dane.getParcelable("KLUCZ_UCZEN");
// API 33+ – typowana wersja bez rzutowania val u = it.getParcelable("KLUCZ_UCZEN", Uczen::class.java) // Kompatybilne ze starszymi wersjami Androida // val u = it.getParcelable<Uczen>("KLUCZ_UCZEN")
| Serializable | Parcelable | |
|---|---|---|
| Ilość kodu | Jedno słowo – nic więcej | Java: ~30 linii; Kotlin + @Parcelize: jedna adnotacja |
| Wydajność | Wolniejsze (refleksja) | Szybsze (brak refleksji) |
| Zalecane przez Google | Nie | ✅ Tak |
| Kiedy używać | Ćwiczenia, szybkie prototypy | Projekt końcowy, aplikacje produkcyjne |
Intencja niejawna – komunikacja z systemem
Dotąd wskazywaliśmy konkretną klasę aktywności. Intencja niejawna nie wskazuje klasy – mówi tylko co chcemy zrobić. Android przeszukuje zainstalowane aplikacje i wybiera tę która potrafi tę akcję wykonać.
// Otwórz adres URL w domyślnej przeglądarce Intent i1 = new Intent(Intent.ACTION_VIEW, Uri.parse("https://school-it.pl")); startActivity(i1); // Otwórz aplikację telefoniczną z wybranym numerem Intent i2 = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:112")); startActivity(i2); // Wyślij tekst – Android pokaże listę aplikacji: e-mail, SMS, Messenger... Intent i3 = new Intent(Intent.ACTION_SEND); i3.setType("text/plain"); i3.putExtra(Intent.EXTRA_TEXT, "Wiadomość do wysłania"); startActivity(Intent.createChooser(i3, "Wyślij przez..."));
// Otwórz adres URL w domyślnej przeglądarce startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://school-it.pl"))) // Otwórz aplikację telefoniczną z wybranym numerem startActivity(Intent(Intent.ACTION_DIAL, Uri.parse("tel:112"))) // Wyślij tekst – Kotlin: apply { } grupuje konfigurację obiektu startActivity(Intent(Intent.ACTION_SEND).apply { type = "text/plain" putExtra(Intent.EXTRA_TEXT, "Wiadomość do wysłania") }.let { Intent.createChooser(it, "Wyślij przez...") })
Podsumowanie
Każdy nowy ekran wymaga trzech elementów. Pominięcie któregokolwiek kończy się błędem.
| Element | Gdzie | Co robi | Brak powoduje |
|---|---|---|---|
| Plik XML layoutu | res/layout/ | Definiuje wygląd ekranu | Crash w setContentView() |
| Klasa Activity | pakiet Java/Kotlin | Definiuje logikę ekranu, łączy się z XML przez setContentView() | Błąd kompilacji |
| Wpis w Manifeście | AndroidManifest.xml | Rejestruje ekran w systemie Android | ActivityNotFoundException – crash po kliknięciu |
| Operacja | Java | Kotlin |
|---|---|---|
| Utwórz intencję | new Intent(this, B.class) | Intent(this, B::class.java) |
| Uruchom ekran | startActivity(intent) | startActivity(intent) |
| Wyślij dane | intent.putExtra("k", v) | intent.putExtra("k", v) |
| Odbierz dane | getIntent().getExtras() | intent.extras |
| Odczytaj String | bundle.getString("k") | bundle.getString("k") |
| Odczytaj int | bundle.getInt("k") | bundle.getInt("k") |
| Zamknij ekran | finish() | finish() |
| Obiekt: prosto | implements Serializable | data class X(...) : Serializable |
| Obiekt: wydajnie | implements Parcelable + ~30 linii | @Parcelize data class X(...) : Parcelable |
| Odbierz obiekt | (X) bundle.getSerializable("k") | bundle.getSerializable("k") as? X |
Zadanie dla uczniów
Aplikacja „Wizytówka ucznia”
- Utwórz ręcznie plik
activity_formularz.xmlz polami: imię, nazwisko, klasa (np. 3TI) i przyciskiem „Pokaż wizytówkę” - Zmień
MainActivitytak, żeby używała tego nowego layoutu - Utwórz ręcznie klasę
UczenimplementującąSerializablez tymi trzema polami - Utwórz ręcznie plik
activity_wizytowka.xmlz trzema polamiTextViewi przyciskiem „Wróć” - Utwórz ręcznie klasę
WizytowkaActivityi zarejestruj ją wAndroidManifest.xml - Po kliknięciu przycisku utwórz obiekt
Uczen, spakuj do intencji przezputExtra()i przejdź doWizytowkaActivity - Odbierz obiekt przez
getSerializable()i wyświetl dane w polachTextView
⭐ Bonus 1: dodaj do klasy Uczen pole srednia (double) – wyświetl je na wizytówce sformatowane do 2 miejsc po przecinku (String.format("%.2f", srednia))
⭐⭐ Bonus 2: dodaj trzeci ekran PotwierdzActivity – po kliknięciu „Zatwierdź” na wizytówce przejdź tam i wyświetl „Dane zapisane!”
⭐⭐⭐ Bonus Kotlin: zamień Serializable na @Parcelize i porównaj ile linii kodu zaoszczędziłeś