Przekazywanie danych pomiędzy aktywnościami
Przesłanie danych w obrębie jednej aplikacji pomiędzy różnymi jej aktywnościami polega na wykorzystaniu metody
- putExtra()- do wysłania danych
- getExtra()- do odbioru danych
Metoda putExtra() przekazuje podstawowe typy danych takie jak Int, Float, Char, Double, String, IntArray itd. Odbywa się to przez podanie do metody dwóch argumentów. Pierwszym argumentem jest tak zwany klucz, drugi argument to przesyłana dana. Klucz pełni role identyfikatora przesyłanej danych. Po kluczu rozpoznaje się przesłane dane w momencie ich odbioru w drugiej aktywności.
Przykładowa instrukcja
Wskazówka:
val bt1=findViewById<Button>(R.id.button1)
bt1.setOnClickListener {
val intencja = Intent(this,Okno1::class.java)
intencja.putExtra("dane_imie","Jan")
intencja.putExtra("dane_nazwisko","Kowalski")
intencja.putExtra("dane_wiek",24)
}
Pisząc powyższy kod, można się posłużyć mechanizmem podpowiedzi. Patrz poniższa ilustracja
Przesłane dane w nowo otwartej aktywności należy odebrać w metodzie OnCreate() stosując metodę getExtra() klasy intent dobraną do typu przesyłanych danych. Rozpoznanie danych odbywa się przez podanie klucza. Nazwa klucza powinna być zgodna co do użytych znaków w kluczy wysyłającym dane. Patrz poniższy przykładowy kod
Wskazówka:
val txtImie=intent.getStringExtra("dane_imie")
val txtNazwisko=intent.getStringExtra("dane_nazwisko")
val intWiek=intent.getIntExtra("dane_wiek",0)
Przesyłanie parcelowanych danych
Sposób przesyłania pojedynczych danych jest prosty ale nie jest zbyt wygodny. Dużo lepszą metodą jest przesyłanie danych serializowanych lub parcelowanych. Wymienione sposoby wymagają skorzystania z odpowiedniego interfejsu: Parcelable lub Serializable. Interfejs Serializable jest standardowym interfejsem Java, zaś Parcelable jest składnikiem Android SDK. Parcelable jest szybszy niż Serializable.
Dodanie interfejsu Parcelable
Skorzystanie z interfejsu Parcelable w budowanym projekcie wymaga zmian w plikach bibliotek i plikach gradle tworzonej aplikacji.
Krok 1
W pliku libs.versions.toml w sekcji [versions] dodaj informację o możliwie najnowszej wersji kotlinPlugin (tu 1.9.0)
Wskazówka:
[versions]
agp = "8.4.0"
kotlin = "1.9.0"
kotlinPlugin = "1.9.0"
coreKtx = "1.13.1"
A w sekcji [plugins] dołącz moduł kotlin-parcelize. Patrz poniżej
Wskazówka:
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlinPlugin" }
Krok 2
Aby skorzystać z interfejsu Parcelable należy go dołączyć w pluginach pliku build.gradle.kts modułu aplikacji.
Wskazówka:
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
alias (libs.plugins.kotlin.parcelize)
}
Krok 3
oraz w pliku build.gradle.kts modułu projektu
Wskazówka:
plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.jetbrains.kotlin.android) apply false
alias (libs.plugins.kotlin.parcelize) apply false
}
Krok 4
UWAGA! Po każdorazowej zmianie zawartości plików gradle należy wykonać synchronizację zmian. Patrz krok 3 na poniższym rysunku
Krok 5
Po aktualizacji zmiany pliku gradle należy w głównym pliku tworzonej aplikacji zaimportować dwa moduły bibliotek rozszerzeń (Parcelize i Parcelable). Patrz poniżej
Wskazówka:
import androidx.appcompat.app.AppCompatActivity
import kotlinx.parcelize.Parcelize
import android.os.Parcelable
class MainActivity : AppCompatActivity() {
Intencje jawne: Przekazywanie danych pomiędzy aktywnościami
Tworzymy projekt, w którym będziemy mogli wykorzystać cztery osobne okna aktywności. Jedno z okien jest oknem głównym, pozostałe trzy są oknami podrzędnymi. Dodanie nowych aktywności w obrębie jednego projektu można wykonać po wybraniu New/ Activity/ Empty Activity
Ustaw nazwę okna aktywności i język (Kotlin)
Po dodaniu mamy cztery aktywności:
- MainActivity (przyjmujemy że jest główna)
- Okno1
- Okno2
- Okno3
Prawidłowo dodane aktywności do projektu są zainicjowane w manifeście tworzonej aplikacji. Sprawdź czy manifest aplikacji zawiera odpowiednie wpisy. Patrz poniższy kod
Wskazówka:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.IntencjaAktywnosci"
tools:targetApi="31">
<activity
android:name=".Okno1"
android:exported="false" />
<activity
android:name=".Okno2"
android:exported="false" />
<activity
android:name=".Okno3"
android:exported="false" />
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Pliki XML układu tworzonych aktywności
Układ widoku głównej aktywności powinien zawierać poniższe kontrolki
- TextView- 1 sztuka (tytuł okna aktywności)
- PlainText- 2 sztuki (pola do wprowadzania imienia i nazwiska)
- Number- 1 sztuka (pole do wprowadzania ilości lat- wieku)
- Button- 4 sztuki
Pozostałe okna aktywności podrzędnych są do siebie podobne. Różnią się tylko tekstem nagłówkowym Okno 1, Okno 2, Okno 3 podanym w kontrolce TextView
Wysyłanie pojedynczych danych
Wysyłanie danych z jednej aktywności do drugiej rozpoczniemy od najprostszego rozwiązania. Będziemy wysyłać pojedyncze dane metoda putExtra(). W pliku głównej aktywności (MainActivity.kt) wysłanie danych zrealizujemy po kliknięciu w pierwszą kontrolkę typu Button. Patrz poniższy kod.
Wskazówka:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//wyślij dane najprostszą metoda do aktywności Okno1
val bt1=findViewById<Button>(R.id.button1)
bt1.setOnClickListener {
val intencja = Intent(this,Okno1::class.java)
val imie=findViewById<EditText>(R.id.editTextText1).text.toString()
intencja.putExtra("dane_imie",imie)
val nazwisko=findViewById<EditText>(R.id.editTextText2).text.toString()
intencja.putExtra("dane_nazwisko",nazwisko)
val wiek=findViewById<EditText>(R.id.editTextNumber1).text.toString().toInt()
intencja.putExtra("dane_wiek",wiek)
startActivity(intencja)
}
//zamkniecie aplikacji
val bt4=findViewById<Button>(R.id.button4)
bt4.setOnClickListener {
finishAffinity()
System.exit(0)
}
}
Zauważ, że każda wysyłana pojedyncza dana ma inny unikatowy klucz. W tym przypadku klucze to
- dane_imie
- dane_nazwisko
- dane_wiek
Odebranie danych w aktywności Okno1 realizuje poniższy kod, w który to używamy tych samych kluczy. UWAGA! Ma znaczenie pisownia, w kluczach rozróżniana jest wielkość liter (duże/ małe)
Wskazówka:
class Okno1 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_okno1)
//odebranie pojedynczych danych
val txtImie=intent.getStringExtra("dane_imie")
val txtNazwisko=intent.getStringExtra("dane_nazwisko")
val intWiek=intent.getIntExtra("dane_wiek",0)
val txt=findViewById<TextView>(R.id.textView2)
txt.setText("Przesłane dane:\n"
+txtImie+"\n"
+txtNazwisko+"\n"
+intWiek.toString())
//powrót do okna głownego
val bt1=findViewById<Button>(R.id.button1)
bt1.setOnClickListener {
val intencja = Intent(this,MainActivity::class.java)
startActivity(intencja)
}
}
}
Skompiluj aplikację i sprawdź efekt działania.
Przesłanie danych metodą Parcelable
W tej metodzie prześlemy dane złożone w postaci rekordu danych, który to w Kotlinie przymuje postać klasy danych (data class). Na końcu pliku (MainActivity.kt) głównej aktywności dopisujemy klasę danych, którą należy parcelizować
Wskazówka:
@Parcelize
data class Osoba(
var nazwisko: String="",
val imie: String="",
val wiek: Int=0
) : Parcelable
Przesłanie danych realizujemy po kliknięciu w druga kontrolkę typu Button. I tak samo jak poprzednio używamy klucza. Tym razem klucz to: paczka_osoba.
Wskazówka:
val intencja = Intent(this,Okno2::class.java)
val osoba:Osoba=Osoba(nazwisko,imie,wiek)
intencja.putExtra("paczka_osoba",osoba)
Kod przesłania danych realizowany po kliknięciu w przycisk.
Wskazówka:
//wyślij dane, metoda Parcelable
val bt2=findViewById<Button>(R.id.button2)
bt2.setOnClickListener {
val intencja = Intent(this,Okno2::class.java)
val imie=findViewById<EditText>(R.id.editTextText1).text.toString()
val nazwisko=findViewById<EditText>(R.id.editTextText2).text.toString()
val wiek=findViewById<EditText>(R.id.editTextNumber1).text.toString().toInt()
val osoba:Osoba=Osoba(nazwisko,imie,wiek)
intencja.putExtra("paczka_osoba",osoba)
startActivity(intencja)
}
W pliku klasy aktywności Okno2.kt odebranie danych przesłanych tą metodą realizuje poniższy kod
Wskazówka:
class Okno2 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_okno2)
val txt=findViewById<TextView>(R.id.textView2)
//odebranie pakietu danych, metoda Parcelize
val osoba=intent.getParcelableExtra<Osoba>("paczka_osoba")as Osoba
txt.setText("Przesłane dane osoba:\n"
+ osoba.imie +"\n"
+osoba.nazwisko+"\n"
+osoba.wiek)
//powrót do okna głownego
val bt1=findViewById<Button>(R.id.button1)
bt1.setOnClickListener {
val intencja = Intent(this,MainActivity::class.java)
startActivity(intencja)
}
}
}
Skompiluj program i sprawdź działanie
Przesłanie danych metodą Serializable
Podobnie jak poprzednio przygotujemy klasę danych, którą przed wysłaniem należy serializować. Dopisujemy ją na końcu pliku (MainActivity.kt) głównej aktywności. Nowej klasie danych nadajemy nazwę Osoba2
Wskazówka:
@Parcelize
data class Osoba(
var nazwisko: String="",
val imie: String="",
val wiek: Int=0
) : Parcelable
data class Osoba2(
var nazwisko:String="",
var imie:String="",
var wiek:Int=0
): Serializable
W nagłówku tego samego pliku importujemy bibliotekę java.io.Serializable. Patrz poniżej
Wskazówka:
import kotlinx.parcelize.Parcelize
import android.os.Parcelable
import java.io.Serializable
Wysłanie danych podpinamy pod trzeci przycisk. Przypisujemy klucz: paczka_osoba2
Wskazówka:
//wyślij dane, metoda Serializable
val bt3=findViewById<Button>(R.id.button3)
bt3.setOnClickListener {
val intencja = Intent(this,Okno3::class.java)
val osoba2=Osoba2()
osoba2.imie=findViewById<EditText>(R.id.editTextText1).text.toString()
osoba2.nazwisko=findViewById<EditText>(R.id.editTextText2).text.toString()
osoba2.wiek=findViewById<EditText>(R.id.editTextNumber1).text.toString().toInt()
intencja.putExtra("paczka_osoba2",osoba2)
startActivity(intencja)
}
Skompiluj program i sprawdź działanie
Pełny kod głównej aktywności
Wskazówka:
import android.content.Intent
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity
import kotlinx.parcelize.Parcelize
import android.os.Parcelable
import java.io.Serializable
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//wyślij dane najprostszą metoda do aktywności Okno1
val bt1=findViewById<Button>(R.id.button1)
bt1.setOnClickListener {
val intencja = Intent(this,Okno1::class.java)
val imie=findViewById<EditText>(R.id.editTextText1).text.toString()
intencja.putExtra("dane_imie",imie)
val nazwisko=findViewById<EditText>(R.id.editTextText2).text.toString()
intencja.putExtra("dane_nazwisko",nazwisko)
val wiek=findViewById<EditText>(R.id.editTextNumber1).text.toString().toInt()
intencja.putExtra("dane_wiek",wiek)
startActivity(intencja)
}
//wyślij dane, metoda Parcelable
val bt2=findViewById<Button>(R.id.button2)
bt2.setOnClickListener {
val intencja = Intent(this,Okno2::class.java)
val imie=findViewById<EditText>(R.id.editTextText1).text.toString()
val nazwisko=findViewById<EditText>(R.id.editTextText2).text.toString()
val wiek=findViewById<EditText>(R.id.editTextNumber1).text.toString().toInt()
val osoba:Osoba=Osoba(nazwisko,imie,wiek)
intencja.putExtra("paczka_osoba",osoba)
startActivity(intencja)
}
//wyślij dane, metoda Serializable
val bt3=findViewById<Button>(R.id.button3)
bt3.setOnClickListener {
val intencja = Intent(this,Okno3::class.java)
val osoba2=Osoba2()
osoba2.imie=findViewById<EditText>(R.id.editTextText1).text.toString()
osoba2.nazwisko=findViewById<EditText>(R.id.editTextText2).text.toString()
osoba2.wiek=findViewById<EditText>(R.id.editTextNumber1).text.toString().toInt()
intencja.putExtra("paczka_osoba2",osoba2)
startActivity(intencja)
}
//zamkniecie aplikacji
val bt4=findViewById<Button>(R.id.button4)
bt4.setOnClickListener {
finishAffinity()
System.exit(0)
}
}
}
@Parcelize
data class Osoba(
var nazwisko: String="",
val imie: String="",
val wiek: Int=0
) : Parcelable
data class Osoba2(
var nazwisko:String="",
var imie:String="",
var wiek:Int=0
): Serializable
Kod aktywności Okno1
Wskazówka:
import android.content.Intent
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
class Okno1 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_okno1)
//odebranie pojedynczych danych
val txtImie=intent.getStringExtra("dane_imie")
val txtNazwisko=intent.getStringExtra("dane_nazwisko")
val intWiek=intent.getIntExtra("dane_wiek",0)
val txt=findViewById<TextView>(R.id.textView2)
txt.setText("Przesłane dane:\n"
+txtImie+"\n"
+txtNazwisko+"\n"
+intWiek.toString())
//powrót do okna głownego
val bt1=findViewById<Button>(R.id.button1)
bt1.setOnClickListener {
val intencja = Intent(this,MainActivity::class.java)
startActivity(intencja)
}
}
}
Kod aktywności Okno2
Wskazówka:
import android.content.Intent
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
class Okno2 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_okno2)
val txt=findViewById<TextView>(R.id.textView2)
//odebranie pakietu danych, metoda Parcelize
val osoba=intent.getParcelableExtra<Osoba>("paczka_osoba")as Osoba
txt.setText("Przesłane dane osoba:\n"
+ osoba.imie +"\n"
+osoba.nazwisko+"\n"
+osoba.wiek)
//powrót do okna głownego
val bt1=findViewById<Button>(R.id.button1)
bt1.setOnClickListener {
val intencja = Intent(this,MainActivity::class.java)
startActivity(intencja)
}
}
}
Kod aktywności Okno3
Wskazówka:
import android.content.Intent
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
class Okno3 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_okno3)
val osoba2=intent.getSerializableExtra("paczka_osoba2")as Osoba2
val txt=findViewById<TextView>(R.id.textView2)
//odebranie pakietu danych, metoda Serializable
txt.setText("Przesłane dane osoba2:\n"
+ osoba2.imie +"\n"
+osoba2.nazwisko+"\n"
+osoba2.wiek)
//powrót do okna głownego
val bt1=findViewById<Button>(R.id.button1)
bt1.setOnClickListener {
val intencja = Intent(this,MainActivity::class.java)
startActivity(intencja)
}
}
}