Podczas zajęć skupimy się na tworzeniu aplikacji mobilnej w środowisku Android Studio, poznając podstawowy workflow pracy programisty Androida: od utworzenia projektu, przez budowę interfejsu, po obsługę danych w aplikacji.
Jako praktyczny przykład zastosowania aplikacji wykorzystamy scenariusz pracy z urządzeniem mobilnym wyposażonym w skaner kodów (np. Zebra TC51), co pozwoli zobaczyć, jak aplikacje Android współpracują z realnym sprzętem wykorzystywanym w logistyce, handlu czy przemyśle.
Skaner posłuży tu jako źródło danych, a głównym celem będzie zaprojektowanie aplikacji, która poprawnie odbiera, przetwarza i wykorzystuje te dane w praktycznym kontekście.
Cele lekcji
Po tej lekcji:
- wiesz, czym różni się „aparat + biblioteka skanera” od skanera sprzętowego Zebry,
- rozumiesz, co to jest DataWedge i po co jest,
- potrafisz zrobić aplikację, która odbiera zeskanowany kod jako tekst (najprostsza integracja),
- wiesz, kiedy potrzebne jest Zebra SDK (EMDK) i co wtedy zyskujesz,
- masz plan: emulator → test → telefon/TC51.
Krok 1. Instalacja i konfiguracja Android Studio
– pobranie i instalacja



– pierwsze uruchomienie



– co to jest SDK i emulator
Co to jest emulator?
Emulator to wirtualne urządzenie z Androidem, które działa na komputerze i zachowuje się jak prawdziwy telefon lub tablet.
Emulator pozwala:
- uruchamiać i testować aplikację bez fizycznego telefonu,
- sprawdzić, jak aplikacja wygląda i działa,
- debugować błędy krok po kroku.
Dzięki emulatorowi możemy pisać i testować aplikację nawet wtedy, gdy nie mamy jeszcze fizycznego urządzenia, np. skanera Zebra.
Dlaczego to ważne na tym etapie?
Emulator umożliwia ich testowanie.
– utworzenie pierwszego projektu
SDK umożliwia tworzenie aplikacji.

Wybieramy empty activity

Nazywamy aplikację. Ta nazwa, będzie widoczna na telefonie/emulatorze i pojawi się później w Google Play (jeśli opublikujesz).


Plik MainActivity.kt – co to jest i za co odpowiada?
MainActivity.kt to główny plik startowy aplikacji.
To właśnie od tej klasy Android zaczyna działanie programu po uruchomieniu aplikacji.
Można powiedzieć, że:
MainActivity to „punkt wejścia” aplikacji Android.
Struktura pliku – krok po kroku
1️⃣ Deklaracja pakietu
package pl.edu.infa.scanapp
Określa, do jakiego pakietu należy plik.
Musi być zgodna z nazwą pakietu projektu.
Zapewnia unikalność aplikacji w systemie Android.
2️⃣ Importy
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
Importy to gotowe klasy i funkcje, z których korzysta aplikacja.
Dzięki nim Android Studio „wie”, skąd pochodzi używany kod.
Na tym etapie nie musimy ich jeszcze dokładnie znać — wystarczy świadomość, że są potrzebne.
3️⃣ Definicja klasy MainActivity
class MainActivity : ComponentActivity() {
Definiujemy klasę o nazwie MainActivity.
ComponentActivity to podstawowa klasa Androida, która:
obsługuje ekran,
reaguje na cykl życia aplikacji.
Każda aplikacja Android ma co najmniej jedną Activity.
4️⃣ Metoda onCreate
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
onCreate to metoda, która:
wykonuje się przy starcie aplikacji,
służy do inicjalizacji ekranu i logiki.
super.onCreate(...) wywołuje kod systemowy Androida — zawsze musi tu być.
5️⃣ setContent { ... } – co widzimy na ekraniesetContent {
ScanAppTheme {
// zawartość ekranu
}
}
setContent określa co zostanie wyświetlone na ekranie.
W nowoczesnych projektach Android używa się Jetpack Compose:
zamiast plików XML,
interfejs tworzy się w Kotlinie.
Na razie traktujemy to jako:
„Tutaj definiujemy wygląd ekranu aplikacji.”
Co warto zapamiętać na tym etapie
MainActivity.kt to centrum sterowania aplikacją.
onCreate() uruchamia się przy starcie aplikacji.
To tutaj później:
- odbierzemy dane (np. ze skanera),
- zareagujemy na zdarzenia,
- zmienimy zawartość ekranu.
Dlaczego to ważne przed pracą ze skanerem?
Bo skaner (Zebra) nie działa sam, dane ze skanera trafią właśnie do Activity, zanim odbierzemy skan, musimy rozumieć:
- gdzie jesteśmy w kodzie,
- co uruchamia aplikację.

Pierwsza drobna zmiana w MainActivity.kt
1️⃣ Znajdź fragment setContent { ... }
W pliku MainActivity.kt zobaczysz coś w tym stylu (nazwy mogą się minimalnie różnić):
setContent {
ScanAppTheme {
Greeting("Android")
}
}

albo (w nowszej wersji):
setContent {
ScanAppTheme {
Surface(
modifier = Modifier.fillMaxSize()
) {
Greeting(
name = "Android",
modifier = Modifier.padding(16.dp)
)
}
}
}
2️⃣ Zmień tekst wyświetlany na ekranie
Zamień "Android" na własny tekst, np.:
Greeting("ScanApp – pierwsza aplikacja")
czyli finalnie np.:
Greeting("ScanApp – pierwsza aplikacja")
To jedna linijka, a zmiana będzie widoczna od razu po uruchomieniu.
3️⃣ Uruchom aplikację
- Kliknij ▶ Run (zielona strzałka)
- Wybierz emulator
- Poczekaj, aż aplikacja się uruchomi
👉 Na ekranie emulatora zobaczysz nowy tekst, który sam wpisałeś.
Co właśnie się wydarzyło (bardzo ważne)
- Zmieniłeś kod w Kotlinie
- Android Studio:
- zbudowało aplikację,
- uruchomiło ją na emulatorze,
- wyświetliło nową treść.
To dokładnie ten sam mechanizm, który później:
- pokaże zeskanowany kod,
- zaktualizuje ekran po skanowaniu,
- zareaguje na dane z urządzenia Zebra.
Jeśli chcesz jeszcze bardziej „czytelny” efekt (opcjonalnie)
Możemy usunąć wszystko i wpisać własny tekst od zera:
setContent {
Text("Witaj! To moja pierwsza aplikacja w Android Studio")
}

Dodanie pierwszego przycisku (Jetpack Compose)
1️⃣ Znajdź miejsce w Scaffold
Masz teraz coś w tym stylu:
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Greeting(
name = "ScanApp",
modifier = Modifier.padding(paddingValues = innerPadding)
)
}
2️⃣ Zamień Greeting(...) na tekst + przycisk
Wstaw ten kod:
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Column(
modifier = Modifier
.padding(innerPadding)
.padding(16.dp)
) {
Text(
text = "To jest moja pierwsza aplikacja",
)
Spacer(modifier = Modifier.height(16.dp))
Button(
onClick = {
// tu później dodamy akcję (np. skanowanie)
}
) {
Text("Kliknij mnie")
}
}
}
3️⃣ Jeśli Android Studio podkreśli coś na czerwono
Użyj:
- Alt + Enter → Import
Najczęściej potrzebne importy:
ButtonTextColumnSpacerModifierdp
Android Studio zrobi to automatycznie.

4️⃣ Uruchom aplikację ▶
Kliknij Run i spójrz na emulator.
👉 Zobaczysz:
- tekst,
- przycisk „Kliknij mnie”,
- po kliknięciu… jeszcze nic (i tak ma być).

Co właśnie zrobiłeś (ważne!)
- Dodałeś pierwszy element interaktywny.
- Poznałeś:
Button– przycisk,onClick– reakcję na kliknięcie,Column– układ pionowy.
To dokładnie ten mechanizm, którego użyjemy później:
- przycisk „Skanuj”,
- reakcja na skan z Zebry,
- aktualizacja tekstu na ekranie.
Zmiana tekstu po kliknięciu (Compose – podstawy)
1️⃣ Dodaj zmienną stanu nad Scaffold
W setContent { … }, na samym początku, dodaj:
var message by remember { mutableStateOf("To jest moja pierwsza aplikacja") }
Całość zacznie wyglądać tak:
setContent {
ScanAppTheme {
var message by remember { mutableStateOf("To jest moja pierwsza aplikacja") }
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
...
}
}
}
Jeśli coś się podkreśli na czerwono → Alt + Enter → Import
(potrzebne: remember, mutableStateOf, by)
Jeżeli nie masz możliwości wykonania importów automatycznie, możesz dopisać je ręcznie w zaznaczonym miejscu.

2️⃣ Zmień Text, żeby korzystał ze zmiennej
Zamiast:
Text(
text = "To jest moja pierwsza aplikacja"
)
daj:
Text(
text = message
)
3️⃣ Zmień onClick przycisku
W Button zamień pusty onClick na:
Button(
onClick = {
message = "Przycisk został kliknięty!"
}
) {
Text(text = "Kliknij mnie")
}

4️⃣ Uruchom aplikację ▶
Kliknij Run i:
- start → widzisz tekst początkowy
- klik → tekst zmienia się natychmiast
Bez restartu, bez odświeżania.
Co właśnie zrobiłeś (to jest kluczowe)
- Poznałeś stan (
state) w Compose - Zrozumiałeś, że:
- UI reaguje na zmianę danych
- nie „rysujesz ekranu ręcznie”
- To dokładnie ten mechanizm, który za chwilę wykorzystamy do:
- pokazania zeskanowanego kodu,
- komunikatu „skan udany”,
- licznika, listy, historii skanów.
1) Co mamy: Zebra TC51, Android, skaner sprzętowy
Zebra TC51 ma wbudowany skaner (laser/imager). W praktyce są 3 drogi, żeby go użyć w aplikacji:
- DataWedge (najprościej)
Skaner „wpisuje” tekst do aplikacji tak, jakbyś pisał klawiaturą, albo wysyła Intent do aplikacji. - Zebra EMDK / Scanner SDK (bardziej „programistycznie”)
Masz większą kontrolę: start/stop skanowania, konfiguracje, eventy, itp. - Biblioteki kamerowe (np. ZXing / ML Kit)
Dobre na zwykłe telefony — ale to nie wykorzystuje sprzętowego skanera Zebry tak wygodnie jak DataWedge/EMDK.
W tej lekcji robimy wariant 1, bo najszybciej daje efekt.
2) Android Studio: Kotlin czy Java?
- Możecie pisać w Kotlinie: zwykle kod jest krótszy i czytelniejszy (mniej „boilerplate”).
- Java też zadziała, ale jeśli Tymek zaczyna, Kotlin jest najczęściej wygodniejszy.
Wniosek do decyzji: robimy Kotlin w Android Studio.
3) Emulator — co da się zasymulować?
- Emulator Androida nie zasymuluje sprzętowego skanera Zebry (to nie ten hardware).
- Ale da się zasymulować to, co aplikacja dostaje:
- albo „wpis” tekstu do pola (jakby DataWedge działał w trybie klawiatury),
- albo „Intent” z danymi (symulujemy ręcznie przyciskiem „Test”).
Czyli: logikę odbioru i obsługi kodu testujemy na emulatorze, a prawdziwe skanowanie sprawdzamy na TC51.
4) Najprostszy plan aplikacji (DataWedge = tekst w polu)
Zadanie
Zrób aplikację z:
- polem tekstowym „Kod”
- listą zeskanowanych kodów (np. w pamięci)
- przyciskiem „Dodaj / Zapisz” (na start może tylko dopisywać do listy)
Minimalny scenariusz testu na emulatorze
- Klikasz w pole „Kod”
- Wpisujesz ręcznie np.
5901234123457 - Enter → aplikacja traktuje to jak „skan”
To 1:1 imituje tryb DataWedge „keystroke output”.
5) Wariant profesjonalny: DataWedge przez Intent
To jest wygodniejsze, bo:
- nie musisz mieć kursora w polu,
- dostajesz kod w zdarzeniu, możesz go od razu przetwarzać.
Co robicie koncepcyjnie
- Aplikacja ma „nasłuch” (BroadcastReceiver / obsługa Intentów)
- DataWedge na urządzeniu Zebry wysyła Intent z:
- wartością skanu
- typem symbologii (EAN-13, Code128, QR itd.)
Jak to testować bez TC51
- Dodajecie w aplikacji przycisk „TEST INTENT”
- Po kliknięciu aplikacja sama wywołuje tę samą ścieżkę kodu, którą normalnie uruchomi skaner.
6) Co to jest Zebra SDK / EMDK i po co
Zebra SDK (często spotkasz nazwę EMDK) warto ruszać, gdy:
- chcesz pełną kontrolę nad skanerem,
- chcesz zmieniać ustawienia skanera z poziomu aplikacji,
- chcesz stabilne zachowanie w środowisku firmowym (magazyn, sklep).
Ale: na pierwszą lekcję to za dużo. Najpierw DataWedge, potem dopiero SDK.
7) Propozycja pracy domowej / kolejny krok
- Dodać walidację:
- jeśli kod ma mniej niż np. 4 znaki → odrzucaj
- Dodać historię + „kopiuj do schowka”
- Dodać rozpoznawanie typu (EAN/QR) jeśli będziecie szli w Intent + DataWedge
- Dopiero potem: „tryb magazynowy” (np. liczenie sztuk, koszyk, stan)
8.
fun TimedMessageExample() {
var message by remember { mutableStateOf("Tekst początkowy") }
var showTempMessage by remember { mutableStateOf(false) }
// Efekt czasowy
LaunchedEffect(showTempMessage) {
if (showTempMessage) {
delay(2000) // 2 sekundy
message = "Tekst początkowy"
showTempMessage = false
}
}
Column {
Text(
text = message,
fontSize = 20.sp
)
Button(
onClick = {
message = "Kliknięto przycisk!"
showTempMessage = true
}
) {
Text("Kliknij")
}
}
}
