0% found this document useful (0 votes)
2 views563 pages

Java + Android

Uploaded by

apiechowiak6572
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views563 pages

Java + Android

Uploaded by

apiechowiak6572
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 563

PROGRAMOWANIE APLIKACJI MOBILNYCH

PRACOWNIA PROGRAMOWANIA APLIKACJI


MOBILNYCH
inż. Paweł Palacz

1

LEKCJA ORGANIZACYJNA

2
O MNIE
• Wykształcenie:

• Collegium Da Vinci w Poznaniu (inżynier


informatyki [Aplikacje Internetowe i Mobilne])

• Zespół Szkół Komunikacji im. Hipolita Cegielskiego


w Poznaniu (technik informatyk)

• Doświadczenie zawodowe:

• Fullstack Web Developer (Symfony/Node/React) -


Fabrity (od 2022)

• Self-employed Web Developer - in2dev (od 2022) Obraz autorstwa storyset na Freepik

• PHP (Symfony) developer - as4you (2020-2022)


3
ZASADY OCENIANIA - WYKŁAD
• I semestr

• 1x sprawdzian

• minimum 2x kartkówka (nie)zapowiedziana*

• odpowiedź ustna

• praca na lekcji**

• nieprzygotowanie 2x

• II semestr

• 1x sprawdzian

• minimum 2x kartkówka (nie)zapowiedziana*

• odpowiedź ustna

• praca na lekcji**

• projekt*** Obraz autorstwa storyset na Freepik


• nieprzygotowanie 2x

4
UWAGI DO ZASAD OCENIANIA -
WYKŁAD
• Szczęśliwy numerek i nieprzygotowanie zwalnia z
odpowiedzi ustnej i innych niezapowiedzianych form
sprawdzenia wiedzy, ale NIE z zapowiedzianej
kartkówki, sprawdzianu i aktywności na
zajęciach

• W przypadku nieobecności na sprawdzianie lub


zapowiedzianej kartkówce – praca musi zostać
uzupełniona

• Sprawdzian musi być zaliczony na ocenę pozytywną

• Aby być klasy kowanym ilość ocen pozytywnych musi


być większa od ilości ocen negatywnych oraz należy Obraz autorstwa storyset na Freepik
zdobyć wymaganą minimalną liczbę ocen

5
fi
ZASADY OCENIANIA - PRACOWNIE
• I semestr

• 1x sprawdzian

• zadania z lekcji

• praca na lekcji*

• nieprzygotowanie 2x

• II semestr

• 1x sprawdzian

• zadania z lekcji

• praca na lekcji*

• projekt**
Obraz autorstwa storyset na Freepik
• nieprzygotowanie 2x

6
UWAGI DO ZASAD OCENIANIA -
PRACOWNIE
• Zadania z lekcji będą sprawdzane wyrywkowo na kolejnych
zajęciach. Nieobecność na lekcji nie zwalnia z wykonania
zadania.

• Szczęśliwy numerek lub nieprzygotowanie zwalnia z


wyrywkowego sprawdzania zadania, ale NIE
ze sprawdzianu i aktywności na zajęciach

• W przypadku nieobecności na sprawdzianie – praca


musi zostać uzupełniona

• Sprawdzian musi być zaliczony na ocenę pozytywną

• Aby być klasy kowanym ilość ocen pozytywnych musi być


większa od ilości ocen negatywnych oraz należy zdobyć Obraz autorstwa storyset na Freepik
wymaganą minimalną liczbę ocen

7
fi
KONTAKT Z PROWADZĄCYM

• E-dziennik

• Email

[email protected] (zalecany)

• Teams

Obraz autorstwa storyset na Freepik

8
TEMATYKA ZAJĘĆ

Obraz autorstwa storyset na Freepik

9
TEMATYKA ZAJĘĆ
• Wprowadzenie do języka Java

• Wprowadzenie do Android Studio

• Podstawy tworzenia interfejsu użytkownika

• Style i tematy

• Aktywności i fragmenty
10
TEMATYKA ZAJĘĆ
• Powiadomienia

• Praca z komponentami Interfejsu Użytkownika (UI)

• Obrazy i animacje

• Zapisywanie i odczytywanie danych

• Wprowadzenie do języka Kotlin

• Język Kotlin w kontekście Androida


11
To jest ta scena, w której zadajecie pytania
12
WPROWADZENIE DO JĘZYKA JAVA

13
TROCHĘ DANYCH TECHNICZNYCH
• Pojawienie się: 1995

• Paradygmat: Wieloparadygmatowy (obiektowy, strukturalny, imperatywny,


funkcyjny)

• Aktualna wersja: Java SE 22

• Twórca: James Gosling

• Licencja: GNU GPL

• Platforma sprzętowa: wieloplatformowy


14
CO TO JEST JAVA?
• Java to popularny język programowania, stworzony w 1995 roku.

• Jego właścicielem jest Oracle, a sama Java działa na ponad 3 miliardach urządzeń.

• Jest używany do:

• Aplikacji mobilnych (w szczególności aplikacji na Androida)

• Aplikacji desktopowych

• Aplikacji internetowych

• Serwerów internetowych i serwerów aplikacji

• Gier

• Połączeń z bazami danych

• I wiele, wiele więcej!

15
DLACZEGO UŻYWAMY JAVY?
• Java działa na różnych platformach (Windows, Mac, Linux, Raspberry Pi itp.).

• Jest to jeden z najpopularniejszych języków programowania na świecie.

• Ma duże zapotrzebowanie na obecnym rynku pracy

• Jest łatwy do nauczenia i prosty w użyciu

• Jest open-source i darmowy

• Jest bezpieczny, szybki i wydajny

• Ma ogromne wsparcie społeczności (dziesiątki milionów programistów).

• Java jest językiem obiektowym, który nadaje programom przejrzystą strukturę i pozwala na ponowne wykorzystanie kodu,
obniżając koszty rozwoju.
16
JRE - JAVA RUNTIME ENVIRONMENT
• Przeznaczenie:

• Użytkownicy uruchamiający aplety i aplikacje napisane w


technologii Java

• Opis:

• Środowisko wymagane do uruchamiania apletów i aplikacji


napisanych w języku programowania Java
17
JAVA SE - JAVA PLATFORM, STANDARD
EDITION
• Przeznaczenie:

• Programiści piszący aplety i aplikacje w technologii Java

• Opis:

• Pakiet narzędzi programistycznych do pisania apletów i aplikacji w


języku programowania Java
18
JRE VS. JDK

JRE (Java Runtime Environment) JDK (Java Development Kit)

Implementacja maszyny wirtualnej Java, który Pakiet oprogramowania, za pomocą którego


wykonuje programy Java. można tworzyć aplikacje oparte na języku Java.

Środowisko Java Runtime Environment to


Pakiet Java Development Kit jest niezbędny do
dodatek wymagany w celu uruchamiania
tworzenia aplikacji Java.
programów Java.
Pakiet JDK wymaga więcej miejsca na dysku,
Środowisko JRE jest mniejsze od pakietu JDK,
ponieważ zawiera środowisko JRE wraz z
przez co zajmuje mniej miejsca na dysku.
różnymi narzędziami programistycznymi.
19
JRE VS. JDK
JRE (Java Runtime Environment) JDK (Java Development Kit)

Zawiera maszynę JVM, podstawowe biblioteki i


Zawiera środowisko JRE, zestaw klas API,
inne dodatkowe składniki wymagane do
kompilator języka Java, narzędzie Webstart i
uruchamiania aplikacji i apletów napisanych w
dodatkowe pliki wymagane do pisania apletów i
języku Java.
aplikacji w języku Java.

20
IDE DLA JĘZYKA JAVA
• IntelliJ IDEA

• Eclipse

• Visual Studio Code

• NetBeans

• i inne…
21
INTELLIJ IDEA

22
SKŁADNIA JĘZYKA JAVA

public class Main {


public static void main(String[] args) {
System.out.println("Hello world!");
}
}

23
OUTPUT - PRINTLN

System.out.println("Hello World!");
System.out.println("I am learning Java.");
System.out.println("It is awesome!”);

// Output:
// Hello World!
// I am learning Java.
// It is awesome!

24
OUTPUT - PRINT

System.out.print("Hello World! ");


System.out.print("I will print on the same line.”);

// Output:
// Hello World! I will print on the same line.

25
KOMENTARZE

// This is a comment
System.out.println("Hello World"); // This is also a comment
/* This is a
multi-line comment */

26
ZMIENNE
• Zmienne są kontenerami do przechowywania wartości danych.

• W Javie istnieją różne typy zmiennych, na przykład:

• String - przechowuje tekst, taki jak „Hello”. Wartości String są otoczone podwójnymi cudzysłowami

• int - przechowuje liczby całkowite bez miejsc po przecinku, takie jak 123 lub -123

• oat - przechowuje liczby zmiennoprzecinkowe z miejscami dziesiętnymi, takie jak 19.99 lub -19.99

• char - przechowuje pojedyncze znaki, takie jak „a” lub „B”. Wartości char są otoczone pojedynczymi cudzysłowami

• boolean - przechowuje wartości z dwoma stanami: prawda lub fałsz

• Deklarowanie zmiennej:

• type variableName = value;

27
fl
DEFINIOWANIE ZMIENNYCH
public class Main {
public static void main(String[] args) {
String name = "John";
System.out.println("Hello, " + name + "!"); // Output: Hello, John!

int myNum = 5;
System.out.println(myNum); // Output: 5

int myOtherNum;
myOtherNum = 10;
System.out.println(myOtherNum); // Output: 10

myNum = 20;
System.out.println(myNum); // Output: 20
}
}
28
ZMIENNA FINAL

public class Main {


public static void main(String[] args) {
final int a = 10;
System.out.println(a); // 10
a = 20; // Compile error
}
}

29
TYPY DANYCH

30
TYPY PRYMITYWNE
Typ Rozmiar Opis

byte 1 bajt Liczby od -128 do 127>

short 2 bajty Liczby od -32 767 do 32 768

Liczby od -2 147 483 648 do 2


int 4 bajty
147 483 647
Liczby od -9 223 372 036 854 775
long 8 bajtów 808 do 9 223 372 036 854 775
807
31
TYPY PRYMITYWNE
Typ Rozmiar Opis

Liczby zmiennoprzecinkowe z max


oat 4 bajty
6/7 miejsc dziesiętnych

Liczby zmiennoprzecinkowe z max


double 8 bajtów
15 miejsc dziesiętnych

boolean 1 bit true lub false

Pojedynczy znak lub litera kodu


char 2 bajty
ASCII

32
fl
TYPY LICZBOWE
public class Main {
public static void main(String[] args) {
byte myByte = 100;
System.out.println(myByte);
short myShort = 5000;
System.out.println(myShort);
int myInt = 100000;
System.out.println(myInt);
long myLong = 1000000000L;
System.out.println(myLong);
float myFloat = 5.75f;
System.out.println(myFloat);
double myDouble = 19.99d;
System.out.println(myDouble);
}
}
33
TYPY LICZBOWE - ZAPIS NAUKOWY

public class Main {


public static void main(String[] args) {
float f1 = 35e3f;
double d1 = 12E4d;
System.out.println(f1); // 35000.0
System.out.println(d1); // 120000.0
}
}

34
TYP CHAR

public class Main {


public static void main(String[] args) {
char myGrade = 'B';
System.out.println(myGrade); // Output: B
char myVar1 = 65, myVar2 = 66, myVar3 = 67;
System.out.println(myVar1); // Output: A
System.out.println(myVar2); // Output: B
System.out.println(myVar3); // Output: C
}
}

35
TYPY NIEPRYMITYWNE
• Nieprymitywne typy danych są nazywane typami referencyjnymi, ponieważ odnoszą się do obiektów.

• Główne różnice między prymitywnymi i nieprymitywnymi typami danych są następujące:

• Typy prymitywne są prede niowane (już zde niowane) w Javie. Typy nieprymitywne są tworzone przez programistę
i nie są zde niowane przez Javę (z wyjątkiem String).

• Typy nieprymitywne mogą być używane do wywoływania metod w celu wykonania pewnych operacji, podczas gdy
typy prymitywne nie mogą.

• Typ prymitywny zawsze ma wartość, podczas gdy typy nieprymitywne mogą mieć wartość null.

• Typ prymitywny zaczyna się małą literą, podczas gdy typy nieprymitywne zaczynają się wielką literą.

• Przykładami typów nieprymitywnych są ciągi znaków, tablice, klasy, interfejsy itp.


36
fi
fi
fi
RZUTOWANIE TYPÓW
• Rzutowanie typów ma miejsce, gdy wartość jednego prymitywnego typu danych jest przypisywana do
innego typu.

• W Javie istnieją dwa rodzaje rzutowania:

• Rzutowanie rozszerzające (automatycznie) - konwersja mniejszego typu na typ o większym


rozmiarze

• byte -> short -> char -> int -> long -> oat -> double

• Rzutowanie zawężające (ręczne) - konwersja większego typu na typ o mniejszym rozmiarze

• double -> oat -> long -> int -> char -> short -> byte
37
fl
fl
RZUTOWANIE ROZSZERZAJĄCE

public class Main {


public static void main(String[] args) {
int myInt = 9;
double myDouble = myInt; // Automatic casting: int to
double

System.out.println(myInt); // Outputs 9
System.out.println(myDouble); // Outputs 9.0
}
}

38
RZUTOWANIE ZAWĘŻAJĄCE

public class Main {


public static void main(String[] args) {
double myDouble = 9.78d;
int myInt = (int) myDouble; // Manual casting: double to
int

System.out.println(myDouble); // Outputs 9.78


System.out.println(myInt); // Outputs 9
}
}

39
OPERATORY

40
OPERATORY ARYTMETYCZNE

Operator Nazwa Opis Przykład

% Modulo Zwraca resztę z dzielenia x%y

++ Inkrementacja Zwiększa wartość o 1 ++x

-- Dekrementacja Zmniejsza wartość o 1 --x

41
OPERATORY PRZYPISANIA
Operator Przykład Równoważny zapis

= x=5 N/D

+= x += 3 x=x+3

-= x -= 3 x=x-3

*= x *= 3 x=x*3

42
OPERATORY PRZYPISANIA
Operator Przykład Równoważny zapis

/= x /= 3 x=x/3

%= x %= 3 x=x%3

&= x &= 3 x=x&3

|= x |= 3 x=x|3

43
OPERATORY PRZYPISANIA

Operator Przykład Równoważny zapis

^= x ^= 3 x=x^3

>>= x >>= 3 x = x >> 3

<<= x <<= 3 x = x << 3

44
OPERATORY BITOWE
Operator Nazwa Opis Przykład
Ustawia bit wynikowy na 1, jeżeli oba
& Bitowy AND x&y
bity są równe 1
Ustawia bit wynikowy na 1, jeżeli co
| Bitowy OR x|y
najmniej jeden bit jest równy 1
Ustawia bit wynikowy na 1, jeżeli
^ Bitowy XOR x^y
jeden z bitów to 1, a drugi 0
Przesunięcie bitowe w Przesunięcie bitów w prawo, skrajne
>> x >> 2
prawo prawe bity „spadają”
Przesunięcie bitowe w Przesunięcie bitów w lewo i
<< x << 2
lewo wypełnienie zerami
~ Negacja bitowa Odwraca bity ~x

45
BITOWY AND

public class Main {


public static void main(String[] args) {
int x = 10;
x = x & 3;
System.out.println(x); // 2
}
}

46
BITOWY OR

public class Main {


public static void main(String[] args) {
int x = 10;
x = x | 3;
System.out.println(x); // 11
}
}

47
BITOWY XOR

public class Main {


public static void main(String[] args) {
int x = 10;
x = x ^ 3;
System.out.println(x); // 9
}
}

48
PRZESUNIĘCIE BITOWE W PRAWO

public class Main {


public static void main(String[] args) {
int x = 10;
x = x >> 3;
System.out.println(x); // 1
}
}

49
PRZESUNIĘCIE BITOWE W LEWO

public class Main {


public static void main(String[] args) {
int x = 10;
x = x << 3;
System.out.println(x); // 80
}
}

50
NEGACJA BITOWA

public class Main {


public static void main(String[] args) {
int x = 10;
x = ~x;
System.out.println(x); // -11
}
}

51
OPERATORY PORÓWNANIA

Operator Nazwa Przykład

== Równe x == y

!= Nie równe x != y

> Większe od x>y

52
OPERATORY PORÓWNANIA

Operator Nazwa Przykład

< Mniejsze od x<y

>= Większe lub równe x >= y

<= Mniejsze lub równe x <= y

53
OPERATORY LOGICZNE

Operator Nazwa Opis Przykład

Zwraca true, jeżeli oba


&& Logiczny AND x && y
stwierdzenia są prawdziwe
Zwraca true, jeżeli co najmniej
|| Logiczny OR jedno stwierdzenie jest x || y
prawdziwe
Odwraca wynik, zwraca false,
! Logiczny NOT !x
jeżeli stwierdzenie jest prawdziwe
54
PRZYDATNE FUNKCJE MATEMATYCZNE

55
MATH.MAX()

public class Main {


public static void main(String[] args) {
System.out.println(Math.max(5, 10)); // 10
}
}

56
MATH.MIN()

public class Main {


public static void main(String[] args) {
System.out.println(Math.min(5, 10)); // 5
}
}

57
MATH.SQRT()

public class Main {


public static void main(String[] args) {
System.out.println(Math.sqrt(64)); // 8.0
}
}

58
MATH.ABS()

public class Main {


public static void main(String[] args) {
System.out.println(Math.abs(-4.47f)); // 4.47
}
}

59
MATH.RANDOM()

public class Main {


public static void main(String[] args) {
System.out.println(Math.random()); // random number
between 0.0 and 1.0
System.out.println((int) (Math.random() * 101)); //
random number between 0 and 100
System.out.println((int) (Math.random() * 100) + 1); //
random number between 1 and 100
}
}

60
INSTRUKCJE WARUNKOWE

61
IF
public class Main {
public static void main(String[] args) {
int x = 20;
int y = 18;
if (x > y) {
System.out.println("x is greater than y");
}

// Output: x is greater than y


}
}

62
ELSE
public class Main {
public static void main(String[] args) {
int time = 20;
if (time < 18) {
System.out.println("Good day.");
} else {
System.out.println("Good evening.");
}
// Outputs "Good evening."
}
}

63
ELSE IF
public class Main {
public static void main(String[] args) {
int time = 22;
if (time < 10) {
System.out.println("Good morning.");
} else if (time < 18) {
System.out.println("Good day.");
} else {
System.out.println("Good evening.");
}

// Output: Good evening.


}
}
64
OPERATOR TRÓJARGUMENTOWY (ELVIS)

• Istnieje skrót if else, który jest znany jako operator trójargumentowy,


ponieważ składa się z trzech operandów.

• Można go użyć do zastąpienia wielu wierszy kodu jednym wierszem i


jest najczęściej używany do zastępowania prostych instrukcji if else:

• variable = (condition) ? expressionTrue : expressionFalse;

65
OPERATOR TRÓJARGUMENTOWY (ELVIS)
public class Main {
public static void main(String[] args) {
int time = 20;
if (time < 18) {
System.out.println("Good day.");
} else {
System.out.println("Good evening.");
}

// Simplified version
System.out.println(time < 18 ? "Good day." : "Good evening.");
}
}
66
SWITCH
public class Main {
public static void main(String[] args) {
int day = 4;
switch (day) {
case 1:
System.out.println("Monday");
break;
case 2:
System.out.println("Tuesday");
break;
case 3:
System.out.println("Wednesday");
break;
case 4:
System.out.println("Thursday");
break;
case 5:
System.out.println("Friday");
break;
case 6:
System.out.println("Saturday");
break;
case 7:
System.out.println("Sunday");
break;
}

// Output: Thursday
}
}

67
SŁOWO KLUCZOWE BREAK
• Po osiągnięciu słowa kluczowego break, Java przerywa wykonywanie
bloku switch.

• Spowoduje to zatrzymanie wykonywania większej ilości kodu i


testowania przypadków wewnątrz bloku.

• Po znalezieniu dopasowania i wykonaniu zadania nadchodzi czas na


przerwanie. Nie ma potrzeby dalszego testowania.
68
PRZYPADEK DEFAULT
public class Main {
public static void main(String[] args) {
int day = 4;
switch (day) {
case 6:
System.out.println("Today is Saturday");
break;
case 7:
System.out.println("Today is Sunday");
break;
default:
System.out.println("Looking forward to the Weekend");
}

// Output: Looking forward to the Weekend


}
}

69
PĘTLE

70
PĘTLA WHILE
public class Main {
public static void main(String[] args) {
int i = 0;
while (i < 5) {
System.out.println(i);
i++;
}

// Output:
// 0
// 1
// 2
// 3
// 4
}
}
71
PĘTLA DO…WHILE
public class Main {
public static void main(String[] args) {
int i = 0;
do {
System.out.println(i);
i++;
}
while (i < 5);

// Output:
// 0
// 1
// 2
// 3
// 4
}
}

72
73
74
PĘTLA FOR
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
System.out.println(i);
}

// Output:
// 0
// 1
// 2
// 3
// 4
}
}
75
PĘTLA FOR
public class Main {
public static void main(String[] args) {
int i = 0;
for (; i < 5;) {
System.out.println(i);
i++;
}

// Output:
// 0
// 1
// 2
// 3
// 4
}
}
76
PĘTLA FOR

public static void main(String[] args) {


int i = 0;
for (;;) {
if (i == 5) {
break;
}
System.out.println(i);
i++;
}
}

77
ZAGNIEŻDŻONE PĘTLE
public class Main {
public static void main(String[] args) {
for (int i = 1; i <= 2; i++) {
System.out.println("Outer: " + i); // Executes 2 times

// Inner loop
for (int j = 1; j <= 3; j++) {
System.out.println(" Inner: " + j); // Executes 6 times (2 * 3)
}
}
// Output:
// Outer: 1
// Inner: 1
// Inner: 2
// Inner: 3
// Outer: 2
// Inner: 1
// Inner: 2
// Inner: 3
}
}

78
PĘTLA FOR-EACH
public class Main {
public static void main(String[] args) {
String[] cars = {"Volvo", "BMW", "Ford", "Mazda"};
for (String i : cars) {
System.out.println(i);
}
// Output:
// Volvo
// BMW
// Ford
// Mazda
}
}
79
TABLICE

80
TABLICE
public class Main {
public static void main(String[] args) {
// Declare arrays
String[] cars;
String[] cars2 = {"Volvo", "BMW", "Ford", "Mazda"};
int[] myNum = {10, 20, 30, 40};

// Empty array
String[] cars3 = new String[4];

// Accessing elements
System.out.println(cars2[0]); // Output: Volvo

// Change an array element


cars2[0] = "Opel";
System.out.println(cars2[0]); // Output: Opel

// Array length
System.out.println(cars2.length); // Output: 4
}
}

81
TABLICE WIELOWYMIAROWE
public class Main {
public static void main(String[] args) {
// Declare array
int[][] myNumbers = { {1, 2, 3, 4}, {5, 6, 7} };

// Access elements
int[][] myNumbers2 = { {1, 2, 3, 4}, {5, 6, 7} };
System.out.println(myNumbers2[1][2]); // Outputs 7

// Change an array element


int[][] myNumbers3 = { {1, 2, 3, 4}, {5, 6, 7} };
myNumbers3[1][2] = 9;
System.out.println(myNumbers3[1][2]); // Outputs 9 instead of 7
}
}
82
METODY

83
METODY
• Metoda to blok kodu, który jest uruchamiany tylko wtedy, gdy zostanie
wywołany.

• Do metody można przekazywać dane zwane parametrami.

• Metody są używane do wykonywania określonych działań i są również znane


jako funkcje.

• Dlaczego warto używać metod? Aby ponownie użyć kodu: zde niuj kod raz i
używaj go wiele razy.
84

fi
METODY
public class Main {
// Defining a method
static void myMethod() {
System.out.println("I just got executed!");
}

public static void main(String[] args) {


// Calling a method
myMethod(); // Output: I just got executed!
myMethod(); // Output: I just got executed!
myMethod(); // Output: I just got executed!
}
}
85
PARAMETRY I ARGUMENTY METOD
public class Main {
static void myMethod(String fname) {
System.out.println(fname + " Refsnes");
}

public static void main(String[] args) {


myMethod("Liam"); // Output: Liam Refsnes
myMethod("Jenny"); // Output: Jenny Refsnes
myMethod("Anja"); // Output: Anja Refsnes
}
}

86
WARTOŚCI ZWROTNE

public class Main {


static int myMethod(int x) {
return 5 + x;
}

public static void main(String[] args) {


System.out.println(myMethod(3)); // Output: 8
}
}

87
WARTOŚCI ZWROTNE

public class Main {


static int myMethod(int x, int y) {
return x + y;
}

public static void main(String[] args) {


System.out.println(myMethod(5, 3)); // Output: 8
}
}

88
PRZECIĄŻANIE METOD
public class Main {
static int plusMethod(int x, int y) {
return x + y;
}

static double plusMethod(double x, double y) {


return x + y;
}

public static void main(String[] args) {


int myNum1 = plusMethod(8, 5);
double myNum2 = plusMethod(4.3, 6.26);
System.out.println("int: " + myNum1); // Output: 13
System.out.println("double: " + myNum2); // Output: 10.56
}
}
89
ZAKRES (SCOPE)
• W języku Java zmienne są dostępne tylko w regionie, w którym zostały utworzone.
Nazywa się to zakresem.

• Zmienne zadeklarowane bezpośrednio wewnątrz metody są dostępne w dowolnym


miejscu metody następującym po linii kodu, w której zostały zadeklarowane.

• Blok kodu odnosi się do całego kodu pomiędzy nawiasami klamrowymi {}.

• Zmienne zadeklarowane wewnątrz bloków kodu są dostępne tylko przez kod znajdujący
się pomiędzy nawiasami klamrowymi, który następuje po linii, w której zmienna została
zadeklarowana.
90
ZAKRES METODY
public class Main {
public static void main(String[] args) {

// Code here CANNOT use x

int x = 100;

// Code here can use x


System.out.println(x);
}
}

91
ZAKRES BLOKOWY
public class Main {
public static void main(String[] args) {

// Code here CANNOT use x

{ // This is a block

// Code here CANNOT use x

int x = 100;

// Code here CAN use x


System.out.println(x);

} // The block ends here

// Code here CANNOT use x

}
}

92
REKURENCJA
• Rekurencja to technika wywoływania funkcji samej w sobie. Technika ta zapewnia sposób na
rozbicie skomplikowanych problemów na proste problemy, które są łatwiejsze do rozwiązania.

• Rekurencja może być nieco trudna do zrozumienia. Najlepszym sposobem na poznanie jej
działania jest eksperymentowanie.

• Podobnie jak pętle mogą napotkać problem nieskończonej pętli, funkcje rekurencyjne mogą
napotkać problem nieskończonej rekurencji. Nieskończona rekurencja ma miejsce, gdy funkcja
nigdy nie przestaje wywoływać samej siebie. Każda funkcja rekurencyjna powinna mieć
warunek zatrzymania, czyli warunek, w którym funkcja przestaje wywoływać samą siebie.

93
REKURENCJA
public class Main {
static int factorial(int n) {
if (n == 0) {
return 1;
}
return n * factorial(n - 1);
}

public static void main(String[] args) {


System.out.println(factorial(5)); // 120
}
}
94
PROGRAMOWANIE OBIEKTOWE W
JĘZYKU JAVA

95
TWORZENIE KLASY

// MyClass.java

public class MyClass {


int x = 5;
}

96
TWORZENIE OBIEKTU

public class Main {


public static void main(String[] args) {
MyClass myObj = new MyClass();
System.out.println(myObj.x); // Output: 5
}
}

97
ATRYBUTY I METODY
// MyClass.java

public class MyClass {


// Attributes
int x = 5;
int y = 3;

// Methods
public void myMethod() {
System.out.println("Hello World");
}
}
98
KONSTRUKTOR
// MyClass.java

public class MyClass {


int x;

// Constructor wihout parameters


public MyClass() {
x = 5;
}

// Constructor with parameters


public MyClass(int y) {
x = y;
}
}
99
KONSTRUKTOR

public class Main {


public static void main(String[] args) {
MyClass myObj = new MyClass();
System.out.println(myObj.x); // Output: 5

MyClass myObj2 = new MyClass(10);


System.out.println(myObj2.x); // Output: 10
}
}

100
MODYFIKATORY DOSTĘPU

101
MODYFIKATORY DOSTĘPU DLA KLAS

Mody kator Opis

public Klasa jest dostępna dla każdej innej klasy

Klasa jest dostępna tylko dla klas w tym samym pakiecie. Jest
default
używana, gdy nie określono mody katora.

102
fi
fi
MODYFIKATORY DOSTĘPU DLA METOD I
ATRYBUTÓW
Mody kator Opis

public Kod jest dostępny dla wszystkich klas

private Kod jest dostępny tylko w obrębie zadeklarowanej klasy

Kod jest dostępny tylko w tym samym pakiecie. Jest to


default
używane, gdy nie określono mody katora.
Kod jest dostępny w tym samym pakiecie i klasach
protected
potomnych.
103
fi
fi
MODYFIKATORY INNE NIŻ DOSTĘPU

104
MODYFIKATORY INNE NIŻ DOSTĘPU
DLA KLAS
Mody kator Opis

nal Klasa nie może być dziedziczona przez inne klasy

Klasa nie może być używana do tworzenia obiektów (aby


abstract uzyskać dostęp do klasy abstrakcyjnej, inna klasa musi po niej
dziedziczyć).
105
fi
fi
MODYFIKATORY INNE NIŻ DOSTĘPU
DLA METOD I ATRYBUTÓW
Mody kator Opis

Atrybuty i metody nie mogą być zastępowane/


nal
mody kowane

static Atrybuty i metody należą do klasy, a nie do obiektu.

Może być używany tylko w klasie abstrakcyjnej i tylko w


abstract metodach. Metoda nie ma ciała, na przykład abstract void
run();. Ciało jest dostarczane przez podklasę.
106
fi
fi
fi
MODYFIKATORY INNE NIŻ DOSTĘPU
DLA METOD I ATRYBUTÓW
Mody kator Opis

Atrybuty i metody są pomijane podczas serializacji


transient
zawierającego je obiektu

synchronized Dostęp do metod może mieć tylko jeden wątek na raz

Wartość atrybutu nie jest buforowana lokalnie w wątku i


volatile
jest zawsze odczytywana z „pamięci głównej”
107
fi
FINAL
public class Main {
final int x = 10;
final double PI = 3.14;

public static void main(String[] args) {


Main myObj = new Main();
myObj.x = 50; // will generate an error: cannot assign a
value to a final variable
myObj.PI = 25; // will generate an error: cannot assign a
value to a final variable
System.out.println(myObj.x);
}
}
108
STATIC
public class Main {
// Static method
static void myStaticMethod() {
System.out.println("Static methods can be called without creating objects");
}

// Public method
public void myPublicMethod() {
System.out.println("Public methods must be called by creating objects");
}

// Main method
public static void main(String[ ] args) {
myStaticMethod(); // Call the static method
// myPublicMethod(); This would output an error

Main myObj = new Main(); // Create an object of Main


myObj.myPublicMethod(); // Call the public method
}
}

109
ABSTRACT

// AbstractStudent.java

abstract class AbstractStudent {


public String fname = "John";
public int age = 24;
public abstract void study(); // abstract method
}

110
ABSTRACT

// Student.java

class Student extends AbstractStudent {


public int graduationYear = 2018;
public void study() { // the body of the abstract method is
provided here
System.out.println("Studying all day long");
}
}

111
ABSTRACT
public class Main {
public static void main(String[ ] args) {
// create an object of the Student class (which inherits
attributes and methods from AbstractStudent)
Student myObj = new Student();

System.out.println("Name: " + myObj.fname);


System.out.println("Age: " + myObj.age);
System.out.println("Graduation Year: " +
myObj.graduationYear);
myObj.study(); // call abstract method
}
}
112
ENKAPSULACJA

• Znaczenie enkapsulacji polega na upewnieniu się, że „wrażliwe” dane


są ukryte przed użytkownikami. Aby to osiągnąć, należy

• zadeklarować zmienne/atrybuty klasy jako prywatne

• zapewnić publiczne metody get i set, aby uzyskać dostęp i


aktualizować wartość zmiennej prywatnej

113
ENKAPSULACJA
// Person.java

public class Person {


private String name; // private = restricted access

// Getter
public String getName() {
return name;
}

// Setter
public void setName(String newName) {
this.name = newName;
}
}
114
ENKAPSULACJA

public class Main {


public static void main(String[ ] args) {
Person myObj = new Person();
// myObj.name = "John"; // this will cause an error

myObj.setName("John"); // Set the value of the name


variable to "John"
System.out.println(myObj.getName());
}
}

115
DLACZEGO ENKAPSULACJA?
• Lepsza kontrola nad atrybutami i metodami klas

• Atrybuty klasy mogą być tylko do odczytu (jeśli używasz tylko metody
get) lub tylko do zapisu (jeśli używasz tylko metody set).

• Elastyczność: programista może zmienić jedną część kodu bez wpływu


na inne części.

• Zwiększone bezpieczeństwo danych


116
PAKIETY

117
PAKIETY I API
• Pakiet w Javie służy do grupowania powiązanych klas. Można to
porównać do folderu w katalogu plików. Używamy pakietów, aby uniknąć
kon iktów nazw i pisać lepszy w utrzymaniu kod. Pakiety dzielą się na
dwie kategorie:

• Pakiety wbudowane (pakiety z Java API)

• Pakiety zde niowane przez użytkownika (tworzenie własnych


pakietów)
118
fl
fi
PAKIETY WBUDOWANE
• Java API to biblioteka wstępnie napisanych klas, z których można korzystać bezpłatnie,
zawarta w środowisku programistycznym Java.

• Biblioteka zawiera komponenty do zarządzania danymi wejściowymi, programowania baz


danych i wiele innych.

• Biblioteka jest podzielona na pakiety i klasy. Oznacza to, że można zaimportować


pojedynczą klasę (wraz z jej metodami i atrybutami) lub cały pakiet, który zawiera
wszystkie klasy należące do określonego pakietu.

• Aby użyć klasy lub pakietu z biblioteki, należy użyć słowa kluczowego import.
119
PAKIETY WBUDOWANE
// import class
import java.util.Scanner;

// import package
import java.util.*;

public class Main {


public static void main(String[ ] args) {
// ... code ...
}
}

120
PAKIETY WBUDOWANE
// import class
import java.util.Scanner;

public class Main {


public static void main(String[ ] args) {
Scanner myObj = new Scanner(System.in);
System.out.println("Enter username");

String userName = myObj.nextLine();


System.out.println("Username is: " + userName);
}
}
121
PAKIETY DEFINIOWANE PRZEZ
UŻYTKOWNIKA
• Aby utworzyć własny pakiet, musisz zrozumieć, że Java używa
katalogów systemu plików do ich przechowywania. Podobnie jak
foldery na komputerze:

└── root
└── mypack
└── MyPackageClass.java

122
PAKIETY DEFINIOWANE PRZEZ
UŻYTKOWNIKA

package mypack;

public class MyPackageClass {


public static void main(String[] args) {
System.out.println("This is my package!");
}
}

123
DZIEDZICZENIE
• W Javie możliwe jest dziedziczenie atrybutów i metod z jednej klasy
do drugiej. Koncepcję dziedziczenia dzielimy na dwie kategorie:

• podklasa (dziecko) - klasa, która dziedziczy z innej klasy

• superclass (rodzic) - klasa, po której się dziedziczy.

• Aby dziedziczyć z klasy, należy użyć słowa kluczowego extends.


124
DZIEDZICZENIE

// Vehicle.java

class Vehicle {
protected String brand = "Ford"; // Vehicle attribute
public void honk() { // Vehicle method
System.out.println("Tuut, tuut!");
}
}

125
DZIEDZICZENIE

// Car.java

class Car extends Vehicle {


private String modelName = "Mustang"; // Car attribute

public String getModelName() {


return this.modelName;
}
}

126
DZIEDZICZENIE
public class Main {
public static void main(String[ ] args) {
// Create a myCar object
Car myCar = new Car();

// Call the honk() method (from the Vehicle class) on the myCar
object
myCar.honk();

// Display the value of the brand attribute (from the Vehicle


class) and the value of the modelName from the Car class
System.out.println(myCar.brand + " " + myCar.getModelName());
}
}
127
POLIMORFIZM

• Polimor zm oznacza „wiele form” i występuje, gdy mamy wiele klas,


które są ze sobą powiązane poprzez dziedziczenie.

• Dziedziczenie pozwala nam dziedziczyć atrybuty i metody z innej


klasy. Polimor zm wykorzystuje te metody do wykonywania różnych
zadań. Pozwala nam to wykonywać jedną czynność na różne sposoby.

128
fi
fi
POLIMORFIZM

// Animal.java

class Animal {
public void animalSound() {
System.out.println("The animal makes a sound");
}
}

129
POLIMORFIZM

// Pig.java

class Pig extends Animal {


public void animalSound() {
System.out.println("The pig says: wee wee");
}
}

130
POLIMORFIZM

// Dog.java

class Dog extends Animal {


public void animalSound() {
System.out.println("The dog says: woof woof");
}
}

131
POLIMORFIZM
public class Main {
public static void main(String[ ] args) {
Animal myAnimal = new Animal(); // Create a Animal object
Animal myPig = new Pig(); // Create a Pig object
Animal myDog = new Dog(); // Create a Dog object

Animal[] animals = {myAnimal, myPig, myDog};

for (Animal animal : animals) {


animal.animalSound();
}

// Output:
// The animal makes a sound
// The pig says: wee wee
// The dog says: woof woof
}
}

132
KLASA WEWNĘTRZNA

• W Javie możliwe jest również zagnieżdżanie klas (klasa wewnątrz


klasy). Celem klas zagnieżdżonych jest grupowanie klas, które należą
do siebie, co sprawia, że kod jest bardziej czytelny i łatwy w
utrzymaniu.

133
KLASA WEWNĘTRZNA

// OuterClass.java

class OuterClass {
int x = 10;

class InnerClass {
int y = 5;
}
}

134
KLASA WEWNĘTRZNA

public class Main {


public static void main(String[ ] args) {
OuterClass outerObject = new OuterClass();
OuterClass.InnerClass innerObject = outerObject.new
InnerClass();
System.out.println(outerObject.x + innerObject.y);
}
}

135
PRYWATNA KLASA WEWNĘTRZNA

// OuterClass.java

class OuterClass {
int x = 10;

private class InnerClass {


int y = 5;
}
}

136
PRYWATNA KLASA WEWNĘTRZNA
public class Main {
public static void main(String[ ] args) {
OuterClass outerObject = new OuterClass();
OuterClass.InnerClass innerObject = outerObject.new
InnerClass();
System.out.println(outerObject.x + innerObject.y);
// Main.java:4: error: OuterClass.InnerClass has private
access in OuterClass
// OuterClass.InnerClass innerObject = outerObject.new
InnerClass();
// ^
}
}
137
STATYCZNA KLASA WEWNĘTRZNA

// OuterClass.java

class OuterClass {
int x = 10;

static class InnerClass {


int y = 5;
}
}

138
STATYCZNA KLASA WEWNĘTRZNA

public class Main {


public static void main(String[ ] args) {
OuterClass outerObject = new OuterClass();
OuterClass.InnerClass innerObject = new
OuterClass.InnerClass();
System.out.println(outerObject.x + innerObject.y);
}
}

139
DOSTĘP DO KLASY ZEWNĘTRZNEJ Z
KLASY WEWNĘTRZNEJ
// OuterClass.java

class OuterClass {
int x = 10;

class InnerClass {
public int myInnerMethod() {
return x;
}
}
}

140
DOSTĘP DO KLASY ZEWNĘTRZNEJ Z
KLASY WEWNĘTRZNEJ

public class Main {


public static void main(String[ ] args) {
OuterClass myOuter = new OuterClass();
OuterClass.InnerClass myInner = myOuter.new InnerClass();
System.out.println(myInner.myInnerMethod()); // Output:
10
}
}

141
KLASY I METODY ABSTRAKCYJNE
• Abstrakcja danych to proces ukrywania pewnych szczegółów i pokazywania użytkownikowi tylko
niezbędnych informacji.

• Abstrakcję można osiągnąć za pomocą klas abstrakcyjnych lub interfejsów

• Słowo kluczowe abstract jest mody katorem niedostępnym, używanym dla klas i metod:

• Klasa abstrakcyjna: jest ograniczoną klasą, która nie może być używana do tworzenia
obiektów (aby uzyskać do niej dostęp, musi być dziedziczona w innej klasie).

• Metoda abstrakcyjna: może być używana tylko w klasie abstrakcyjnej i nie ma ciała. Treść jest
dostarczana przez podklasę.
142
fi
KLASY I METODY ABSTRAKCYJNE
// Animal.java

// Abstract class
abstract class Animal {
// Abstract method (does not have a body)
public abstract void animalSound();
// Regular method
public void sleep() {
System.out.println("Zzz");
}
}

143
KLASY I METODY ABSTRAKCYJNE

// Pig.java

public class Pig extends Animal {


public void animalSound() {
// The body of animalSound() is provided here
System.out.println("The pig says: wee wee");
}
}

144
KLASY I METODY ABSTRAKCYJNE

public class Main {


public static void main(String[ ] args) {
Pig myPig = new Pig(); // Create a Pig object
myPig.animalSound(); // Output: The pig says: wee wee
myPig.sleep(); // Output: Zzz
}
}

145
INTERFEJSY
• Innym sposobem na osiągnięcie abstrakcji w Javie są interfejsy.

• Interfejs jest całkowicie „abstrakcyjną klasą”, która służy do grupowania


powiązanych metod z pustymi ciałami.

• Aby uzyskać dostęp do metod interfejsu, interfejs musi zostać


„zaimplementowany” (coś w rodzaju dziedziczenia) przez inną klasę za
pomocą słowa kluczowego implements (zamiast extends). Ciało
metody interfejsu jest dostarczane przez klasę „implementującą”.
146
INTERFEJSY

// Animal.java

interface Animal {
void animalSound(); // interface method (does not have a
body)
void sleep(); // interface method (does not have a body)
}

147
INTERFEJSY
// Pig.java

class Pig implements Animal {


public void animalSound() {
// The body of animalSound() is provided here
System.out.println("The pig says: wee wee");
}
public void sleep() {
// The body of sleep() is provided here
System.out.println("Zzz");
}
}
148
INTERFEJSY

public class Main {


public static void main(String[ ] args) {
Pig myPig = new Pig(); // Create a Pig object
myPig.animalSound(); // Output: The pig says: wee wee
myPig.sleep(); // Output: Zzz
}
}

149
UWAGI DOTYCZĄCE INTERFEJSÓW
• Podobnie jak klasy abstrakcyjne, interfejsy nie mogą być używane do tworzenia obiektów.

• Metody interfejsu nie mają ciała - ciało jest dostarczane przez klasę „implementującą”.

• Po zaimplementowaniu interfejsu należy nadpisać wszystkie jego metody.

• Metody interfejsu są domyślnie abstrakcyjne i publiczne

• Atrybuty interfejsu są domyślnie publiczne, statyczne i ostateczne.

• Interfejs nie może zawierać konstruktora (ponieważ nie może być używany do tworzenia
obiektów).
150
DLACZEGO I KIEDY UŻYWAĆ
INTERFEJSÓW?
• Aby osiągnąć bezpieczeństwo - ukryć pewne szczegóły i pokazać
tylko ważne szczegóły obiektu (interfejsu).

• Java nie obsługuje „wielokrotnego dziedziczenia” (klasa może


dziedziczyć tylko z jednej nadklasy). Można to jednak osiągnąć za
pomocą interfejsów, ponieważ klasa może implementować wiele
interfejsów.

151
IMPLEMENTACJA WIELU INTERFEJSÓW

// FirstInterface.java

interface FirstInterface {
public void myMethod(); // interface method
}

152
IMPLEMENTACJA WIELU INTERFEJSÓW

// SecondInterface.java

interface SecondInterface {
public void myOtherMethod(); // interface method
}

153
IMPLEMENTACJA WIELU INTERFEJSÓW

// DemoClass.java

class DemoClass implements FirstInterface, SecondInterface {


public void myMethod() {
System.out.println("Some text..");
}
public void myOtherMethod() {
System.out.println("Some other text...");
}
}

154
IMPLEMENTACJA WIELU INTERFEJSÓW

public class Main {


public static void main(String[ ] args) {
DemoClass myObj = new DemoClass();
myObj.myMethod(); // Output: Some text..
myObj.myOtherMethod(); // Output: Some other text...
}
}

155
ENUMERATORY

• Enumerator to specjalna „klasa”, która reprezentuje grupę stałych


(niezmiennych zmiennych, takich jak zmienne końcowe).

• Aby utworzyć enumerator, należy użyć słowa kluczowego enum


(zamiast class lub interface) i oddzielić stałe przecinkiem. Należy
pamiętać, że powinny być one pisane wielkimi literami

156
ENUMERATORY

// Level.java

enum Level {
LOW,
MEDIUM,
HIGH
}

157
ENUMERATORY

public class Main {


public static void main(String[ ] args) {
Level myLevel = Level.HIGH;
}
}

158
ENUM WEWNĄTRZ KLASY
public class Main {
enum Level {
LOW,
MEDIUM,
HIGH
}

public static void main(String[] args) {


Level myVar = Level.MEDIUM;
System.out.println(myVar); // Output: MEDIUM
}
}
159
PĘTLA PRZEZ WARTOŚCI
ENUMERATORA
public class Main {
enum Level {
LOW,
MEDIUM,
HIGH
}

public static void main(String[] args) {


for (Level myVar : Level.values()) {
System.out.println(myVar);
}

// Output:
// LOW
// MEDIUM
// HIGH
}
}

160
PRZYJMOWANIE DANYCH OD
UŻYTKOWNIKA

161
PRZYJMOWANIE DANYCH OD
UŻYTKOWNIKA

• Klasa Scanner służy do pobierania danych wejściowych użytkownika i


znajduje się w pakiecie java.util.

• Aby użyć klasy Scanner, należy utworzyć obiekt tej klasy i użyć
dowolnej z dostępnych metod znajdujących się w dokumentacji klasy
Scanner.

162
PRZYJMOWANIE DANYCH OD
UŻYTKOWNIKA
import java.util.Scanner; // Import the Scanner class

class Main {
public static void main(String[] args) {
Scanner myObj = new Scanner(System.in); // Create a Scanner
object
System.out.println("Enter username");

String userName = myObj.nextLine(); // Read user input


System.out.println("Username is: " + userName); // Output
user input
}
}
163
TYPY PRZYJMOWANYCH DANYCH
Metoda Opis

nextBoolean() Odczytuje od użytkownika wartość typu boolean

nextByte() Odczytuje od użytkownika wartość typu byte

nextDouble() Odczytuje od użytkownika wartość typu double

nextFloat() Odczytuje od użytkownika wartość typu oat

164
fl
TYPY PRZYJMOWANYCH DANYCH
Metoda Opis

nextInt() Odczytuje od użytkownika wartość typu int

nextLine() Odczytuje od użytkownika wartość typu String

nextLong() Odczytuje od użytkownika wartość typu long

nextShort() Odczytuje od użytkownika wartość typu short

165
TYPY PRZYJMOWANYCH DANYCH
import java.util.Scanner;

class Main {
public static void main(String[] args) {
Scanner myObj = new Scanner(System.in);

System.out.println("Enter name, age and salary:");

// String input
String name = myObj.nextLine();

// Numerical input
int age = myObj.nextInt();
double salary = myObj.nextDouble();

// Output input by user


System.out.println("Name: " + name);
System.out.println("Age: " + age);
System.out.println("Salary: " + salary);
}
}

166
TYPY PRZYJMOWANYCH DANYCH

• Uwaga: Jeśli wprowadzisz nieprawidłowe dane (np. tekst w danych


liczbowych), otrzymasz wyjątek/komunikat o błędzie (np.
„InputMismatchException”).

167
OBSŁUGA DAT

168
OBSŁUGA DAT

• Java nie ma wbudowanej klasy Date, ale możemy zaimportować


pakiet java.time, aby pracować z API daty i czasu. Pakiet ten zawiera
wiele klas daty i czasu.

169
WYŚWIETLANIE BIEŻĄCEJ DATY

import java.time.LocalDate;

public class Main {


public static void main(String[] args) {
LocalDate myObj = LocalDate.now(); // Create a date
object
System.out.println(myObj); // Display the current date
}
}

170
WYŚWIETLANIE BIEŻĄCEGO CZASU

import java.time.LocalTime;

public class Main {


public static void main(String[] args) {
LocalTime myObj = LocalTime.now();
System.out.println(myObj);
}
}

171
WYŚWIETLANIE BIEŻĄCEJ DATY I
GODZINY

import java.time.LocalDateTime;

public class Main {


public static void main(String[] args) {
LocalDateTime myObj = LocalDateTime.now();
System.out.println(myObj);
}
}

172
FORMATOWANIE DATY I CZASU
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class Main {


public static void main(String[] args) {
LocalDateTime myDateObj = LocalDateTime.now();
System.out.println("Before formatting: " + myDateObj);
DateTimeFormatter myFormatObj = DateTimeFormatter.ofPattern("dd-MM-yyyy
HH:mm:ss");

String formattedDate = myDateObj.format(myFormatObj);


System.out.println("After formatting: " + formattedDate);
}
}

// Before formatting: 2021-07-07T12:08:56.662


// After formatting: 07-07-2021 12:08:56

173
ARRAYLIST

174
ARRAYLIST
• Klasa ArrayList to tablica o zmiennym rozmiarze, którą można znaleźć
w pakiecie java.util.

• Różnica między wbudowaną tablicą a ArrayList w Javie polega na tym,


że rozmiar tablicy nie może być mody kowany (jeśli chcesz dodać lub
usunąć elementy do/z tablicy, musisz utworzyć nową). Podczas gdy
elementy mogą być dodawane i usuwane z ArrayList w dowolnym
momencie. Składnia jest również nieco inna.
175
fi
ARRAYLIST

import java.util.ArrayList;

public class Main {


public static void main(String[] args) {
ArrayList<String> cars = new ArrayList<String>(); //
Create an ArrayList object
}
}

176
DODAWANIE ELEMENTÓW
import java.util.ArrayList;

public class Main {


public static void main(String[] args) {
ArrayList<String> cars = new ArrayList<String>();
cars.add("Volvo");
cars.add("BMW");
cars.add("Ford");
cars.add("Mazda");
System.out.println(cars);
}
}

// Output: [Volvo, BMW, Ford, Mazda]


177
DODAWANIE ELEMENTÓW
import java.util.ArrayList;

public class Main {


public static void main(String[] args) {
ArrayList<String> cars = new ArrayList<String>();
cars.add("Volvo");
cars.add("BMW");
cars.add("Ford");

cars.add(0, "Mazda"); // Insert element at the beginning of the list (0)

System.out.println(cars);
}
}

// Output: [Mazda, Volvo, BMW, Ford]


178
DOSTĘP DO ELEMENTU
import java.util.ArrayList;

public class Main {


public static void main(String[] args) {
ArrayList<String> cars = new ArrayList<String>();
cars.add("Volvo");
cars.add("BMW");
cars.add("Ford");

System.out.println(cars.get(0)); // Output: Volvo


}
}
179
ZMIANA ELEMENTU
import java.util.ArrayList;

public class Main {


public static void main(String[] args) {
ArrayList<String> cars = new ArrayList<String>();
cars.add("Volvo");
cars.add("BMW");
cars.add("Ford");

cars.set(0, "Opel");

System.out.println(cars.get(0)); // Output: Volvo


}
}
180
USUWANIE ELEMENTU
import java.util.ArrayList;

public class Main {


public static void main(String[] args) {
ArrayList<String> cars = new ArrayList<String>();
cars.add("Volvo");
cars.add("BMW");
cars.add("Ford");

cars.remove(0);

System.out.println(cars.get(0)); // Output: BMW


}
}
181
CZYSZCZENIE ARRAYLIST
import java.util.ArrayList;

public class Main {


public static void main(String[] args) {
ArrayList<String> cars = new ArrayList<String>();
cars.add("Volvo");
cars.add("BMW");
cars.add("Ford");

cars.clear();

System.out.println(cars); // Output: []
}
}
182
ROZMIAR ARRAYLIST
import java.util.ArrayList;

public class Main {


public static void main(String[] args) {
ArrayList<String> cars = new ArrayList<String>();
cars.add("Volvo");
cars.add("BMW");
cars.add("Ford");

System.out.println(cars.size()); // Output: 3
}
}
183
PRZEJŚCIE PĘTLĄ
import java.util.ArrayList;

public class Main {


public static void main(String[] args) {
ArrayList<String> cars = new ArrayList<String>();
cars.add("Volvo");
cars.add("BMW");
cars.add("Ford");
cars.add("Mazda");
for (int i = 0; i < cars.size(); i++) {
System.out.println(cars.get(i));
}
}
}
184
PRZEJŚCIE PĘTLĄ
import java.util.ArrayList;

public class Main {


public static void main(String[] args) {
ArrayList<String> cars = new ArrayList<String>();
cars.add("Volvo");
cars.add("BMW");
cars.add("Ford");
cars.add("Mazda");
for (String car : cars) {
System.out.println(car);
}
}
}
185
ARRAYLIST - TYPY DANYCH
• Elementy w ArrayList są w rzeczywistości obiektami. W powyższych przykładach
utworzyliśmy elementy (obiekty) typu „String”.

• Należy pamiętać, że String w Javie jest obiektem (nie typem prymitywnym).

• Aby użyć innych typów, takich jak int, należy określić równoważną klasę wrapper:
Integer.

• W przypadku innych typów prymitywnych należy użyć: Boolean dla boolean,


Character dla char, Double dla double itd.
186
SORTOWANIE
import java.util.ArrayList;
import java.util.Collections; // Import the Collections class

public class Main {


public static void main(String[] args) {
ArrayList<String> cars = new ArrayList<String>();
cars.add("Volvo");
cars.add("BMW");
cars.add("Ford");
cars.add("Mazda");
Collections.sort(cars); // Sort cars
for (String i : cars) {
System.out.println(i);
}
}
}
// Output: BMW Ford Mazda Volvo

187
SORTOWANIE
import java.util.ArrayList;
import java.util.Collections; // Import the Collections class

public class Main {


public static void main(String[] args) {
ArrayList<Integer> myNumbers = new ArrayList<Integer>();
myNumbers.add(33);
myNumbers.add(15);
myNumbers.add(20);
myNumbers.add(34);
myNumbers.add(8);
myNumbers.add(12);

Collections.sort(myNumbers); // Sort myNumbers

for (int i : myNumbers) {


System.out.println(i);
}
}
}
// Output: 8 12 15 20 33 34

188
LINKEDLIST

189
LINKEDLIST
import java.util.LinkedList;

public class Main {


public static void main(String[] args) {
LinkedList<String> cars = new LinkedList<String>();
cars.add("Volvo");
cars.add("BMW");
cars.add("Ford");
cars.add("Mazda");
System.out.println(cars);
}
}

// Output [Volvo, BMW, Ford, Mazda]


190
ARRAYLIST VS. LINKEDLIST
• Klasa LinkedList jest kolekcją, która może zawierać wiele obiektów tego
samego typu, podobnie jak ArrayList.

• Klasa LinkedList posiada wszystkie te same metody co klasa ArrayList, ponieważ


obie implementują interfejs List. Oznacza to, że można dodawać elementy,
zmieniać elementy, usuwać elementy i czyścić listę w ten sam sposób.

• Jednakże, podczas gdy klasa ArrayList i LinkedList mogą być używane w ten sam
sposób, są one zbudowane zupełnie inaczej.
191
JAK DZIAŁA ARRAYLIST?

• Klasa ArrayList zawiera w sobie zwykłą tablicę. Po dodaniu elementu


jest on umieszczany w tablicy. Jeśli tablica nie jest wystarczająco duża,
tworzona jest nowa, większa tablica, która zastępuje starą, a stara jest
usuwana.

192
JAK DZIAŁA LINKEDLIST?

• LinkedList przechowuje swoje elementy w „kontenerach”. Lista ma


łącze do pierwszego kontenera, a każdy kontener ma łącze do
następnego kontenera na liście. Aby dodać element do listy, element
jest umieszczany w nowym kontenerze, a ten kontener jest połączony
z jednym z innych kontenerów na liście.

193
METODY LINKEDLIST
Metoda Opis
addFirst() Dodaje element na początku listy
addLast() Dodaje element na koniec listy
removeFirst() Usuwa element z początku listy
removeLast() Usuwa element z końca listy
getFirst() Pobierz element z początku listy
getLast() Pobiera element z końca listy
194
HASHMAP

195
HASHMAP

• HashMap przechowuje elementy w parach „klucz/wartość”, a dostęp


do nich można uzyskać za pomocą indeksu typu innego (np. String).

• Jeden obiekt jest używany jako klucz (indeks) do innego obiektu


(wartość). Może przechowywać różne typy: String klucze i Integer
wartości, lub tego samego typu, jak: String klucze i String wartości:

196
DODAWANIE ELEMENTÓW
// Import the HashMap class
import java.util.HashMap;

public class Main {


public static void main(String[] args) {
// Create a HashMap object called capitalCities
HashMap<String, String> capitalCities = new HashMap<String, String>();

// Add keys and values (Country, City)


capitalCities.put("England", "London");
capitalCities.put("Germany", "Berlin");
capitalCities.put("Norway", "Oslo");
capitalCities.put("USA", "Washington DC");
System.out.println(capitalCities);
}
}
// Output: {USA=Washington DC, Norway=Oslo, England=London, Germany=Berlin}

197
DOSTĘP DO ELEMENTU
// Import the HashMap class
import java.util.HashMap;

public class Main {


public static void main(String[] args) {
// Create a HashMap object called capitalCities
HashMap<String, String> capitalCities = new HashMap<String, String>();

// Add keys and values (Country, City)


capitalCities.put("England", "London");
capitalCities.put("Germany", "Berlin");
capitalCities.put("Norway", "Oslo");
capitalCities.put("USA", "Washington DC");
System.out.println(capitalCities.get("England"));
}
}
// Output: London

198
USUWANIE ELEMENTU
// Import the HashMap class
import java.util.HashMap;

public class Main {


public static void main(String[] args) {
// Create a HashMap object called capitalCities
HashMap<String, String> capitalCities = new HashMap<String, String>();

// Add keys and values (Country, City)


capitalCities.put("England", "London");
capitalCities.put("Germany", "Berlin");
capitalCities.put("Norway", "Oslo");
capitalCities.put("USA", "Washington DC");

capitalCities.remove("England");

System.out.println(capitalCities);
}
}
// Output: {USA=Washington DC, Norway=Oslo, Germany=Berlin}

199
CZYSZCZENIE HASHMAP
// Import the HashMap class
import java.util.HashMap;

public class Main {


public static void main(String[] args) {
// Create a HashMap object called capitalCities
HashMap<String, String> capitalCities = new HashMap<String, String>();

// Add keys and values (Country, City)


capitalCities.put("England", "London");
capitalCities.put("Germany", "Berlin");
capitalCities.put("Norway", "Oslo");
capitalCities.put("USA", "Washington DC");

capitalCities.clear();

System.out.println(capitalCities);
}
}
// Output: {}

200
ROZMIAR HASHMAP
// Import the HashMap class
import java.util.HashMap;

public class Main {


public static void main(String[] args) {
// Create a HashMap object called capitalCities
HashMap<String, String> capitalCities = new HashMap<String, String>();

// Add keys and values (Country, City)


capitalCities.put("England", "London");
capitalCities.put("Germany", "Berlin");
capitalCities.put("Norway", "Oslo");
capitalCities.put("USA", "Washington DC");

System.out.println(capitalCities.size());
}
}
// Output: 4

201
PĘTLA PRZEZ HASHMAP
// Print keys
for (String i : capitalCities.keySet()) {
System.out.println(i); // Output: England, Germany, Norway, USA
}

// Print values
for (String i : capitalCities.values()) {
System.out.println(i); // Output: London, Berlin, Oslo, Washington DC
}

// Print keys and values


for (String i : capitalCities.keySet()) {
System.out.println("key: " + i + " value: " + capitalCities.get(i)); //
Output: key: England value: London, key: Germany value: Berlin, key: Norway value:
Oslo, key: USA value: Washington DC
}
202
HASHSET

203
HASHSET

• HashSet jest zbiorem elementów, w którym każdy element jest


unikalny.

204
HASHSET
// Import the HashSet class
import java.util.HashSet;

public class Main {


public static void main(String[] args) {
HashSet<String> cars = new HashSet<String>();
cars.add("Volvo");
cars.add("BMW");
cars.add("Ford");
cars.add("BMW");
cars.add("Mazda");
System.out.println(cars); // Output : [BMW, Volvo, Ford, Mazda]
}
}
205
SPRAWDZANIE CZY ELEMENT ISTNIEJE
// Import the HashSet class
import java.util.HashSet;

public class Main {


public static void main(String[] args) {
HashSet<String> cars = new HashSet<String>();
cars.add("Volvo");
cars.add("BMW");
cars.add("Ford");
cars.add("Mazda");

System.out.println(cars.contains("Mazda")); // Output: true


}
}
206
USUWANIE ELEMENTU
// Import the HashSet class
import java.util.HashSet;

public class Main {


public static void main(String[] args) {
HashSet<String> cars = new HashSet<String>();
cars.add("Volvo");
cars.add("BMW");
cars.add("Ford");
cars.add("Mazda");

cars.remove("Volvo");

System.out.println(cars); // Output: [BMW, Ford, Mazda]


}
}
207
CZYSZCZENIE HASHSET
// Import the HashSet class
import java.util.HashSet;

public class Main {


public static void main(String[] args) {
HashSet<String> cars = new HashSet<String>();
cars.add("Volvo");
cars.add("BMW");
cars.add("Ford");
cars.add("Mazda");

cars.clear();

System.out.println(cars); // Output: []
}
}
208
ROZMIAR HASHSET
// Import the HashSet class
import java.util.HashSet;

public class Main {


public static void main(String[] args) {
HashSet<String> cars = new HashSet<String>();
cars.add("Volvo");
cars.add("BMW");
cars.add("Ford");
cars.add("Mazda");

System.out.println(cars.size()); // Output 4
}
}
209
PĘTLA PRZEZ HASHSET

for (String i : cars) {


System.out.println(i); // Output: Volvo, BMW, Ford, Mazda
}

210
ITERATOR

211
ITERATOR
• Iterator to obiekt, który może być używany do zapętlania kolekcji,
takich jak ArrayList i HashSet. Nazywany jest „iteratorem”, ponieważ
„iterowanie” jest technicznym określeniem pętli.

• Aby użyć Iteratora, należy zaimportować go z pakietu java.util.

• Metoda iterator() może być użyta do uzyskania Iteratora dla


dowolnej kolekcji.
212
ITERATOR
import java.util.ArrayList;
import java.util.Iterator;

public class Main {


public static void main(String[] args) {
ArrayList<String> cars = new ArrayList<String>();
cars.add("Volvo");
cars.add("BMW");
cars.add("Ford");
cars.add("Mazda");

// Get the iterator


Iterator<String> it = cars.iterator();

// Print the first item


System.out.println(it.next());
}
}

213
PĘTLA Z UŻYCIEM ITERATORA

while(it.hasNext()) {
System.out.println(it.next());
}

214
CZYSZCZENIE KOLEKCJI Z UŻYCIEM
ITERATORA
ArrayList<Integer> numbers = new ArrayList<Integer>();
numbers.add(12);
numbers.add(8);
numbers.add(2);
numbers.add(23);
Iterator<Integer> it = numbers.iterator();
while(it.hasNext()) {
Integer i = it.next();
if(i < 10) {
it.remove();
}
}
System.out.println(numbers); // Output: [12, 23]
215
WRAPPER CLASSES

216
WRAPPER CLASSES

• Klasy opakowujące zapewniają sposób na wykorzystanie


prymitywnych typów danych (int, boolean itp.) jako obiektów.

217
WRAPPER CLASSES
Typ prymitywny Wrapper Class
byte Byte
short Short
int Integer
long Long
oat Float
double Double
boolean Boolean
char Char
218
fl
PO CO?
import java.util.ArrayList;

public class Main {


public static void main(String[] args) {
ArrayList<int> myNumbers = new ArrayList<int>(); //
Invalid

ArrayList<Integer> myNumbers = new


ArrayList<Integer>(); // Valid
}
}

219
TWORZENIE WRAPPER OBJECTS
import java.util.ArrayList;

public class Main {


public static void main(String[] args) {
Integer myInt = 5;
Double myDouble = 5.99;
Character myChar = 'A';
System.out.println(myInt); // Output: 5
System.out.println(myDouble); // Output: 5.99
System.out.println(myChar); // Output: A
}
}
220
METODY WRAPPER OBJECTS
public class Main {
public static void main(String[] args) {
Integer myInt = 5;
Double myDouble = 5.99;
Character myChar = 'A';
System.out.println(myInt.intValue()); // Returns the value
of this Integer as an int.
System.out.println(myDouble.doubleValue()); // Returns the
value of this Double as a double.
System.out.println(myChar.charValue()); // Returns the
value of this Character object as a char.
}
}
221
METODY WRAPPER OBJECTS

public class Main {


public static void main(String[] args) {
Integer myInt = 100;
String myString = myInt.toString();
System.out.println(myString.length()); // Outputs 3
}
}

222
OBSŁUGA BŁĘDÓW

223
TRY…CATCH

try {
// Block of code to try
}
catch(Exception e) {
// Block of code to handle errors
}

224
TRY…CATCH

public class Main {


public static void main(String[ ] args) {
int[] myNumbers = {1, 2, 3};
System.out.println(myNumbers[10]); // error!
}
}

// Exception in thread "main"


java.lang.ArrayIndexOutOfBoundsException: 10
// at Main.main(Main.java:4)

225
TRY…CATCH
public class Main {
public static void main(String[ ] args) {
try {
int[] myNumbers = {1, 2, 3};
System.out.println(myNumbers[10]);
} catch (Exception e) {
System.out.println("Something went wrong.");
}
}
}

// Output: Something went wrong.


226
FINALLY
public class Main {
public static void main(String[ ] args) {
try {
int[] myNumbers = {1, 2, 3};
System.out.println(myNumbers[10]);
} catch (Exception e) {
System.out.println("Something went wrong.");
} finally {
System.out.println("The 'try catch' is finished.");
}
}
}

// Output: Something went wrong.


// The 'try catch' is finished.
227
THROW

• Instrukcja throw umożliwia utworzenie niestandardowego błędu.

• Instrukcja throw jest używana razem z typem wyjątku. W języku Java


dostępnych jest wiele typów wyjątków: ArithmeticException,
FileNotFoundException, ArrayIndexOutOfBoundsException,
SecurityException, itd.

228
THROW
public class Main {
static void checkAge(int age) {
if (age < 18) {
throw new ArithmeticException("Access denied - You must be at least 18 years
old.");
}
else {
System.out.println("Access granted - You are old enough!");
}
}

public static void main(String[] args) {


checkAge(15); // Set age to 15 (which is below 18...)
}
}

// Output: Exception in thread "main" java.lang.ArithmeticException: Access denied - You must


be at least 18 years old.

229
WYRAŻENIA REGULARNE

230
CO TO JEST WYRAŻENIE REGULARNE?
• Wyrażenie regularne to ciąg znaków, który tworzy wzorzec wyszukiwania.
Podczas wyszukiwania danych w tekście można użyć tego wzorca
wyszukiwania, aby opisać to, czego szukasz.

• Wyrażenie regularne może być pojedynczym znakiem lub bardziej


skomplikowanym wzorcem.

• Wyrażenia regularne mogą być używane do wykonywania wszystkich


typów operacji wyszukiwania i zamiany tekstu.
231
CO TO JEST WYRAŻENIE REGULARNE?
• Java nie ma wbudowanej klasy wyrażeń regularnych, ale możemy zaimportować
pakiet java.util.regex do pracy z wyrażeniami regularnymi. Pakiet ten zawiera
następujące klasy:

• Klasa Pattern - de niuje wzorzec (do użycia w wyszukiwaniu)

• Klasa Matcher - używana do wyszukiwania wzorca

• Klasa PatternSyntaxException - wskazuje błąd składni we wzorcu


wyrażenia regularnego.
232
fi
WYRAŻENIA REGULARNE
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {


public static void main(String[] args) {
Pattern pattern = Pattern.compile("zsk", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher("Visit ZSK!");
boolean matchFound = matcher.find();
if(matchFound) {
System.out.println("Match found");
} else {
System.out.println("Match not found");
}
}
}
// Output: Match found
233
FLAGI
• Flagi w metodzie compile() zmieniają sposób wyszukiwania. Oto kilka z nich:

• Pattern.CASE_INSENSITIVE - wielkość liter będzie ignorowana podczas


wyszukiwania.

• Pattern.LITERAL - znaki specjalne we wzorcu nie będą miały żadnego


specjalnego znaczenia i będą traktowane jak zwykłe znaki podczas wyszukiwania.

• Pattern.UNICODE_CASE - Użyj go razem z agą CASE_INSENSITIVE,


aby zignorować wielkość liter spoza alfabetu angielskiego.
234 fl
WĄTKI

235
WĄTKI

• Wątki pozwalają programowi działać wydajniej poprzez wykonywanie


wielu czynności w tym samym czasie.

• Wątki mogą być używane do wykonywania skomplikowanych zadań


w tle bez przerywania głównego programu.

236
TWORZENIE WĄTKU

public class Main extends Thread {


public void run() {
System.out.println("This code is running in a thread");
}
}

237
TWORZENIE WĄTKU

public class Main implements Runnable {


public void run() {
System.out.println("This code is running in a thread");
}
}

238
URUCHAMIANIE WĄTKU

public class Main extends Thread {


public static void main(String[] args) {
Main thread = new Main();
thread.start();
System.out.println("This code is outside of the thread");
}
public void run() {
System.out.println("This code is running in a thread");
}
}

239
URUCHAMIANIE WĄTKU
public class Main implements Runnable {
public static void main(String[] args) {
Main obj = new Main();
Thread thread = new Thread(obj);
thread.start();
System.out.println("This code is outside of the thread");
}
public void run() {
System.out.println("This code is running in a thread");
}
}

240
RÓŻNICE MIĘDZY „ROZSZERZANIEM” I
„IMPLEMENTOWANIEM” WĄTKÓW

• Główna różnica polega na tym, że gdy klasa rozszerza klasę Thread,


nie można rozszerzyć żadnej innej klasy, ale poprzez implementację
interfejsu Runnable możliwe jest rozszerzenie z innej klasy, na
przykład: class MyClass extends OtherClass implements Runnable.

241
PROBLEMY ZE WSPÓŁBIEŻNOŚCIĄ
• Ponieważ wątki działają w tym samym czasie, co inne części programu, nie ma sposobu,
aby dowiedzieć się, w jakiej kolejności kod zostanie uruchomiony. Gdy wątki i program
główny odczytują i zapisują te same zmienne, ich wartości są nieprzewidywalne.
Wynikające z tego problemy nazywane są problemami współbieżności.

• Aby uniknąć problemów ze współbieżnością, najlepiej jest współdzielić jak najmniej


atrybutów między wątkami. Jeśli atrybuty muszą być współdzielone, jednym z
możliwych rozwiązań jest użycie metody isAlive() wątku w celu sprawdzenia, czy wątek
zakończył działanie przed użyciem jakichkolwiek atrybutów, które wątek może zmienić.

242
PROBLEMY ZE WSPÓŁBIEŻNOŚCIĄ
public class Main extends Thread {
public static int amount = 0;

public static void main(String[] args) {


Main thread = new Main();
thread.start();
System.out.println(amount);
amount++;
System.out.println(amount);
}

public void run() {


amount++;
}
}
243
PROBLEMY ZE WSPÓŁBIEŻNOŚCIĄ
public class Main extends Thread {
public static int amount = 0;

public static void main(String[] args) {


Main thread = new Main();
thread.start();
// Wait for the thread to finish
while(thread.isAlive()) {
System.out.println("Waiting...");
}
// Update amount and print its value
System.out.println("Main: " + amount);
amount++;
System.out.println("Main: " + amount);
}
public void run() {
amount++;
}
}

244
LAMBDA

245
WYRAŻENIA LAMBDA
• Wyrażenia lambda zostały dodane w Javie 8.

• Wyrażenie lambda to krótki blok kodu, który przyjmuje parametry i zwraca


wartość. Wyrażenia lambda są podobne do metod, ale nie potrzebują
nazwy i mogą być zaimplementowane bezpośrednio w treści metody.

• Najprostsze wyrażenie lambda zawiera pojedynczy parametr i wyrażenie:

• parametr -> wyrażenie


246
WYRAŻENIA LAMBDA
• Aby użyć więcej niż jednego parametru, należy ująć je w nawiasy:

• (parametr1, parametr2) -> wyrażenie

• Wyrażenia są ograniczone. Muszą natychmiast zwracać wartość i nie mogą zawierać


zmiennych, przypisań ani instrukcji takich jak if lub for. Aby wykonać bardziej złożone
operacje, można użyć bloku kodu z nawiasami klamrowymi. Jeśli wyrażenie lambda
musi zwracać wartość, blok kodu powinien zawierać instrukcję return.

• (parametr1, parametr2) -> { blok kodu }


247
UŻYWANIE LAMBDY
import java.util.ArrayList;

public class Main {


public static void main(String[] args) {
ArrayList<Integer> numbers = new ArrayList<Integer>();
numbers.add(5);
numbers.add(9);
numbers.add(8);
numbers.add(1);
numbers.forEach( (n) -> { System.out.println(n); } );
}
}
// Output: 5 9 8 1
248
ZAPIS LAMBDY DO ZMIENNEJ

• Wyrażenia lambda mogą być przechowywane w zmiennych, jeśli typ


zmiennej jest interfejsem, który ma tylko jedną metodę. Wyrażenie
lambda powinno mieć taką samą liczbę parametrów i taki sam typ
zwracany jak ta metoda. Java ma wbudowanych wiele tego typu
interfejsów, takich jak interfejs Consumer (znajdujący się w pakiecie
java.util) używany przez listy.

249
ZAPIS LAMBDY DO ZMIENNEJ
import java.util.ArrayList;
import java.util.function.Consumer;

public class Main {


public static void main(String[] args) {
ArrayList<Integer> numbers = new ArrayList<Integer>();
numbers.add(5);
numbers.add(9);
numbers.add(8);
numbers.add(1);
Consumer<Integer> method = (n) -> { System.out.println(n); };
numbers.forEach( method );
}
}

// Output: 5 9 8 1
250
ZAPIS LAMBDY DO ZMIENNEJ

• Aby użyć wyrażenia lambda w metodzie, metoda powinna mieć


parametr, którego typem jest interfejs pojedynczej metody.
Wywołanie metody interfejsu spowoduje uruchomienie wyrażenia
lambda.

251
ZAPIS LAMBDY DO ZMIENNEJ
interface StringFunction {
String run(String str);
}

public class Main {


public static void main(String[] args) {
StringFunction exclaim = (s) -> s + "!";
StringFunction ask = (s) -> s + "?";
printFormatted("Hello", exclaim);
printFormatted("Hello", ask);
}
public static void printFormatted(String str, StringFunction format) {
String result = format.run(str);
System.out.println(result);
}
}

// Output:
// Hello!
// Hello?

252
WPROWADZENIE DO ANDROID
STUDIO

253
INSTALACJA ŚRODOWISKA ANDROID
STUDIO

254
WYMAGANIA SYSTEMOWE - WINDOWS
Parameter Minimalne Zalecane

Najnowsza 64-bitowa wersja


System operacyjny 64-bitowy Microsoft Windows 8
systemu Windows

Pamięć RAM 8GB RAM 16GB RAM lub więcej

architektura procesora x86_64; Procesor Intel Core 2 generacji lub


Procesor Najnowszy procesor Intel Core
nowszy albo AMD z obsługą systemu Windows Hypervisor Platform

dysk SSD z co najmniej 16 GB


Miejsce na dysku 8 GB (IDE i pakiet SDK na Androida oraz emulator)
pamięci,

Rozdzielczość ekranu 1280 x 800 1920 x 1080

255
INSTALACJA - WINDOWS
• Aby zainstalować Android Studio w systemie Windows, wykonaj te czynności:

• Jeśli masz pobrany plik .exe (zalecane), kliknij dwukrotnie aby ją uruchomić.

• Jeśli masz pobrany plik .zip:

• Rozpakuj urządzenie .zip.

• Skopiuj folder android-studio do folderu Program Files.

• Otwórz android-studio > bin.

• Uruchom studio64.exe (w przypadku systemów 64-bitowych) lub studio.exe (w wersji 32-bitowej) komputery).

• Postępuj zgodnie z kreatorem kon guracji w Android Studio i zainstaluj zalecane rozwiązania. Pakiety SDK.

256
fi
INSTALACJA - WINDOWS

257
WYMAGANIA SYSTEMOWE - MACOS
Parameter Minimalne Zalecane

Najnowsza wersja systemu


System operacyjny MacOS 10.14 (Mojave)
macOS

Pamięć RAM 8GB RAM 16GB RAM lub więcej

Procesor Apple M1 lub Intel Core 2 generacji bądź nowszy z Najnowszy układ krzemowy
Procesor
obsługą Hypervisor Platform Apple

dysk SSD z co najmniej 16 GB


Miejsce na dysku 8 GB (IDE i pakiet SDK na Androida oraz emulator)
pamięci,

Rozdzielczość ekranu 1280 x 800 1920 x 1080

258
INSTALACJA - MACOS
• Aby zainstalować Android Studio na Macu, wykonaj te czynności:

• Uruchom plik Android Studio DMG.

• Przeciągnij Android Studio i upuść go w folderze Aplikacje, a następnie uruchom


Android Studio.

• Wybierz, czy chcesz zaimportować poprzednie ustawienia ze Studio. i kliknij OK.

• Wykonaj kreator kon guracji Android Studio, co obejmuje pobranie Komponenty


Android SDK wymagane do programowania.
259
fi
INSTALACJA - MACOS

260
WYMAGANIA SYSTEMOWE - LINUX
Parameter Minimalne Zalecane

dowolna 64-bitowa dystrybucja Linuksa, która obsługuje środowiska Najnowsza 64-bitowa wersja
System operacyjny Gnome, KDE lub Unity DE; GNU C Library (glibc) w wersji 2.31 lub Linuksa
nowszej.

Pamięć RAM 8GB RAM 16GB RAM lub więcej

architektura procesora x86_64; Procesor Intel Core 2 generacji lub


Procesor Najnowszy procesor Intel Core
nowszy albo AMD z obsługą wirtualizacji AMD (AMD-V) i SSSE3.

dysk SSD z co najmniej 16 GB


Miejsce na dysku 8 GB (IDE i pakiet SDK na Androida oraz emulator)
pamięci,

Rozdzielczość ekranu 1280 x 800 1920 x 1080

261
INSTALACJA - LINUX
• Aby zainstalować Android Studio w Linuksie, wykonaj te czynności:

• Rozpakuj pobrany plik .tar.gz do odpowiednie miejsce dla Twoich aplikacji, na przykład w /usr/local/ w
Twoim pro lu użytkownika lub na /opt/ użytkowników, którym udostępniono treści.W 64-bitowej
wersji Linuksa najpierw zainstaluj biblioteki wymagane dla komputerów 64-bitowych,

• Aby uruchomić Androida Studio, otwórz terminal, przejdź do katalogu android-studio/bin/, i


wykonaj studio.sh.

• Wybierz, czy chcesz zaimportować poprzednie ustawienia ze Studio. i kliknij OK.

• Wykonaj kreator kon guracji Android Studio, co obejmuje pobranie Komponenty Android SDK
wymagane do programowania.
262
fi
fi
BIBLIOTEKI WYMAGANE W PRZYPADKU
MASZYN 64-BITOWYCH - LINUX
• Jeśli używasz 64-bitowej wersji Ubuntu, musisz zainstalować kilka 32-
bitowych za pomocą tego polecenia:

• sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386


lib32z1 libbz2-1.0:i386

• Jeśli używasz 64-bitowej wersji Fedory, polecenie będzie wyglądać tak:

• sudo yum install zlib.i686 ncurses-libs.i686 bzip2-libs.i686


263
INSTALACJA - LINUX

264
INTERFEJS ANDROID STUDIO

265
INTERFEJS ANDROID STUDIO

266
EDYTOR KODU
Uruchomienie
aktywności

Wybór edytowanego pliku

Edycja UI

Kod źródłowy

267
WIDOK PROJEKTU - ANDROID
Kod Java/Kotlin

Elementy UI
Prede niowane stałe
(teksty, kolory, itp.)

Motywy

268
fi
WIDOK PROJEKTU - STRUKTURA
PLIKÓW

269
PASEK GÓRNY - LEWA STRONA

Wybór projektu

Narzędzia GIT

270
PASEK GÓRNY - PRAWA STRONA

Kon guracja uruchomienia


Debugowanie Podpięcie debuggera
/ debugowania

Uruchomienie Budowanie
Wybrany emulator
projektu

271
fi
MENADŻER URZĄDZEŃ

272
AKTYWNY EMULATOR

273
TWORZENIE PIERWSZEGO PROJEKTU

274
EKRAN STARTOWY ANDROID STUDIO

Tworzenie
nowego
projektu

275
WYBÓR SZABLONU
Aktualnie Empty
Activity = Kotlin +
Jetpack Compose

Wybór typu Empty Views


urządzenia Activity - można
wybrać Javę

276
SZCZEGÓŁY PROJEKTU
Nazwa aplikacji
Lokalizacja na
Nazwa pakietu dysku
Język
programowania Minimalne
(Java/Kotlin) Android SDK

Kon guracja
Zakończenie
budowania
kon guracji

277
fi
fi
MINIMALNE ANDROID SDK

278
KONFIGURACJA EMULATORA AVD
(Android Virtual Device)

279
DODANIE NOWEGO EMULATORA

Dodawanie urządzenia

Nowy emulator lokalny

280
WYBÓR URZĄDZENIA

281
WYBÓR WERSJI SYSTEMU OPERACYJNEGO
Pobieranie obrazu SO

282
SPRAWDZENIE KONFIGURACJI

283
URUCHAMIANIE EMULATORA

Uruchamianie

284
URUCHOMIONY EMULATOR

285
PODSTAWY TWORZENIA INTERFEJSU
UŻYTKOWNIKA

286
EDYTOR UKŁADÓW

287
EDYTOR UKŁADÓW
3

5
2

288
1. PALETA

289
2. DRZEWO KOMPONENTÓW

290
3. PASEK NARZĘDZIOWY

291
4. EDYTOR

292
5. WŁAŚCIWOŚCI

293
PRZEŁĄCZNIK TRYBÓW WIDOKU

294
WIDOK XML

295
WIDOK SPLIT (XML + DESIGN)

296
PASEK NARZĘDZIOWY - PRZYCISKI

1 2 3 4 5 6

297
1. TRYB WIDOKU
• Tryb widoku — określa, w jaki sposób
pokazywany jest nasz układ.

• Tryb Design wyświetla układ tak, jak będzie


wyglądał w aplikacji po jej uruchomieniu.

• Tryb Blueprint (plan), na którym widoczny


jest tylko zarys użytych kontrolek.

• Design and Blueprint łączy oba powyższe


style.
298
2. ZMIANA ORIENTACJI EKRANU

• Zmiana orientacji ekranu — pozwala


na wyświetlanie układu w orientacji
poziomej (ang. landscape) lub
pionowej (ang. portrait).

299
3. TYP URZĄDZENIA ORAZ ROZMIAR
• Typ urządzenia oraz rozmiar — pozwala na
wybranie typu urządzenia (np. telefonu, tabletu,
telewizora) oraz jego rozmiaru wraz z gęstością
pikseli.

• Urządzenia wybieramy z prede niowanej listy albo


dodajemy własne.

• Dodatkowo możemy w łatwy sposób zmieniać ich


rozmiar przez uchwycenie dolnego rogu układu.

300
fi
4. WERSJA API

• Wersja API — określa wersję API, w


której chcemy zobaczyć nasz układ.

301
5. TEMAT APLIKACJI (THEME)

• Temat aplikacji — pozwala na


podgląd wybranego tematu aplikacji
w naszym układzie.

302
6. JĘZYK APLIKACJI

• Język aplikacji — pozwala na zmianę


języka naszej aplikacji. Na liście
wyświetlane są tylko dostępne wersje
językowe. Jeżeli zatem chcemy dodać
nową wersję, musimy z rozwijanej
listy wybrać opcję Edit Translations.

303
PRACA Z UKŁADAMI

304
PRACA Z UKŁADAMI

• Układ (ang. layout) to podstawowy element każdego interfejsu


użytkownika. To na nim umieszczamy kontrolki i inne elementy, które
będzie widział użytkownik i z których będzie korzystał.

305
UKŁADY DOSTĘPNE W OKNIE PALETY
• Do dyspozycji mamy pięć
podstawowych układów (pozycja
TableRow nie jest układem, ale
wierszem w układzie tabelarycznym,
zaś Space to lekka podklasa widoku,
która może być używana do tworzenia
przerw między komponentami w
układach ogólnego przeznaczenia.)
306
UKŁADY DOSTĘPNE W OKNIE PALETY
• ConstraintLayout — pozwala na tworzenie złożonych układów o płaskiej
strukturze, czyli bez zagnieżdżania w nim innych układów;

• LinearLayout (Horizontal) — wyświetla komponenty w jednym wierszu (jeden


obok drugiego);

• LinearLayout (Vertical) — wyświetla komponenty w jednej kolumnie (jeden


pod drugim);

• FrameLayout — przesłania cały obszar ekranu w celu wyświetlenia jednego


elementu; jeżeli umieścimy w nim kilka elementów, to na wierzchu zostanie
wyświetlony ten dodany jako ostatni (przykrywający inne);

• TableLayout — wyświetla elementy w układzie tabeli: każdy wiersz jest


reprezentowany przez komponent podrzędny TableRow.

307
UKŁADY DOSTĘPNE LEGACY
• GridLayout — układ siatki podzielony
niewidocznymi liniami na wiersze i kolumny
tworzące komórki (ang. cells), w których
możemy umieszczać komponenty;

• RelativeLayout — wyświetla elementy


przez podawanie ich pozycji względem
innych elementów;
308
LINEAR LAYOUT (HORIZONTAL)

309
LINEAR LAYOUT (HORIZONTAL)

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/
android"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>

310
STRUKTURA PLIKU XML
• W pierwszej linii de niujemy wersję XML-a (wersja 1.0) oraz sposób
kodowania znaków (kodowanie UTF-8).

• W drugiej linii — układ (w naszej sytuacji to LinearLayout). Z technicznego


punktu widzenia stanowi on element główny (ang. root element) pliku XML.
Zgodnie z wymaganiami możemy mieć tylko jeden element główny
(pozostałe muszą być w nim zagnieżdżone). Pierwszy wpis jest opatrzony
znakami <? i ?>, co oznacza instrukcję przetwarzania i nie jest traktowane
jako element główny.
311
fi
STRUKTURA PLIKU XML
• W znaczniku LinearLayout mamy też wpis xmlns:android=http://schemas.android.com/apk/res/
android, który pozwala na zde niowanie przestrzeni nazw. Od tej pory do przestrzeni nazw będziemy się
odwoływać za pomocą nazwy android. W tej przestrzeni zde niowane są elementy niezbędne do tworzenia
interfejsu użytkownika i będziemy bardzo często z niej korzystać. Kolejne linie rozpoczynają się od nazwy
android (która oznacza właśnie zde niowaną wcześniej przestrzeń).

• Kolejna linia to android:layout_width="match_parent". De niuje ona szerokość naszego układu.


Wskazana wartość "match_parent" oznacza, że nasz element zajmie cały obszar rodzica (czyli w naszej sytuacji
całą szerokość ekranu). To samo dotyczy właściwości layout_height, która oznacza wysokość naszego układu.
Te dwie właściwości (layout_width i layout_height) są obowiązkowe i nie możemy ich pominąć w de nicji układu.

• Ostatni znacznik </LinearLayout> to znacznik zamykający.

312
fi
fi
fi
fi
fi
LINEAR LAYOUT (VERTICAL)

313
LINEAR LAYOUT (VERTICAL)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Button" />

<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Button" />

<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Button" />

<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Button" />

<Button
android:id="@+id/button5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Button" />
</LinearLayout>

314
ANDROID:ID
<Button • android:id to jednoznaczny identy kator
android:id="@+id/
button" komponentu, przez który będziemy się do
niego odwoływać w kodzie programu. Znak @
android:layout_width="wrap_ oznacza odwołanie do pliku zasobów (ang.
content"
resources). Natomiast znak + oznacza, że
android:layout_height="wrap chcemy dodać identy kator właśnie w tym
_content" miejscu. Tych dwóch znaków (@,+) używamy
tylko raz w momencie de niowania
android:layout_weight="1"
android:text="Button" / identy katora. Natomiast odwołanie do niego
> realizujemy za pomocą samego znaku @.
315
fi
fi
fi
fi
OSTRZEŻENIA DOTYCZĄCE LAYOUTU

316
BUTTON SHOULD BE BORDERLESS

• Ostrzeżenie to informuje nas, że przyciski leżące obok siebie nie


powinny mieć obramowania (ang. borderless).

317
BUTTON SHOULD BE BORDERLESS
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/
android"
android:layout_width="match_parent"
android:layout_height="match_parent"
style="?android:attr/buttonBarStyle"> <!-- 1 -->

<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Button"
style="?android:attr/buttonBarButtonStyle" /> <!-- 2 -->
318
BUTTON SHOULD BE BORDERLESS
• Linia oznaczona cyfrą 1 dodaje styl do układu. Natomiast linia oznaczona
cyfrą 2 dodaje odpowiedni styl do przycisku. Ten wpis powinien być
wprowadzony do każdego przycisku.

• Znak zapytania, który widzimy na początku, określa, że style zastosowane do


przycisku będą pochodziły z bieżącego tematu aplikacji. Oznacza to, że jeżeli
zmienimy temat główny, to zmiany będą widoczne w tych elementach. Jeśli
pominęlibyśmy ten znak (co można zrobić), zastosowane style ustawione
byłyby na sztywno i nie uległyby mody kacji wraz ze zmianą tematu.
319
fi
BUTTON SHOULD BE BORDERLESS

320
HARDCODED TEXT
• Ostrzeżenie to informuje nas, że nasz napis (ang. string) jest zapisany bezpośrednio w pliku XML
naszej aktywności (activity_main.xml), a powinien być zapisany w pliku zasobów.

• To istotna uwaga i warto się do niej zastosować. Jeżeli tekst wyświetlany użytkownikowi zapiszemy w
pliku zasobów (strings.xml), to będziemy mieli pewien logiczny układ, którym łatwiej zarządzać. Na
przykład kiedy dany tekst jest wyświetlany w kilku różnych miejscach, wystarczy nam jeden zasób. W
takiej sytuacji zmiana napisu będzie wymagała zmiany tylko w jednej lokalizacji (w pliku zasobów).

• Poza tym jeżeli będziemy chcieli naszą aplikację dystrybuować w kilku językach, to powinniśmy wpisy
umieszczać w pliku strings.xml. Dzięki temu w łatwy sposób przygotujemy napisy lokalizacyjne w
innych językach.

321
DEFINIOWANIE ZASOBU TEKSTOWEGO -
TRYB GRAFICZNY

322
DEFINIOWANIE ZASOBU TEKSTOWEGO -
TRYB GRAFICZNY

323
DEFINIOWANIE ZASOBU TEKSTOWEGO -
TRYB GRAFICZNY

324
DEFINIOWANIE ZASOBU TEKSTOWEGO -
TRYB GRAFICZNY

325
DEFINIOWANIE ZASOBU TEKSTOWEGO -
TRYB EXTRACT

326
DEFINIOWANIE ZASOBU TEKSTOWEGO -
TRYB EXTRACT

327
ZAWARTOŚĆ PLIKU STRINGS.XML

<resources>
<string name="app_name">My Application</string>
<string name="button_1_text">Button 1</string>
<string name="button_2_text">Button 2</string>
</resources>

328
LINEAR LAYOUT (VERTICAL)

329
LINEAR LAYOUT (VERTICAL)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/
android"
android:layout_width="match_parent"
android:layout_height="match_parent"
style="?android:attr/buttonBarStyle"
android:orientation="vertical"> <!-- Orientacja układu -->

330
LINEAR LAYOUT (VERTICAL)

331
SZEROKOŚĆ PRZYCISKÓW

• Zobaczmy, że domyślnie przyciski zajmują tylko tyle miejsca, ile jest


niezbędne do prawidłowego wyświetlania ich zawartości. Decydują o
tym dwa atrybuty określone w de nicji przycisku:
android:layout_width oraz android:layout_height.
Ustawiono w nich wartość wrap_content. Jeżeli chcemy, aby przycisk
zajął całą szerokość okna, to wystarczy, że zmienimy wartość atrybutu
android:layout_width na match_parent.
332
fi
SZEROKOŚĆ PRZYCISKÓW

<Button
android:id="@+id/button"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/button_1_text" />

333
SZEROKOŚĆ PRZYCISKÓW

334
LAYOUT_WEIGHT
• Mamy jeszcze kilka innych opcji, które służą do określania rozmiaru komponentów. Zwróćmy
uwagę na brak wolnej przestrzeni na poprzednim zrzucie ekranu. Tą przestrzenią możemy
rozdysponować pomiędzy naszymi komponentami za pomocą atrybutu
android:layout_weight. Domyślnie (bez ustawiania tej wartości) każdy komponent
przyjmuje wartość tego atrybutu równą 0. Oznacza to, że nie jest mu udostępniana żadna
dodatkowa przestrzeń. Jeżeli zmienimy tę wartość na inną, różną od 0, to zajmie on całą
dostępną przestrzeń. Co się natomiast stanie w sytuacji, kiedy kilka komponentów będzie chciało
skorzystać z tej wartości? Z pomocą przychodzi nam odpowiedni wzór:

• ułamek dodatkowej przestrzeni przypisanej do danego komponentu = waga


danego komponentu / suma wag wszystkich komponentów.
335
WŁASNY ROZMIAR KOMPONENTÓW
• Przyszedł czas na zde niowanie własnych rozmiarów komponentów. W tym celu
wykorzystamy atrybuty android:layout_width oraz android:layout_height. Pierwszy
z nich określa szerokość naszego komponentu, drugi zaś jego wysokość.

• Jakich jednostek powinniśmy użyć? W systemie Windows byliśmy przyzwyczajeni do


stosowania pikseli. Ta popularna jednostka miary nie będzie jednak się dobrze sprawdzać na
urządzeniach z systemem Android, ponieważ mają one bardzo różne rozmiary: od małych
smartwatchy po duże telewizory. Co więcej, nawet w obrębie smartfonów rozdzielczość
ekranów oraz gęstość pikseli są bardzo zróżnicowane. Dlatego też wprowadzono jednostkę
dip (Density-independent Pixels). Można zamiennie stosować jej krótszą nazwę dp. Jest
to jednostka miary niezależna od gęstości.
336
fi
WŁASNY ROZMIAR KOMPONENTÓW
• Wartość 1 dp jest równoważna 1 pikselowi na ekranie o gęstości 160 dpi. To jednostka rekomendowana i właściwie
prawie zawsze powinniśmy ją wykorzystywać. Zagwarantuje to, że nasze aplikacje będą wyglądały podobnie na różnych
urządzeniach.

• Opiszmy jeszcze inne jednostki, których możemy używać:

• px (pixel) — oznacza rzeczywisty piksel na ekranie urządzenia,

• in (inch) — 1 cal równy jest 2,54 cm zycznego rozmiaru ekranu,

• mm (milimeter) — 1 milimetr zycznego rozmiaru ekranu,

• pt (point) — 1 punkt to 1/72 cala zycznego rozmiaru ekranu,

• sip (Scale-independent Pixels) lub sp — oznacza to samo co dp, z tym że odnosi się do tekstów, czyli bierze pod uwagę
ustawienia rozmiaru tekstów zde niowane w systemie przez użytkownika.
337
fi
fi
fi
fi
WŁASNY ROZMIAR KOMPONENTÓW
• Podsumowując, rekomendowane opcje to dp do rozmiarów
komponentów oraz sp do rozmiarów tekstów. Na koniec
omawiania jednostek podajmy jeszcze wzór, który pozwoli nam na
obliczenie rzeczywistej liczby pikseli zajmowanych przez dany element
(którego wielkość podawana jest w jednostce dp).

• Rzeczywista liczba pikseli = wartość dp / (wartość dpi :


160)
338
WARTOŚCI GĘSTOŚCI PIKSELI
• System Android określa obecnie sześć uogólnionych wartości gęstości pikseli (dpi):

• ldpi (low) — około 120 dpi,

• mdpi (medium) — około 160 dpi,

• hdpi (high) — około 240 dpi,

• xhdpi (extra-high) — około 320 dpi,

• xxhdpi (extra-extra-high) — około 480 dpi,

• xxxhdpi (extra-extra-extra-high) — około 640 dpi.


339
LAYOUT_GRAVITY
• Kolejny ważny atrybut, z którego będziemy często korzystali, to android:layout_gravity. Określa on położenie obiektu w układzie. Najważniejsze jego
właściwości to:

• top — umieszcza obiekt u góry układu,

• bottom — umieszcza obiekt u dołu układu,

• left — umieszcza obiekt z lewej strony układu,

• right — umieszcza obiekt z prawej strony układu,

• center_vertical — umieszcza obiekt pośrodku (biorąc pod uwagę położenie pionowe),

• center_horizontal — umieszcza obiekt pośrodku (biorąc pod uwagę położenie poziome),

• center — umieszcza obiekt pośrodku,

• start — umieszcza obiekt na początku układu,

• end — umieszcza obiekt na końcu układu.

340
LAYOUT_GRAVITY

• Zauważmy, że nie wszystkie wartości odniosą skutek w każdym


układzie. Na przykład ustawienie wartości top w układzie liniowym
nie zmieni położenia obiektu. Związane jest to z tym, że układ
komponentów został już określony i nie ma miejsca na przesunięcie
danego elementu do góry.

341
LAYOUT_GRAVITY
• Opisy opcji left i start są do siebie bardzo podobne (tak jak right i
end). Których powinniśmy używać?

• Zgodnie z zasadami internacjonalizacji powinniśmy korzystać z start


oraz end.

• Związane jest to z wyświetlaniem w językach, w których zapis tekstu


jest od prawej do lewej (np. język arabski)
342
PODSUMOWANIE ATRYBUTÓW
• android:orientation — określa orientację poziomą (wartość horizontal lub pominięcie atrybutu) albo pionową
(wartość vertical);

• android:layout_width — określa szerokość komponentu, wykorzystując dwie wartości: wartość wrap_content


oznacza szerokość zgodną z zawartością komponentu, a wartość match_parent szerokość równą szerokości
komponentu rodzica;

• android:layout_height — określa wysokość komponentu, wykorzystując dwie wartości: wartość wrap_content


oznacza wysokość zgodną z zawartością komponentu, a wartość match_parent wysokość równą wysokości
komponentu rodzica;

• android:layout_weight — określa wagowy przydział dodatkowej przestrzeni dostępnej dla danego komponentu;

• android:layout_gravity — określa położenie obiektu w układzie.

343
INNE WŁAŚCIWOŚCI WSPÓLNE DLA
KOMPONENTÓW WIZUALNYCH
• android:layout_marginTop — określa ilość dodatkowego wolnego miejsca od góry,

• android:layout_marginBottom — określa ilość dodatkowego wolnego miejsca od


dołu,

• android:layout_marginLeft — określa ilość dodatkowego wolnego miejsca z lewej


strony,

• android:layout_marginRight — określa ilość dodatkowego wolnego miejsca z


prawej strony.

344
TABLE LAYOUT

345
TABLE LAYOUT

• Układ tabelaryczny (ang. table layout) porządkuje elementy za


pomocą wierszy i kolumn. Nowy wiersz tabeli de niujemy za
pomocą znacznika <TableRow>. Do takiego wiersza możemy
dodać jeden komponent bądź kilka. Każdy dodany element tworzy
komórkę (ang. cell). Szerokość kolumny będzie równa najszerszej
komórce z całej kolumny.

346

fi
TABLE LAYOUT

<?xml version="1.0" encoding="utf-8"?>


<TableLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent" >
</TableLayout>

347
PRZYKŁAD WYKORZYSTANIA TABLE
LAYOUT

348
PRZYKŁAD WYKORZYSTANIA TABLE
LAYOUT - XML

<?xml version="1.0" encoding="utf-8"?>


<TableLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent" >

349
PRZYKŁAD WYKORZYSTANIA TABLE
LAYOUT - XML
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent" >

<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="0"
android:text="@string/username" />

<EditText
android:id="@+id/editTextText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="1"
android:ems="10"
android:inputType="text" />

</TableRow>

350
PRZYKŁAD WYKORZYSTANIA TABLE
LAYOUT - XML
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent" >

<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="0"
android:text="@string/password" />

<EditText
android:id="@+id/editTextTextPassword"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPassword" />

</TableRow>

351
PRZYKŁAD WYKORZYSTANIA TABLE
LAYOUT - XML
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent" >

<CheckBox
android:id="@+id/checkBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="1"
android:text="@string/remember_me" />
</TableRow>

352
PRZYKŁAD WYKORZYSTANIA TABLE
LAYOUT - XML
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent" >

<Button
android:id="@+id/button7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/sign_in" />
</TableRow>
</TableLayout>

353
FRAME LAYOUT

354
FRAME LAYOUT

• Układ FrameLayout rezerwuje dany obszar ekranu w celu


wyświetlenia pojedynczego elementu. Jeśli ułożymy na nim kilka
elementów, to będą one wyświetlane w formie stosu. Na górze zaś
znajdzie się ostatnio dodany element.

355
FRAME LAYOUT

<?xml version="1.0" encoding="utf-8"?>


<FrameLayout xmlns:android="http://schemas.android.com/apk/res/
android"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>

356
FRAME LAYOUT - PRZYKŁAD UŻYCIA

357
FRAME LAYOUT - PRZYKŁAD UŻYCIA
(XML)
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">

<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/todo"
tools:src="@tools:sample/backgrounds/scenic" />

<TextView
android:id="@+id/textView3"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textSize="50sp"
android:textColor="@color/red"
android:textStyle="bold"
android:text="@string/textview" />
</FrameLayout>

358
RELATIVE LAYOUT

359
RELATIVE LAYOUT

• Układ RelativeLayout, jak sama nazwa wskazuje, zbudowany jest


na podstawie idei ustalania położenia komponentów w odniesieniu
do położenia innych komponentów. Mówiąc bardziej precyzyjnie,
możemy podać lokalizację naszego komponentu w odniesieniu do
innych komponentów leżących na tym samym rodzicu bądź podać
lokalizację naszego komponentu w odniesieniu do samego rodzica. W
kolejnych przykładach rodzicem będzie układ RelativeLayout.
360
ATRYBUTY ODPOWIEDZIALNE ZA
POŁOŻENIE WZGLĘDEM RODZICA
• android:layout_alignParentBottom — dolna krawędź komponentu będzie przylegać do dolnej krawędzi
jego rodzica,

• android:layout_alignParentLeft — lewa krawędź komponentu będzie przylegać do lewej krawędzi jego


rodzica,

• android:layout_alignParentStart — początkowa krawędź komponentu będzie przylegać do początkowej


krawędzi jego rodzica,

• android:layout_alignParentRight — prawa krawędź komponentu będzie przylegać do prawej krawędzi jego


rodzica,

• android:layout_alignParentEnd — końcowa krawędź komponentu będzie przylegać do końcowej krawędzi


jego rodzica,
361
ATRYBUTY ODPOWIEDZIALNE ZA
POŁOŻENIE WZGLĘDEM RODZICA
• android:layout_alignParentTop — górna krawędź komponentu będzie przylegać do
górnej krawędzi jego rodzica,

• android:layout_centerHorizontal — wyśrodkowuje komponent poziomo


wewnątrz rodzica,

• android:layout_centerVertical — wyśrodkowuje komponent pionowo wewnątrz


rodzica,

• android:layout_centerInParent — wyśrodkowuje komponent (poziomo i pionowo)


wewnątrz rodzica.
362
ATRYBUTY ODPOWIEDZIALNE ZA
POŁOŻENIE WZGLĘDEM RODZICA
• Pierwsza uwaga dotyczy atrybutów android:layout_alignParentLeft i
android:layout_alignParentStart oraz android:layout_alignParentRight i
android:layout_alignParentEnd.

• Tak jak już mówiliśmy, wartości różnych atrybutów typu left są tożsame z wartościami
atrybutów typu start tylko w odniesieniu do tekstów pisanych od lewej
do prawej (czyli tak jak w języku polskim i innych językach zapisywanych alfabetem
łacińskim). Natomiast w przypadku języków, w których teksty pisane są od prawej do
lewej (np. języku arabskim czy hebrajskim), musimy zamiast atrybutu typu left użyć
atrybutu typu start. To samo dotyczy pary atrybutów typu right oraz end.
363
ATRYBUTY ODPOWIEDZIALNE ZA
POŁOŻENIE WZGLĘDEM RODZICA

• Drugą kwestią są wartości, które przyjmują te atrybuty. Każdy z nich


ma wartość logiczną true (prawda) lub false (fałsz). Domyślną
wartością jest false. Dlatego jeżeli chcemy dezaktywować dany
atrybut, najprościej jest go po prostu usunąć.

364
RELATIVE LAYOUT
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button 1"
android:id="@+id/button"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true" /> <!-- 1 -->
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button 2"
android:id="@+id/button2"
android:layout_centerInParent="true" /> <!-- 2 -->
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button 3"
android:id="@+id/button3"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true" /> <!-- 3 -->
</RelativeLayout>

365
RELATIVE LAYOUT

366
ATRYBUTY ODPOWIEDZIALNE ZA
POŁOŻENIE WZGLĘDEM SIEBIE
• android:layout_above — ustawia dolną krawędź komponentu powyżej wskazanego
komponentu,

• android:layout_alignBaseline — ustawia podstawową linię na wysokości podstawowej linii


wskazanego komponentu (dzięki temu teksty komponentów o różnej wielkości będą wyświetlane w
tym samym poziomie),

• android:layout_alignBottom — ustawia dolną krawędź komponentu na tej samej wysokości


co dolna krawędź wskazanego komponentu,

• android:layout_alignEnd — ustawia końcową krawędź komponentu w tej samej pozycji co


końcowa krawędź wskazanego komponentu,
367
ATRYBUTY ODPOWIEDZIALNE ZA
POŁOŻENIE WZGLĘDEM SIEBIE
• android:layout_alignLeft — ustawia lewą krawędź komponentu w tej samej pozycji
co lewa krawędź wskazanego komponentu,

• android:layout_alignRight — ustawia prawą krawędź komponentu w tej samej


pozycji co prawa krawędź wskazanego komponentu,

• android:layout_alignStart — ustawia początkową krawędź komponentu w tej samej


pozycji co początkowa krawędź wskazanego komponentu,

• android:layout_alignTop — ustawia górną krawędź komponentu na tej samej


wysokości co górna krawędź wskazanego komponentu,
368
ATRYBUTY ODPOWIEDZIALNE ZA
POŁOŻENIE WZGLĘDEM SIEBIE
• android:layout_below — ustawia górną krawędź komponentu poniżej wskazanego komponentu,

• android:layout_toEndOf — ustawia początkową krawędź komponentu w pozycji końcowej krawędzi


wskazanego komponentu,

• android:layout_toLeftOf — ustawia prawą krawędź komponentu w pozycji lewej krawędzi


wskazanego komponentu,

• android:layout_toRightOf — ustawia lewą krawędź komponentu w pozycji prawej krawędzi


wskazanego komponentu,

• android:layout_toStartOf — ustawia końcową krawędź komponentu w pozycji początkowej


krawędzi wskazanego komponentu.
369
GRID LAYOUT

370
GRID LAYOUT

• GridLayout to układ siatki podzielony niewidocznymi liniami na wiersze i kolumny.

• Siatka ta tworzy komórki (ang. cells), w których możemy umieszczać komponenty,


co daje nam więcej możliwości niż w układzie tabelarycznym (TableLayout).

• Ta opcja jest jednak dostępna dopiero od wersji Android 4.0.

• Układ GridLayout jest bardzo dobrze zintegrowany z edytorem gra cznym, dzięki
czemu w łatwy sposób można z niego korzystać.

371

fi
GRID LAYOUT

<?xml version="1.0" encoding="utf-8"?>


<GridLayout xmlns:android="http://schemas.android.com/apk/res/
android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</GridLayout>

372
GRID LAYOUT - PRZYKŁAD

373
GRID LAYOUT - PRZYKŁAD (XML)
<?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1"
android:id="@+id/button"
android:layout_row="0"
android:layout_column="0" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="2"
android:id="@+id/button2"
android:layout_row="0"
android:layout_column="1" />

374
GRID LAYOUT - PRZYKŁAD (XML)
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="3"
android:id="@+id/button3"
android:layout_row="0"
android:layout_column="2"
android:layout_rowSpan="2"
android:layout_gravity="center_vertical" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="4"
android:id="@+id/button4"
android:layout_row="1"
android:layout_column="0"
android:layout_columnSpan="2"
android:layout_gravity="center_horizontal" />
</GridLayout>

375
ZAGNIEŻDŻANIE UKŁADÓW

376
ZAGNIEŻDŻANIE UKŁADÓW

• Opisaliśmy już wszystkie układy wykorzystywane w aplikacjach dla


systemu Android. Ich ważną zaletą jest fakt, że możemy je w sobie
zagnieżdżać.

• Spróbujmy wykorzystać trzy układy: RelativeLayout,


TableLayout i LinearLayout.

377
ZAGNIEŻDŻANIE UKŁADÓW
• W pliku XML umieszczamy układ RelativeLayout, który będzie układem głównym.
Ustawiamy w nim atrybut android:gravity na wartość center_horizontal.
Dzięki temu pozostałe układy, które będą w nim zagnieżdżone, będą wyświetlane w
pozycji wyśrodkowywanej poziomo. Następnie w układzie RelativeLayout
umieszczamy układ TableLayout, a w nim cztery komponenty CheckBox. Po czym
dodajemy poniżej układ LinearLayout, a w nim dwa przyciski. Żeby zrobić nieco
odstępu pomiędzy układami (TableLayout i LinearLayout), użyliśmy atrybutów
android:layout_marginTop oraz android:layout_marginBottom.
De niujemy je w układzie TableLayout: pierwszy z wartością 10dp, a drugi 5dp.
378
fi
ZAGNIEŻDŻANIE UKŁADÓW

379
ZAGNIEŻDŻANIE UKŁADÓW (XML)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal">
<TableLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tableLayout"
android:layout_marginTop="10dp"
android:layout_marginBottom="5dp">
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent">
380
ZAGNIEŻDŻANIE UKŁADÓW (XML)
<CheckBox
android:text="Opcja 1"
android:id="@+id/checkBox"
android:layout_column="0"
android:checked="false" />
<CheckBox
android:text="Opcja 2"
android:id="@+id/checkBox2"
android:layout_column="1"
android:checked="false" />
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent">
<CheckBox
android:text="Opcja 3"
android:id="@+id/checkBox3"
android:layout_column="0"
android:checked="false" />
<CheckBox
android:text="Opcja 4"
android:id="@+id/checkBox4"
android:layout_column="1"
android:checked="false" />
</TableRow>

381
ZAGNIEŻDŻANIE UKŁADÓW (XML)
</TableLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tableLayout">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="OK"
android:id="@+id/button" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Anuluj"
android:id="@+id/button2" />
</LinearLayout>
</RelativeLayout>

382
KOMPONENT SCROLLVIEW

383
KOMPONENT SCROLLVIEW
• Komponent ScrollView jest kontenerem dla innych układów pozwalającym na przewijanie
ich zawartości, który przydaje się w sytuacji, kiedy rozmiar układu przekracza zyczną wielkość
naszego ekranu.

• Z technicznego punktu widzenia komponent ScrollView dziedziczy po układzie


FrameLayout, co oznacza, że jest on przeznaczony do wyświetlania jednego elementu
zajmującego cały jego obszar.

• Najczęściej wykorzystujemy go wraz z układem LinearLayout w orientacji pionowej


zawierającym elementy poukładane jeden pod drugim, dzięki czemu użytkownik może je
swobodnie przewijać.
384

fi
KOMPONENT SCROLLVIEW
• Nie powinniśmy go używać z komponentem ListView, który ma już własny
mechanizm przewijania zoptymalizowany pod kątem pracy z dużymi listami.

• Także komponent TextView jest wyposażony we własny mechanizm


przewijania i nie wymaga użycia dodatkowego elementu.

• Zaznaczmy jeszcze, że komponent ScrollView wspiera tylko przewijanie


pionowe, więc jeżeli chcemy mieć możliwość przewijania poziomego,
musimy użyć komponentu HorizontalScrollView.
385
KOMPONENT SCROLLVIEW
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Przycisk 1" />
<!-- Tutaj należy wstawić kilkanaście elementów, niekoniecznie przycisków-->
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Przycisk 20” />
</LinearLayout>
</ScrollView>

386
KOMPONENT SCROLLVIEW

387
KOMPONENT SCROLLVIEW

388
KOMPONENTY INTERFEJSU
UŻYTKOWNIKA

389
KOMPONENTY INTERFEJSU
UŻYTKOWNIKA
• Komponenty są bardzo istotnym elementem interfejsu użytkownika. To za ich pomocą
komunikuje się on z aplikacją, a aplikacja prezentuje mu informacje zwrotne.

• Wszystkie komponenty użytkownika dziedziczą po klasie View, co oznacza, że zajmują


prostokątny obszar ekranu i są odpowiedzialne za wyświetlanie jego zawartości oraz obsługę
zdarzeń. View jest klasą bazową dla kontrolek (ang. widgets), które są używane do tworzenia
interaktywnych komponentów interfejsu użytkownika (przyciski, pola tekstowe, edycyjne itp.).
Klasa ViewGroup (podklasa View) jest klasą bazową dla układów, które (jak już wiemy) są
niewidocznymi kontenerami, na których układamy inne komponenty typu View lub
ViewGroup. Oczywiście możemy tworzyć własne komponenty dziedziczące po klasie View
bądź po jej klasach pochodnych.
390
KATEGORIA TEXT

391
KATEGORIA BUTTONS

392
KATEGORIA WIDGETS

393
KATEGORIA CONTAINERS

394
KATEGORIA HELPERS

395
KATEGORIA GOOGLE

396
KATEGORIA LEGACY

397
STYLE I TEMATY

398
STYLE

• Idea stylów w systemie Android jest bardzo podobna do stylów CSS


wykorzystywanych w tworzeniu stron internetowych. De niujemy
tutaj jakiś zbiór atrybutów, z którego będą mogły korzystać używane
przez nas komponenty.

399

fi
STYLE

• Zanim jednak przejdziemy do omawiania stylów, przeanalizujmy


prosty przykład, w którym nasze komponenty ich nie wykorzystują.

• Załóżmy, że chcemy umieścić pole tekstowe (TextView) wraz z


atrybutami pokazanymi na kolejnym slajdzie

400
STYLE
<TextView
android:id="@+id/textView1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"
android:text="tekst1"
android:textColor="#434230"
android:background="#c6ecc6"
android:typeface="serif"
android:textSize="15sp"
android:textStyle="bold"
android:padding="10dp"
/>
401
STYLE
• Możemy to zrobić w sposób przedstawiony na poprzednim slajdzie i wszystko będzie
działać oraz wyglądać poprawnie. Jeśli jednak będziemy chcieli umieścić inne kontrolki
wykorzystujące takie same atrybuty, będziemy musieli je powielić w każdej z
kontrolek.

• Wydaje się, że to nic trudnego, bo wystarczy skopiować ten sam fragment i


powklejać go do pozostałych kontrolek. Problem pojawia się w sytuacji, kiedy chcemy
zmienić jeden z atrybutów, np. kolor tekstu (android:textColor). W takim wypadku
będziemy musieli przeprowadzić tę samą zmianę we wszystkich kontrolkach.

402
STYLE
• Jak się niedługo dowiemy, aplikacja może składać się z kilku plików XML, więc
przeglądanie ich wszystkich i szukanie kontrolek, które wymagają mody kacji,
okaże się bardzo czasochłonnym zadaniem.

• Stąd też w systemie Android mamy możliwość de niowania stylów. Dzięki nim w
jednym miejscu określimy wszystkie wymagane atrybuty, z których będą korzystały
nasze kontrolki. Jeżeli zaistnieje potrzeba dokonania jakiejś zmiany, to wystarczy
wprowadzić ją w jednym pliku (tam, gdzie zde niowaliśmy dany styl). Kod kontrolki
TextView wykorzystującej style będzie wyglądał jak na kolejnym slajdzie.
403
fi
fi
fi
STYLE

<TextView
android:id="@+id/textView1"
style="@style/MyStyle"
android:text="tekst"
/>

404
STYLE
<resources>
<style name="MyStyle">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textColor">#434230</item>
<item name="android:background">#c6ecc6</item>
<item name="android:typeface">serif</item>
<item name="android:textSize">15sp</item>
<item name="android:textStyle">bold</item>
<item name="android:padding">10dp</item>
</style>
</resources>
405
STYLE - WYJAŚNIENIE WŁAŚCIWOŚCI
• android:textColor — kolor tekstu,

• android:background — kolor tła,

• android:typeface — krój pisma, z czego do wyboru mamy:

• normal — zwykłą czcionkę,

• serif — czcionkę szeryfową (z ozdobnikami w postaci poprzecznie lub ukośnie zakończonych głównych
kresek liter danego kroju pisma),

• sans — czcionkę bezszeryfową (bez ozdobników),

• monospace — czcionkę o stałej szerokości znaków.


406
STYLE - WYJAŚNIENIE WŁAŚCIWOŚCI

• android:textStyle — odmiana pisma, z czego do wyboru mamy:

• normal — tekst zwykły,

• bold — tekst pogrubiony,

• italic — tekst pochylony (kursywę).

407
DZIEDZICZENIE STYLÓW

• Do tej pory poznaliśmy proste style, które tworzą zamknięty zbiór


zde niowanych atrybutów. Natomiast w przypadku bardziej
skomplikowanych aplikacji przy de niowaniu nowych stylów
będziemy wykorzystywać te zde niowane wcześniej. Nazywa się to
dziedziczeniem stylów. Sam mechanizm dziedziczenia jest dobrze
znany wszystkim programistom.

408
fi
fi
fi
DZIEDZICZENIE STYLÓW
• Tworząc nowy styl, nie musimy od nowa de niować wszystkich atrybutów, może
skorzystać ze stylu zde niowanego wcześniej i dodać do niego tylko nowe elementy.

• Dzięki temu unikniemy niepotrzebnego powtarzania (często obszernych) fragmentów


kodu.

• Dodatkowo będziemy mieli spójną i przejrzystą hierarchię stylów, która ułatwi nam
pisanie kodu i wprowadzanie wszelkich mody kacji.

• Style, które będziemy tworzyć, mogą dziedziczyć po naszych własnych stylach (wcześniej
już zde niowanych) lub też po stylach zde niowanych w pakiecie Android SDK.
409
fi
fi
fi
fi
fi
DZIEDZICZENIE STYLÓW
<style name="MyStyle">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textColor">#434230</item>
<item name="android:background">#c6ecc6</item>
<item name="android:typeface">serif</item>
<item name="android:textSize">15sp</item>
<item name="android:textStyle">bold</item>
<item name="android:padding">10dp</item>
</style>
<style name="MyStyle.BlueCursive">
<item name="android:textColor">#0000ff</item>
<item name="android:textStyle">italic</item>
</style>
410
DZIEDZICZENIE STYLÓW

<style name="MyStyle.BlueCursive.Small">
<item name="android:textSize">10sp</item>
</style>

411
KORZYSTANIE Z DZIEDZICZĄCEGO
STYLU

<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/MyStyle.BlueCursive.Small"
android:text="tekst2"
/>

412
DZIEDZICZENIE STYLÓW - UŻYCIE
„PARENT”
<style name="MyStyle">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textColor">#434230</item>
<item name="android:background">#c6ecc6</item>
<item name="android:typeface">serif</item>
<item name="android:textSize">15sp</item>
<item name="android:textStyle">bold</item>
<item name="android:padding">10dp</item>
</style>
<style name="BlueCursive" parent="MyStyle">
<item name="android:textColor">#0000ff</item>
<item name="android:textStyle">italic</item>
</style>
<style name="Small" parent="BlueCursive">
<item name="android:textSize">10sp</item>
</style>

413
DZIEDZICZENIE STYLÓW - UŻYCIE
„PARENT”

• W przypadku dziedziczenia własnych stylów możemy stosować


zarówno notację z kropką, jak i atrybut parent. Natomiast na
dziedziczenie po stylach wbudowanych w platformę Android SDK
pozwala tylko atrybut parent (notacja z kropką nie będzie działać).

414
STYLE
• Kiedy poznaliśmy już metody tworzenia stylów oraz mechanizm dziedziczenia, pojawia
się pytanie, skąd mamy wiedzieć, jakie atrybuty możemy w danym stylu zde niować?

• Żeby rozstrzygnąć ten problem, musimy najpierw odpowiedzieć sobie na pytanie, do


której kontrolki (bądź zestawu kontrolek) będziemy stosować dany styl.

• Jeżeli będzie to na przykład kontrolka TextView, to wystarczy w dokumentacji technicznej


sprawdzić, jakie atrybuty są dla niej dostępne.

• Jeżeli jednak zdarzy nam się, że w de nicji naszego stylu użyliśmy atrybutu, którego dana
kontrolka nie obsługuje, to ten atrybut zostanie po prostu zignorowany.
415
fi
fi
STYLE
• Istnieją jednak takie atrybuty stylów, które nie są obsługiwane przez żadną kontrolkę i
mogą być stosowane tylko do tematów (ang. themes). Właściwości te dotyczą całego
okna aplikacji, a nie żadnej konkretnej kontrolki. Przykładem tego typu właściwości są
m.in.: ukrywanie tytułu aplikacji, ukrywanie pasku stanu i zmiana tła okna.

• Istnieje prosty sposób, w jaki możemy odróżnić style stosowane do tematów od


stylów przeznaczonych dla kontrolek. Te pierwsze są poprzedzone pre ksem window.
Przykładem mogą tu być takie atrybuty, jak windowNoTitle (określa, czy tytuł okna
będzie wyświetlany), windowTitleSize (określa wysokość paska tytułowego okna) czy
windowBackground (określa tło okna).
416

fi
TEMATY

417
TEMATY

• Temat (ang. theme) jest stylem stosownym do danej aktywności (ang.


Activity) lub aplikacji.

• Sposób, w jaki będziemy de niować tematy, jest identyczny jak w


przypadku stylów, które stosowaliśmy do naszych kontrolek (plik res/
values/themes.xml)

418
fi
PRZYKŁAD TEMATU

<!-- Base application theme. -->


<style name="Base.Theme.MyApplication"
parent="Theme.Material3.DayNight.NoActionBar">
<item name="android:windowFullscreen">true</item>
<item name="android:colorBackground">@color/green</item>
</style>

419
PRZYKŁAD TEMATU
• Zwróćmy uwagę na nazwę naszego tematu oraz na temat bazowy.

• Nazwa to Base.Theme.MyApplication, a temat bazowy, po którym dziedziczymy, to


Theme.Material3.DayNight.NoActionBar.

• Do jego podstawowej de nicji dodaliśmy dwa atrybuty.

• Pierwszy to android:windowFullscreen o wartości true, która pozwala na ustawienie aplikacji


w trybie pełnoekranowym (aplikacja zajmie cały dostępny obszar ekranu).

• Drugi atrybut to android:colorBackground, który już poznaliśmy, ustawia on tło naszej aplikacji.
Oczywiście w pliku colors.xml należy wcześniej zde niować wartość koloru o nazwie green.

420
fi
fi
GDZIE SZUKAĆ JAKI TEMAT JEST
USTAWIONY?
<?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.MyApplication"
tools:targetApi="31">
<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>

421
OBRAZY TYPU NINE-PATCH
• Obrazy typu nine-patch (ang. dziewięć łatek) są specjalnymi,
rozciągalnymi bitmapami, które system Android potra w ładny
sposób wyświetlać.

• Urządzenia pracujące pod kontrolą systemu Android mają różne


rozdzielczości, rozmiary oraz gęstości pikseli. Dlatego uruchomione
na nich aplikacje będą wyskalowane w różny sposób, co może
powodować rozciąganie obrazów i znaczne pogorszenie ich wyglądu.
422

fi
OBRAZY TYPU NINE-PATCH

• Z tego powodu powstała technologia


obsługi obrazów znana jako nine-
patch. Polega ona na tym, że obraz
jest dzielony na dziewięć części
(może ich też być więcej).

423
OBRAZY TYPU NINE-PATCH
• Obszary narożne, oznaczone cyfrą 1, nie są skalowane, co oznacza, że zawsze wyglądają
tak samo. Obszary oznaczone cyfrą 2 mogą być skalowane tylko w poziomie, a obszary
oznaczone cyfrą 3 tylko w pionie. Obszar środkowy, oznaczony cyfrą 4, jest skalowany
zarówno w pionie, jak i poziomie. Podsumowując, w obszarach oznaczonych cyfrą 1
umieszczamy elementy, które nie powinny być skalowane, żeby zawsze wyglądać tak
samo (np. zaokrąglone narożniki przycisku lub małe ikony). Natomiast w obszarze 4
możemy umieszczać elementy, które wyglądają dobrze w każdym rozmiarze (np.
jednolity kolor). W obszarach oznaczonych cyframi 2 i 3 umieszczamy takie elementy,
które dobrze się skalują w jednym wymiarze (poziomo lub pionowo).

424
OBRAZY TYPU NINE-PATCH
• Technicznie plik obrazu, który wykorzystuje technologię nine-patch,
różni się od zwykłego obrazu tylko dwoma rzeczami. Pierwsza to
nazwa pliku, która ma postać <nazwa obrazka>.9.png (zwykła
nazwa pliku to <nazwa obrazka>.png), druga to ramka
otaczająca nasz obraz o szerokości 1 piksela.

• Obraz tego typu z łatwością przygotujemy w narzędziu dostarczanym


wraz z pakietem Android Studio.
425
OBRAZY TYPU NINE-PATCH

426
OBRAZY TYPU NINE-PATCH

• Dokumentacja: https://developer.android.com/studio/write/
draw9patch

427
SELEKTORY
• Selektory (ang. selectors) to prosta, ale bardzo użyteczna konstrukcja pozwalająca
dostosować wygląd komponentu w zależności od stanu, w jakim się znajduje.

• Rozważmy przykład przycisku (ang. button), który będzie inaczej wyglądał w


zależności od tego, czy w danym momencie jest wciśnięty, niewciśnięty (w stanie
normalnym) lub przejął skupienie (ang. focus).

• Kolejny przykład z będzie dotyczył zwykłego przycisku (Button) i zmiany koloru


jego tła. W tym celu najpierw tworzymy plik XML, w którym de niujemy selektor.
428

fi
SELEKTORY
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/
android">
<item android:state_pressed="true">
<color android:color="#FF0000" /> <!-- pressed -->
</item>
<item android:state_focused="true">
<color android:color="#00FF00" /> <!-- focused -->
</item>
<item>
<color android:color="#0000FF" /> <!-- default -->
</item>
</selector>
429
SELEKTORY

430
SELEKTORY

431
SELEKTORY

432
SELEKTORY
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/
android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/main">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Przycisk"
android:id="@+id/button"
android:background="@drawable/my_button" />
</LinearLayout>
433
SELEKTORY

• Uwaga! Aby selektory działały poprawnie w


przypadku kolorów przycisków należy dziedziczyć
motyw po innym niż Material!

434
SELEKTORY

<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="MyApplication" parent="Theme.AppCompat">>
<item name="android:colorBackground">@color/white</item>
</style>
</resources>

435
SELEKTORY

436
DOSTĘPNE STANY DLA SELEKTORÓW
• android:state_pressed — kontrolka jest wciśnięta,

• android:state_focused — kontrolka przejęła skupienie (ang. focus),

• android:state_selected — zostaje wybrana pozycja z listy,

• android:state_checkable — kontrolka może zmienić swój stan (np. CheckBox),

• android:state_checked — kontrolka (np. Checkbox) zmieniła swój stan na zaznaczony,

• android:state_enabled — kontrolka jest włączona (ang. enabled),

• android:state_activated — kontrolka (np. Checkbox) lub jej rodzic zmienili swój stan na zaznaczony,

• android:state_window_focused — okno kontrolki przejęło skupienie (ang. focus).


437
KSZTAŁTY

• Kształt (ang. shape) to kolejny znacznik, który pozwoli nam za


pomocą odpowiednich wpisów w pliku XML uatrakcyjnić wygląd
naszej aplikacji. Dzięki znacznikowi <shape> uzyskamy wiele
ciekawych efektów, ale żeby dobrze zrozumieć jego działanie,
spójrzmy na jego de nicję.

438
fi
KSZTAŁTY
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape=["rectangle" | "oval" | "line" | "ring"] >
<corners
android:radius="integer"
android:topLeftRadius="integer"
android:topRightRadius="integer"
android:bottomLeftRadius="integer"
android:bottomRightRadius="integer" />
<gradient
android:angle="integer"
android:centerX="float"
android:centerY="float"
android:centerColor="integer"
android:endColor="color"
android:gradientRadius="integer"
android:startColor="color"
android:type=["linear" | "radial" | "sweep"]
android:useLevel=["true" | "false"] />
<padding
android:left="integer"
android:top="integer"
android:right="integer"
android:bottom="integer" />
<size
android:width="integer"
android:height="integer" />
<solid
android:color="color" />
<stroke
android:width="integer"
android:color="color"
android:dashWidth="integer"
android:dashGap="integer" />
</shape>

439
KSZTAŁTY
• Opiszmy teraz po kolei wszystkie dostępne opcje. Pierwszy istotny element w znaczniku
<shape> to atrybut android:shape. Jak widzimy, może on przyjąć cztery wartości:

• rectangle — kształt prostokątny (opcja domyślna) wypełniający cały dostępny obszar


kontrolki;

• oval — kształt owalny dopasowujący się do rozmiarów kontrolki;

• line — linia biegnąca poziomo przez środek kontrolki; wartość ta wymaga znacznika
<stroke> do zde niowania szerokości linii;

• ring — kształt pierścienia.


440
fi
KSZTAŁTY
• Wartość ring może wykorzystywać jeszcze dodatkowe opcje:

• android:innerRadius — promień wewnętrznej części pierścienia (środek pierścienia pokrywa się ze środkiem kontrolki).

• android:innerRadiusRatio — promień wewnętrznej części pierścienia wyrażony jako stosunek szerokości pierścienia. Na
przykład jeżeli ustawimy android:innerRadiusRatio="7", to promień będzie równy szerokości pierścienia podzielonej przez 7.
Wartość ta jest nadpisywana przez android:innerRadius.

• android:thickness — grubość pierścienia.

• android:thicknessRatio — grubość pierścienia wyrażona jako stosunek szerokości pierścienia. Na przykład jeżeli
android:thicknessRatio="2", wtedy grubość pierścienia równa jest szerokości pierścienia podzielonej przez 2.

• android:useLevel — ustawiamy wartość true, jeżeli pierścień jest używany jako LevelListDrawable (zasób, który zarządza
grupą obiektów gra cznych). We wszystkich innych sytuacjach powinniśmy ustawić tę wartość jako false, inaczej nasz pierścień
się nie pojawi!

441
fi
KSZTAŁTY
• Kolejny przydatny znacznik to <corners>. Dzięki niemu możemy tworzyć prostokąty z zaokrąglonymi rogami.
Stąd też występuje tylko z kształtem o wartości rectangle (pol. prostokąt). Atrybuty, które możemy wraz z nim
wykorzystać, to:

• android:radius — promień dla wszystkich narożników wartość ta jest nadpisywana przez szczegółowe
ustawienia poszczególnych z nich;

• android:topLeftRadius — promień lewego górnego narożnika;

• android:topRightRadius — promień prawego górnego narożnika;

• android:bottomLeftRadius — promień lewego dolnego narożnika;

• android:bottomRightRadius — promień prawego dolnego narożnika.


442
KSZTAŁTY
• Następny znacznik to <gradient>, pozwala on na realizację przejścia tonalnego pomiędzy (co najmniej) dwoma kolorami.
Są z nim skojarzone następujące atrybuty:

• android:angle — kąt określający kierunek przejścia tonalnego. Wartość 0 (domyślna) oznacza kierunek od lewej do
prawej, zaś 90 kierunek z dołu do góry, przy czym każda przypisana wartość musi być wielokrotnością liczby 45.

• android:centerX — względna współrzędna X wyznaczająca środek gradientu. Wartość ta musi mieścić się w
przedziale [0, 1].

• android:centerY — względna współrzędna Y wyznaczająca środek gradientu. Wartość ta musi mieścić się w
przedziale [0, 1].

• android:centerColor — opcjonalny kolor, który jest kolorem pośrednim pomiędzy początkowym a końcowym.

• android:endColor — końcowy kolor gradientu.


443
KSZTAŁTY
• android:gradientRadius — promień gradientu. Ma on zastosowanie tylko wtedy, gdy atrybut android:type ustawiony
jest na wartość radial.

• android:startColor — początkowy kolor gradientu.

• android:type — typ gradientu z kilkoma dostępnymi opcjami:

• linear — gradient liniowy (wartość domyślna);

• radial — gradient promieniowy (radialny), kolor początkowy znajduje się w środku okręgu;

• sweep — kierunek gradientu wyznaczony jest przez wskazówkę zegara.

• android:useLevel — ustawiamy wartość true, jeżeli gradient używany jest jako LevelListDrawable (zasób, który
zarządza grupą obiektów gra cznych). We wszystkich innych sytuacjach powinniśmy użyć wartości false.
444
fi
KSZTAŁTY
• Kolejny atrybut to <padding>, czyli margines wewnętrzny. Wyznacza on pozycję
zawartości kontrolki (np. tekstu na przycisku), a nie pozycję kształtu. Atrybuty dostępne
wraz ze znacznikiem <padding> to:

• android:left — margines wewnętrzny lewy,

• android:top — margines wewnętrzny górny,

• android:right — margines wewnętrzny prawy,

• android:bottom — margines wewnętrzny dolny.


445
KSZTAŁTY
• Atrybut <size> de niuje rozmiar kształtu. Wraz z nim dostajemy dwa
następujące atrybuty:

• android:height — wysokość kształtu,

• android:width — szerokość kształtu.

• Rozmiar kontrolki będzie wyskalowany zgodnie z powyższymi wartościami.


Dlatego kiedy używamy kontrolki ImageView i chcemy zablokować skalowanie,
musimy ustawić atrybut android:scaleType na wartość center.
446
fi
KSZTAŁTY
• Atrybut <solid> ustawia jednolity kolor kształtu. Ma on tylko jedną opcję, a mianowicie android:color, w której podajemy
wartość koloru.

• Ostatni z omawianych znaczników to <stroke>, który rysuje ramkę otaczającą kontrolkę. Do dyspozycji mamy cztery
atrybuty:

• android:width — grubość ramki,

• android:color — kolor ramki,

• android:dashGap — odległość pomiędzy kreskami (w ramce rysowanej linią przerywaną) wykorzystywaną wraz z
atrybutem android:dashWidth,

• android: dashWidth — długość kresek (w ramce rysowanej linią przerywaną) wykorzystywaną wraz z atrybutem
dashGap.

447
PRZYKŁAD

• Omówiliśmy wszystkie elementy dostępne dla znacznika <shape>.


Pora na przykład, który podsumuje zdobytą przez nas wiedzę.

• Naszym celem jest utworzenie przycisku z gradientowym tłem, które


będzie przechodziło w jednolity kolor w momencie wciśnięcia
przycisku.

448
PRZYKŁAD
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="StylPrzycisku">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textColor">#ffffff</item>
<item name="android:gravity">center</item>
<item name="android:layout_margin">10dp</item>
<item name="android:textSize">25sp</item>
<item name="android:textStyle">bold</item>
<item name="android:shadowColor">#0a0a0a</item>
<item name="android:shadowDx">-2</item>
<item name="android:shadowDy">-2</item>
<item name="android:shadowRadius">1</item>
</style>
</resources>
449
PRZYKŁAD
• Opiszmy pokrótce wykorzystane przez nas atrybuty:

• android:layout_width (o wartości match_parent) — ustala szerokość komponentu na całą szerokość


rodzica,

• android:layout_height (o wartości wrap_content) — ustala wysokość komponentu zgodnie z jego


zawartością (np. dla przycisku będzie to rozmiar tekstu),

• android:textColor (o wartości #ffffff) — ustawia kolor tekstu na biały,

• android:gravity (o wartości center) — ustawia tekst na środku przycisku,

• android:layout_margin (o wartości 10dp) — ustawia marginesy (zewnętrzne) na 10dp,


450
PRZYKŁAD
• android:textSize (o wartości 25sp) — ustawia rozmiar tekstu na 25sp,

• android:textStyle (o wartości bold) — ustawia styl tekstu na pogrubiony,

• android:shadowColor (o wartości #0a0a0a) — ustawia kolor cieni tekstu,

• android:shadowDx (o wartości -2) — określa pozycję cienia w kierunku poziomym, wartość


ujemna oznacza przesunięcie w lewo (dodatnia w prawo);

• android:shadowDy (o wartości -2) — określa pozycję cienia w kierunku pionowym, wartość ujemna
oznacza przesunięcie w górę (dodatnia w dół);

• android:shadowRadius (o wartości 1) — określa promień cienia.


451
PRZYKŁAD
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" > <!-- stan wciśnięty -->
<shape>
<solid android:color="#52a4ef" />
<stroke
android:width="2dp"
android:color="#245684" />
<corners
android:radius="5dp" />
<padding
android:left="12dp"
android:top="12dp"
android:right="12dp"
android:bottom="12dp" />
</shape>
</item>
<item> <!-- stan domyślny -->
<shape>
<gradient
android:startColor="#52a4ef"
android:endColor="#245684"
android:angle="45" />
<stroke
android:width="2dp"
android:color="#245684" />
<corners
android:radius="5dp" />
<padding
android:left="12dp"
android:top="12dp"
android:right="12dp"
android:bottom="12dp" />
</shape>
</item>
</selector>

452
PRZYKŁAD
• Opiszmy pokrótce użyte przez nas atrybuty:

• <selector> — pozwala na zmianę wyglądu przycisku w zależności od stanu, w jakim się znajduje; w naszym przykładzie mamy opisane dwa
stany: atrybut android:state_pressed oznaczający przycisk wciśnięty oraz brak atrybutu w znaczniku <item> oznaczający stan domyślny
(normalny);

• <shape> — nadaje odpowiedni kształt naszemu komponentowi, a brak wartości oznacza domyślny prostokątny kształt; kolor de niujemy za
pomocą znacznika <solid> i atrybutu android:color;

• <stroke> — określa obramowanie komponentu; atrybut android:width ustawia grubość ramki, a atrybut android:color jej kolor;

• <corners> — wprowadza zaokrąglone rogi, promień zaokrągleń de niuje atrybut android:radius;

• <padding> — ustawia poszczególne marginesy wewnętrzne dzięki atrybutom android:left (lewy), android:top (górny), android:right (prawy),
android:bottom (dolny);

• <gradient> — ustawia przejście tonalne pomiędzy kolorem początkowym (atrybut android:startColor) a kolorem końcowym (atrybut
android:endColor), kąt przejścia de niujemy dzięki atrybutowi android:angle.

453
fi
fi
fi
PRZYKŁAD

454
PRZYKŁAD

455
PRZYKŁAD

456
PRZYKŁAD

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/
android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/main">
<Button
android:text="OK"
style="@style/StylPrzycisku"
android:background="@drawable/gradient" />
</LinearLayout>

457
PRZYKŁAD

<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="MyApplication" parent="Theme.AppCompat">>
<item name="android:colorBackground">@color/white</item>
</style>
</resources>

458
PRZYKŁAD

459
AKTYWNOŚCI I FRAGMENTY

460
AKTYWNOŚCI

461
AKTYWNOŚCI
• Aktywność (ang. activity) to jeden z najważniejszych komponentów w aplikacjach systemu
Android.

• Najprostszą drogą to zrozumienia aktywności jest utożsamianie jej z pojedynczym


ekranem naszej aplikacji.

• Tak więc aplikacja najczęściej składa się z jednej bądź kilku aktywności, z których będą
korzystali użytkownicy.

• Prawie wszystkie aktywności wchodzą w interakcję z użytkownikiem, dlatego to one


odpowiadają za utworzenie okna, w którym umieszczone będą różne elementy interfejsu.
462
AKTYWNOŚCI
• Aktywność od momentu uruchomienia do czasu jej ukrycia przechodzi przez kilka
różnych stanów zwanych cyklem życia (ang. life cycle) aktywności. Zrozumienie tej
koncepcji jest podstawą, jeżeli chcemy pisać wydajne i poprawnie działające aplikacje.

• Idea ta wynika z faktu, że system Android zarządza całą dostępną pamięcią. Jeżeli
będzie jej potrzebował więcej, to może niektóre (ukryte) aktywności naszej aplikacji
usunąć z pamięci. Będzie to skutkowało tym, że jeżeli się odpowiednio to tego nie
przygotujemy, możemy utracić część istotnych danych. Dlatego też musimy dobrze
zrozumieć tę koncepcję.
463
CYKL ŻYCIA AKTYWNOŚCI

464
CYKL ŻYCIA AKTYWNOŚCI
• Na pierwszy rzut oka widzimy, że schemat jest dość skomplikowany. Postaram się
jednak wszystko dokładnie wyjaśnić. Na samej górze mamy uruchomienie
aktywności. Pierwsza metoda, która zostanie wywołana, to onCreate(). To tutaj
powinniśmy dokonać wszystkich statycznych ustawień dotyczących aktywności (np.
tworzenia kontrolek, podpinania danych do listy). W metodzie tej mamy dostępny
obiekt typu Bundle, który przechowuje poprzedni stan aktywności (jeżeli taki
wystąpił). Tutaj także możemy zakończyć aktywność za pomocą metody nish(). W
takiej sytuacji zostanie wywołana metoda onDestroy(), a cały cykl życia aktywności
zostanie pominięty (onStart(), onResume(), onPause(), onStop()).
465

fi
CYKL ŻYCIA AKTYWNOŚCI

• Metoda onStart() wywoływana jest w momencie, kiedy aktywność


staje się widoczna dla użytkownika, i zawsze występuje po metodzie
onCreate() lub onRestart(). Metoda onRestart()jest wywoływana w
sytuacji, gdy aktywność została wcześniej zatrzymana, a teraz
ponownie ją wyświetlamy.

466
CYKL ŻYCIA AKTYWNOŚCI

• Następnie, gdy aktywność jest gotowa do rozpoczęcia interakcji z


użytkownikiem, zostanie uruchomiona metoda onResume(), która jest
w tym momencie na samej górze stosu aktywności (przykrywa
wszystkie inne). Metoda onResume() to odpowiednie miejsce np. na
rozpoczęcie animacji czy włączenie urządzeń wymagających
wyłączności (aparatu itp.).

467
CYKL ŻYCIA AKTYWNOŚCI
• Kolejna metoda w cyklu życia aktywności to onPause(). Wywołuje się ją, kiedy inna aktywność
przykrywa naszą. Na przykład jeżeli aktywność B jest uruchomiona na przodzie aktywności A,
to zostanie dla niej wywołana metoda onPause(). Dopóki nie zakończy się działanie tej
metody, dopóty aktywność B nie zostanie uruchomiona. Stąd też nie powinniśmy w tej
metodzie wykonywać żadnych długich operacji. Metoda onPause() jest najczęściej
wykorzystywana do zapisywania danych, zatrzymywania działających animacji (czy innych
elementów nadmiernie obciążających procesor), zwalniania zasobów (szczególnie tych, które
wymagają wyłącznego dostępu, np. aparatu). Zapisywanie danych wprowadzonych przez
użytkownika jest tutaj niezwykle istotne, gdyż system może w tym stanie zakończyć istnienie
metody (ang. kill), jeżeli będzie potrzebował dodatkowych zasobów.

468
CYKL ŻYCIA AKTYWNOŚCI

• Kiedy nasza aktywność staje się całkowicie niewidoczna dla


użytkownika, wywoływana jest metoda onStop(). Może się to zdarzyć
w sytuacji, gdy zostaje uruchomiona nowa aktywność, wracamy do
poprzedniej aktywności lub aktywność zostaje zamknięta.

469
CYKL ŻYCIA AKTYWNOŚCI
• Ostatnia metoda, jaka zostanie wywołana przed całkowitym zniszczeniem aktywności, to
onDestroy(). Może to nastąpić po wywołaniu metody nish(), albo kiedy system operacyjny
tymczasowo zniszczy aktywność, aby odzyskać pamięć. Miejmy na uwadze, że zgodnie ze
schematem metoda ta nie musi zostać wykonana.

• W sytuacji bardzo niskiego poziomu zasobów system może (po metodzie onPause())
całkowicie zakończyć działanie aplikacji. Dlatego też onDestroy()nie służy do zapisywania
danych (należy to robić w metodzie onPause()). Tutaj natomiast powinniśmy zwolnić zasoby
takie jak wątki związane z daną aktywnością, które nie są potrzebne w innych aktywnościach
naszej aplikacji. W tym przypadku nie ma obaw, że metoda nie zostanie wykonana (gdy system
zamknie aplikację), bo wraz z zamknięciem aplikacji wszystkie jej zasoby zostaną zwolnione.
470
fi
CYKL ŻYCIA AKTYWNOŚCI

• Ostatnia metoda, której jeszcze nie omówiliśmy, to onRestart().


Zostanie ona wywołana w sytuacji, gdy użytkownik będzie chciał
ponownie przejść do aktywności, która wcześniej stała się dla niego
niewidoczna. Jak widzimy na schemacie, jest ona wywoływana po
metodzie onStop(), ale przed metodą onStart().

471
CYKL ŻYCIA AKTYWNOŚCI
• Zwróćmy uwagę na trzy istotne pętle widoczne na schemacie:

• Cały okres życia aktywności — rozciąga się od metody


onCreate() do metody onDestroy(). Aktywność realizuje ustawienie
wszystkich globalnych stanów w metodzie onCreate(), a zwalnia
wszystkie pozostałe zasoby w metodzie onDestroy(). Jeśli na przykład
wątek (uruchomiony w tle) pobiera jakieś dane z sieci, możemy go
utworzyć w metodzie onCreate(), a zatrzymać w onDestroy().
472
CYKL ŻYCIA AKTYWNOŚCI
• Zwróćmy uwagę na trzy istotne pętle widoczne na schemacie:

• Widoczny okres aktywności — rozciąga się od metody


onStart() do metody onStop(). Przez ten czas użytkownik widzi
aktywność, choć niekoniecznie na pierwszym planie (ang.
foreground), nie musi też wchodzić z nią w interakcję. Metody
onStart() i onStop() mogą być wywoływane wielokrotnie (gdy
aktywność staję się niewidoczna, a później znowu się pokazuje).
473
CYKL ŻYCIA AKTYWNOŚCI
• Zwróćmy uwagę na trzy istotne pętle widoczne na schemacie:

• Pierwszoplanowy okres aktywności — rozciąga się od metody


onResume() do metody onPause(). W tym okresie aplikacja jest cały
czas widoczna i pozostaje na pierwszym planie (nie jest przesłonięta inną
aktywnością). Może bardzo często przechodzić pomiędzy stanami Resume
a Stop. Skutkuje to tym, że obie metody będą dość często wywoływane.
Dlatego należy zadbać, aby zawarty w nich kod był wykonywany możliwie
szybko.
474
CYKL ŻYCIA AKTYWNOŚCI
• Na koniec przypomnijmy jeszcze stany, w których może się znaleźć nasza aktywność:

• stan aktywny (ang. active) — aktywność jest na pierwszym planie (na górze stosu aktywności);

• stan wstrzymania (ang. pause) — aktywność straciła skupienie (ang. focus), ale jest cały czas (choćby częściowo)
widoczna, zachowuje też swój stan oraz dane wszystkich kontrolek i jest przypięta do menedżera okien (ang. window
manager), jednakże w przypadku ekstremalnie niskiego poziomu zasobów może być przez system zamknięta;

• stan zatrzymania (ang. stop) — aktywność jest całkowicie niewidoczna, ale zachowuje swój stan oraz dane
wszystkich kontrolek, może być dość często zamykana przez system w celu odzyskania wykorzystywanej przez nią pamięci;

• stan zniszczenia (ang. destroy) — aktywność może zostać zakończona przez użytkownika (np. metodą nish()) lub
przez system operacyjny, jeżeli ponownie ją uruchomimy, musi na nowo zostać utworzona i powrócić do swojego
poprzedniego stanu.

475

fi
AKTYWNOŚCI - PRZYKŁAD
package edu.zsk.myapplication;

import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {


String tag = "my_custom_events";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(tag, "onCreate");
}
476
AKTYWNOŚCI - PRZYKŁAD
@Override
public void onStart()
{
super.onStart();
Log.d(tag, "onStart()");
}

@Override
public void onRestart()
{
super.onRestart();
Log.d(tag, "onRestart()");
}
477
AKTYWNOŚCI - PRZYKŁAD
@Override
public void onResume()
{
super.onResume();
Log.d(tag, "onResume()");
}

@Override
public void onPause()
{
super.onPause();
Log.d(tag, "onPause()");
}
478
AKTYWNOŚCI - PRZYKŁAD
@Override
public void onStop()
{
super.onStop();
Log.d(tag, "onStop()");
}

@Override
public void onDestroy()
{
super.onDestroy();
Log.d(tag, "onDestroy()");
}

479
AKTYWNOŚCI - PRZYKŁAD

480
AKTYWNOŚCI - PRZYKŁAD

481
OKNA DIALOGOWE

482
OKNA DIALOGOWE POSTĘPU
• Klasyczne okno dialogowe służy do prezentowania użytkownikowi
informacji i pozyskiwania od niego odpowiedzi. Najpierw pokażemy
jednak okna dialogowe postępu używane do wyświetlania
użytkownikowi informacji o tym, jak zajęta jest aplikacja.

• Pierwsze z nich będzie prostym oknem postępu w formie


obracającego się fragmentu okręgu. Nie pokazuje ono jednak stopnia
postępu, a jedynie informuje o tym, że aplikacja jest zajęta.
483
OKNA DIALOGOWE POSTĘPU
package edu.zsk.myapplication;

import android.app.ProgressDialog;
import android.os.Bundle;
import android.view.View;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void DialogWindow(View view) {
final ProgressDialog dialog = ProgressDialog.show(this,
"Realizuję zadanie", "Proszę czekać...");
new Thread(new Runnable(){
public void run(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
dialog.dismiss();
}
}).start();
}
}

484
OKNA DIALOGOWE POSTĘPU
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/
android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Oblicz"
android:id="@+id/button"
android:onClick="DialogWindow" />
</LinearLayout>

485
OKNA DIALOGOWE POSTĘPU

486
OKNA DIALOGOWE POSTĘPU
public void DialogWindow(View view) {
final ProgressDialog progressDialog = new ProgressDialog(this);
progressDialog.setCancelable(false);
progressDialog.setIcon(R.mipmap.ic_launcher);
progressDialog.setTitle("Pobieram dane...");
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setButton(DialogInterface.BUTTON_POSITIVE, "OK",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Toast.makeText(getBaseContext(),"Kliknięto OK",
Toast.LENGTH_SHORT).show();
}
});
progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE,
"Anuluj",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int which)
{
Toast.makeText(getBaseContext(),
"Kliknięto Anuluj",
Toast.LENGTH_SHORT).show();
}
});
progressDialog.show();
new Thread(new Runnable(){
public void run(){
for (int i=1; i<=10; i++) {
try {
Thread.sleep(1500);
progressDialog.incrementProgressBy(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
progressDialog.dismiss();
}
}).start();
}

487
OKNA DIALOGOWE POSTĘPU
public void DialogWindow(View view) {
final ProgressDialog progressDialog = new ProgressDialog(this);
progressDialog.setCancelable(false);
progressDialog.setIcon(R.mipmap.ic_launcher);
progressDialog.setTitle("Pobieram dane...");
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setButton(DialogInterface.BUTTON_POSITIVE, "OK",
(dialogInterface, i) -> Toast.makeText(getBaseContext(),"Kliknięto OK",
Toast.LENGTH_SHORT).show());
progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE,
"Anuluj",
(dialog, which) -> Toast.makeText(getBaseContext(),
"Kliknięto Anuluj",
Toast.LENGTH_SHORT).show());
progressDialog.show();
new Thread(() -> {
for (int i=1; i<=10; i++) {
try {
Thread.sleep(1500);
progressDialog.incrementProgressBy(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
progressDialog.dismiss();
}).start();
}

488
OKNA DIALOGOWE POSTĘPU

489
UWAGA!
Klasa ProgressDialog została zdeprecjonowana wraz z API 26 (Android 8 „Oreo”) i
nie powinniśmy jej używać. Zamiast tego powinniśmy użyć komponentu ProgressBar.

490
INFORMACYJNE OKNA DIALOGOWE
package edu.zsk.myapplication;

import android.os.Bundle;
import android.view.View;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void DialogWindow(View v) {
AlertDialog.Builder dialogBuilder = new
AlertDialog.Builder(this);
dialogBuilder.setTitle("Informacja");
dialogBuilder.setMessage("Witamy w aplikacji");
AlertDialog dialog = dialogBuilder.create();
dialog.show();
}
}

491
INFORMACYJNE OKNA DIALOGOWE

492
INFORMACYJNE OKNA DIALOGOWE
package edu.zsk.myapplication;

import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void DialogWindow(View v) {
AlertDialog.Builder dialogBuilder = new
AlertDialog.Builder(this);
dialogBuilder.setTitle("Informacja");
dialogBuilder.setMessage("Witamy w aplikacji");
dialogBuilder.setCancelable(false);
dialogBuilder.setPositiveButton("OK",
(dialog, which) -> Toast.makeText(getBaseContext(),
"Okienko zostało zamknięte",
Toast.LENGTH_SHORT).show());
AlertDialog dialog = dialogBuilder.create();
dialog.show();
}
}

493
INFORMACYJNE OKNA DIALOGOWE

494
INFORMACYJNE OKNA DIALOGOWE
package edu.zsk.myapplication;

import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {


int poziom = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void DialogWindow(View v) {
final CharSequence[] pozycje = {"Łatwy","Średni","Trudny","Bardzo trudny"};
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setCancelable(false);
builder.setTitle("Wybierz poziom trudności");
builder.setPositiveButton("OK",
(dialog, which) -> Toast.makeText(getBaseContext(), "Wybrano poziom " + pozycje[poziom],
Toast.LENGTH_SHORT).show());
builder.setNegativeButton("Anuluj",
(dialog, which) -> Toast.makeText(getBaseContext(), "Zrezygnowano ze zmiany poziomu",
Toast.LENGTH_SHORT).show());
builder.setSingleChoiceItems(pozycje, poziom, (dialog, item) -> poziom = item);
AlertDialog dialog = builder.create();
dialog.show();
}
}

495
INFORMACYJNE OKNA DIALOGOWE

496
INTENCJE

497
INTENCJE

• Intencje (ang. intents) są abstrakcyjnym opisem operacji, które mają


być wykonane. Intencje mogą być używane w obrębie jednej aplikacji,
ale także kierowane do innych aplikacji oraz usług działających w tle
(ang. background services).

498
INTENCJE
• Dzielimy je na trzy podstawowe grupy pozwalające na:

• uruchomienie innej aktywności — aby uruchomić nową aktywność, przekazujemy obiekt klasy Intent do
metody startActivity(); intencja opisuje aktywność, która ma zostać uruchomiona, oraz dostarcza innych
niezbędnych do uruchomienia informacji;

• uruchomienie usługi — usługa (ang. service) to komponent, który wykonuje swoje operacje w tle (bez interfejsu
użytkownika), aby ją uruchomić (np. w celu ściągnięcia pliku), przekazujemy intencję do metody startService();
intencja opisuje usługę, która ma zostać uruchomiona, oraz dostarcza innych niezbędnych do uruchomienia informacji;

• dostarczenie komunikatu rozgłoszeniowego — komunikat rozgłoszeniowy (ang. broadcast) to wiadomość,


którą może otrzymać każda aplikacja; system Android rozsyła wiele takich komunikatów związanych z zaistniałymi
zdarzeniami (np. urządzenie rozpoczyna ładowanie baterii, system operacyjny zostaje włączony), nasza aplikacja także
może rozsyłać komunikaty rozgłoszeniowe przez przekazanie intencji do metody sendBroadcast().

499
INTENCJE
• Aby rozpocząć pracę z intencjami i lepiej zrozumieć mechanizm ich działania, musimy opisać dwa typy
intencji:

• intencje jawne (ang. explicit intents) — określają komponent do uruchomienia przez


podanie jego pełnej nazwy; najczęściej wykorzystujemy ten rodzaj intencji do uruchomienia
komponentu w naszej aplikacji, gdyż znamy nazwy intencji czy usług, które chcemy uruchomić;

• intencje domniemane (ang. implicit intents) — nie określają nazwy komponentu, a jedynie
deklarują akcję, którą chcemy wykonać; w tej sytuacji to system operacyjny zdecyduje, który
komponent należy wykorzystać, na przykład jeżeli chcemy pokazać użytkownikowi jego położenie na
mapie, to możemy użyć intencji domniemanej, wtedy to system operacyjny uruchomi aplikację, która
będzie w stanie to zadanie wykonać.
500
INTENCJE
• Kiedy tworzymy intencję jawną, system operacyjny (dzięki dostarczonej mu pełnej
nazwie) natychmiast uruchamia podaną aktywność czy usługę.

• Sytuacja jest bardziej skomplikowana w przypadku intencji domniemanych. W


tej sytuacji system Android przeszukuje odpowiednie komponenty, które mogą
wykonać daną intencję, i porównuje zawartości znacznika <intent- lter>
znajdującego się w plikach manifestu aplikacji zainstalowanych na naszym urządzeniu.
Jeżeli intencja pasuje do ltra intencji danej aplikacji, to jest ona uruchamiana. Jeżeli
natomiast dopasowanie zostało znalezione dla kilku aplikacji, to użytkownikowi zostaje
wyświetlone okno dialogowe, w którym będzie mógł wybrać odpowiednią.
501
fi
fi
FILTR INTENCJI
• Filtr intencji (ang. intent lter) to wyrażenie zde niowane w
pliku manifestu danej aplikacji. Określa ono typy intencji, na jakie
komponenty naszej aplikacji mogą odpowiadać. Dzięki zde niowaniu
odpowiedniego ltra możemy innym aplikacjom umożliwić
uruchamianie naszych aktywności (zgodnie z rodzajem intencji). Jeżeli
jednak nie zde niujemy żadnego ltra intencji danej aktywności, to nie
będzie ona mogła być uruchomiona przez intencję domniemaną.
Natomiast dalej będzie możliwe uruchomienie jej dzięki jawnej intencji.
502
fi
fi
fi
fi
fi
fi
SCHEMAT DZIAŁANIA INTENCJI
DOMNIEMANYCH

503
INTENCJE JAWNE

504
INTENCJE JAWNE - PRZYKŁAD 1
// MainActivity.java

package edu.zsk.myapplication;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

public void onClick(View view) {


startActivity(new Intent(this, SecondActivity.class));
}
}

505
INTENCJE JAWNE - PRZYKŁAD 1
<!-- activity_main.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Pierwsza aktywność"
android:textColor="@color/black"
android:textSize="30sp"
/>

<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Przejdź do drugiej aktywności"
android:id="@+id/button"
android:onClick="onClick" />
</LinearLayout>

506
INTENCJE JAWNE - PRZYKŁAD 1
// SecondActivity.java

package edu.zsk.myapplication;

import android.os.Bundle;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

public class SecondActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
}
}

507
INTENCJE JAWNE - PRZYKŁAD 1
<!-- activity_second.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Druga aktywność"
android:textColor="@color/black"
android:textSize="30sp"
android:gravity="center"
/>
</LinearLayout>
508
INTENCJE JAWNE - PRZYKŁAD 1

509
INTENCJE JAWNE - PRZYKŁAD 2
// MainActivity.java

package edu.zsk.myapplication;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

public void onClick(View view) {


Intent i = new Intent(this, SecondActivity.class);
i.putExtra("Imie", "Janusz");
i.putExtra("Wiek", 18);
startActivity(i);
}
}

510
INTENCJE JAWNE - PRZYKŁAD 2
// SecondActivity.java

package edu.zsk.myapplication;

import android.os.Bundle;
import android.widget.Toast;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

public class SecondActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
Bundle bundle = getIntent().getExtras();
if (bundle != null) {
String napis = bundle.getString("Imie");
int liczba = bundle.getInt("Wiek");
Toast.makeText(this, napis + " ma " + liczba + " lat",
Toast.LENGTH_SHORT).show();
}
}
}

511
INTENCJE JAWNE - PRZYKŁAD 2

512
INTENCJE JAWNE - PRZYKŁAD 3
// MainActivity.java

package edu.zsk.myapplication;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {


int myCode = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

public void onClick(View view) {


startActivityForResult(new Intent(this, SecondActivity.class), myCode);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == myCode && resultCode == RESULT_OK) {
String imie = data.getStringExtra("imie");
Toast.makeText(this, "Witaj " + imie, Toast.LENGTH_SHORT).show();
}
super.onActivityResult(requestCode, resultCode, data);
}
}

513
INTENCJE JAWNE - PRZYKŁAD 3
<!-- activity_main.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Pierwsza aktywność"
android:textColor="@color/black"
android:textSize="30sp"
/>

<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Przejdź do drugiej aktywności"
android:id="@+id/button"
android:onClick="onClick" />
</LinearLayout>

514
INTENCJE JAWNE - PRZYKŁAD 3
// SecondActivity.java

package edu.zsk.myapplication;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

public class SecondActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
}

public void onClick(View view) {


Intent intent = new Intent();
EditText imie = findViewById(R.id.imie);
intent.putExtra("imie", imie.getText().toString());
setResult(RESULT_OK, intent);
finish();
}
}

515
INTENCJE JAWNE - PRZYKŁAD 3
<!-- activity_second.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Druga aktywność"
android:textColor="@color/black"
android:textSize="30sp"
android:gravity="center"
/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Podaj imię:"
android:textColor="@color/black"
android:id="@+id/textView"
android:textSize="20sp" />

<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/black"
android:id="@+id/imie" />

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Logowanie"
android:id="@+id/button"
android:onClick="onClick"/>
</LinearLayout>

516
INTENCJE JAWNE - PRZYKŁAD 3

517
INTENCJE DOMNIEMANE

518
INTENCJE DOMNIEMANE

• Teraz zajmiemy się intencjami domniemanymi, które dają nam dużo


większe możliwości. Dzięki nim oprócz wywoływania naszych
aktywności będziemy mogli także kierować żądania do systemu czy
innych aplikacji.

519
INTENCJE DOMNIEMANE - PRZYKŁAD 1
<?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/MyApplication"
tools:targetApi="31">
<activity
android:name=".SecondActivity"
android:exported="false"
>
<intent-filter>
<action android:name="edu.zsk.myapplication.ACTION2" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<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>

520
INTENCJE DOMNIEMANE - PRZYKŁAD 1
// MainActivity.java

package edu.zsk.myapplication;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

public void onClick(View view) {


startActivity(new Intent("edu.zsk.myapplication.ACTION2"));
}
}

521
INTENCJE DOMNIEMANE - PRZYKŁAD 1
// SecondActivity.java

package edu.zsk.myapplication;

import android.os.Bundle;

import androidx.appcompat.app.AppCompatActivity;

public class SecondActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
}
}
522
INTENCJE DOMNIEMANE - PRZYKŁAD 1

523
INTENCJE DOMNIEMANE - PRZYKŁAD 2
<activity
android:name=".ThirdActivity"
android:exported="false">
<intent-filter>
<action android:name="edu.zsk.myapplication.ACTION2" />

<category android:name="android.intent.category.DEFAULT" />


</intent-filter>
</activity>
<activity
android:name=".SecondActivity"
android:exported="false">
<intent-filter>
<action android:name="edu.zsk.myapplication.ACTION2" />

<category android:name="android.intent.category.DEFAULT" />


</intent-filter>
</activity>

524
INTENCJE DOMNIEMANE - PRZYKŁAD 2
// MainActivity.java

package edu.zsk.myapplication;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

public void onClick(View view) {


startActivity(new Intent("edu.zsk.myapplication.ACTION2"));
}
}

525
INTENCJE DOMNIEMANE - PRZYKŁAD 2
<!-- activity_main.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Pierwsza aktywność"
android:textColor="@color/black"
android:textSize="30sp"
/>

<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Przejdź do innej aktywności"
android:id="@+id/button"
android:onClick="onClick" />
</LinearLayout>

526
INTENCJE DOMNIEMANE - PRZYKŁAD 2
// SecondActivity.java

package edu.zsk.myapplication;

import android.os.Bundle;

import androidx.appcompat.app.AppCompatActivity;

public class SecondActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
}
}
527
INTENCJE DOMNIEMANE - PRZYKŁAD 2
<!-- activity_second.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Druga aktywność"
android:textColor="@color/black"
android:textSize="30sp"
android:gravity="center"
/>
</LinearLayout>
528
INTENCJE DOMNIEMANE - PRZYKŁAD 2
// ThirdActivity.java

package edu.zsk.myapplication;

import android.os.Bundle;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

public class ThirdActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_third);
}
}

529
INTENCJE DOMNIEMANE - PRZYKŁAD 2
<!-- activity_third.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Trzecia aktywność"
android:textColor="@color/black"
android:textSize="30sp"
android:gravity="center"
/>
</LinearLayout>
530
INTENCJE DOMNIEMANE - PRZYKŁAD 2

531
INTENCJE DOMNIEMANE - PRZYKŁAD 3
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Podaj adres strony WWW" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/editTextWebsite"
android:text="zsk.poznan.pl" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Otwórz WWW"
android:id="@+id/buttonWebsite"
android:onClick="onClickButtonWebsite"/>
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="@android:color/darker_gray" /> <!-- Linia -->

532
INTENCJE DOMNIEMANE - PRZYKŁAD 3
// MainActivity.java

public void onClickButtonWebsite(View view)


{
EditText editText = findViewById(R.id.editTextWebsite);
String url = editText.getText().toString();
Uri uri = Uri.parse("http://" + url);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}

533
INTENCJE DOMNIEMANE - PRZYKŁAD 3
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Podaj miasto" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/editTextCity"
android:text="Poznań" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pokaż Miasto"
android:id="@+id/buttonCity"
android:onClick="onClickButtonCity"/>
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="@android:color/darker_gray" /> <!-- Linia -->

534
INTENCJE DOMNIEMANE - PRZYKŁAD 3

// MainActivity.java

public void onClickButtonCity(View view)


{
EditText editText = findViewById(R.id.editTextCity);
String city = editText.getText().toString();
Uri geoUri = Uri.parse("geo:0,0?q=" + city);
Intent intent = new Intent(Intent.ACTION_VIEW, geoUri);
startActivity(intent);
}

535
INTENCJE DOMNIEMANE - PRZYKŁAD 3
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Podaj szerokość geograficzną" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/editTextLatitude"
android:inputType="numberDecimal"
android:text="52.2296" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Podaj długość geograficzną" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/editTextLongitude"
android:inputType="numberDecimal"
android:text="21.0122" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pokaż Lokalizację"
android:id="@+id/buttonLocation"
android:onClick="onClickButtonLocation" />

536
INTENCJE DOMNIEMANE - PRZYKŁAD 3
// MainActivity.java

public void onClickButtonLocation(View view)


{
EditText editText = findViewById(R.id.editTextLatitude);
String latitude = editText.getText().toString();
EditText editText2 = findViewById(R.id.editTextLongitude);
String longitude = editText2.getText().toString();
String s = String.format("geo:%s,%s", latitude, longitude);
Uri geoUri = Uri.parse(s);
Intent intent = new Intent(Intent.ACTION_VIEW, geoUri);
startActivity(intent);
}
537
INTENCJE DOMNIEMANE - PRZYKŁAD 3

538
INTENCJE DOMNIEMANE - PRZYKŁAD 4
public void onClickAlarm(View view){
Intent intent = new Intent(AlarmClock.ACTION_SET_ALARM)
.putExtra(AlarmClock.EXTRA_MESSAGE, "Pora wstawać!")
.putExtra(AlarmClock.EXTRA_HOUR, 17)
.putExtra(AlarmClock.EXTRA_MINUTES, 54);
startActivity(intent);
}

public void onClickTimer(View view) {


Intent intent = new Intent(AlarmClock.ACTION_SET_TIMER)
.putExtra(AlarmClock.EXTRA_MESSAGE, "Odliczanie w dół!")
.putExtra(AlarmClock.EXTRA_LENGTH, 15)
.putExtra(AlarmClock.EXTRA_SKIP_UI, false);
startActivity(intent);
}
539
INTENCJE DOMNIEMANE - PRZYKŁAD 4
<!-- activity_main.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Ustaw Alarm"
android:id="@+id/buttonAlarm"
android:onClick="onClickAlarm"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Ustaw Timer"
android:id="@+id/buttonTimer"
android:onClick="onClickTimer"/>
</LinearLayout>

540
INTENCJE DOMNIEMANE - PRZYKŁAD 4

<?xml version="1.0" encoding="utf-8"?>


<manifest xmlns:android="http://schemas.android.com/apk/res/
android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission
android:name="com.android.alarm.permission.SET_ALARM" />
[...]
</manifest>

541
INTENCJE DOMNIEMANE - PRZYKŁAD 4

542
FRAGMENTY

543
FRAGMENTY
• Od wersji systemu Android 3.0 możemy korzystać z fragmentów
(ang. fragments), które pozwalają na podzielenie naszej aktywności na
moduły oraz lepsze dopasowanie wyglądu i zachowania naszej
aplikacji. Wynika to z faktu, że oprócz urządzeń o małym ekranie,
takich jak smartfony, naszą aplikację mogą obsługiwać także tablety o
dużo większych rozmiarach. Ta dużo większa przestrzeń może zostać
lepiej wykorzystana dzięki wyświetlaniu dwóch (lub większej liczby)
fragmentów w ramach jednej aktywności.
544
FRAGMENTY

• Na początku dobrze jest intuicyjnie skojarzyć fragment z podaktywnością,


w której mogą pojawić się elementy interfejsu użytkownika i która ma
własny cykl życia oraz zawsze jest osadzona w jakiejś aktywności.

• Fragmenty mogą być ustawiane statycznie oraz dynamicznie. Na przykład


kiedy zmienia się orientacja aplikacji, utworzenie fragmentów (i osadzenie
ich w naszej aktywności) polepszy zagospodarowanie przestrzeni ekranu.

545
FRAGMENTY - PRZYKŁAD 1
// MainActivity.java

package edu.zsk.myapplication;

import android.os.Bundle;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
546
FRAGMENTY - PRZYKŁAD 1
<!-- activity_main.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:name="edu.zsk.myapplication.FirstFragment"
android:id="@+id/fragment1"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<fragment
android:name="edu.zsk.myapplication.SecondFragment"
android:id="@+id/fragment2"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>

547
FRAGMENTY - PRZYKŁAD 1
// FirstFragment.java

package edu.zsk.myapplication;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.fragment.app.Fragment;

public class FirstFragment extends Fragment {


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
return inflater.inflate(R.layout.fragment_first, container, false);
}
}

548
FRAGMENTY - PRZYKŁAD 1
<?xml version="1.0" encoding="utf-8"?>
<!--fragment_first.xml-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#5eb4e6">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Fragment 1"
android:textColor="#000000"
android:textSize="30sp" />
</RelativeLayout>
549
FRAGMENTY - PRZYKŁAD 1
// SecondFragment.java

package edu.zsk.myapplication;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.fragment.app.Fragment;

public class SecondFragment extends Fragment {


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
return inflater.inflate(R.layout.fragment_second, container, false);
}
}

550
FRAGMENTY - PRZYKŁAD 1
<?xml version="1.0" encoding="utf-8"?>
<!--fragment_second.xml-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#dc3b53">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Fragment 2"
android:textColor="#000000"
android:textSize="30sp" />
</RelativeLayout>
551
FRAGMENTY - PRZYKŁAD 1

552
FRAGMENTY - PRZYKŁAD 1

553
FRAGMENTY - PRZYKŁAD 2

<!-- activity_main.xml -->


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/
android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:id="@+id/main">
</LinearLayout>

554
FRAGMENTY - PRZYKŁAD 2
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
if (getResources().getConfiguration().orientation ==
Configuration.ORIENTATION_PORTRAIT)
{
fragmentTransaction.replace(R.id.main, new FirstFragment());
}
else
{
fragmentTransaction.replace(R.id.main, new SecondFragment());
}
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}

555
FRAGMENTY - PRZYKŁAD 2

556
FRAGMENTY - PRZYKŁAD 3
<!-- activity_main.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:name="edu.zsk.myapplication.FirstFragment"
android:id="@+id/fragment1"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<fragment
android:name="edu.zsk.myapplication.SecondFragment"
android:id="@+id/fragment2"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>

557
FRAGMENTY - PRZYKŁAD 3
// MainActivity.java

package edu.zsk.myapplication;

import android.os.Bundle;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
558
FRAGMENTY - PRZYKŁAD 3
<?xml version="1.0" encoding="utf-8"?>
<!--fragment_first.xml-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#5eb4e6">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Fragment 1"
android:textColor="#000000"
android:textSize="30sp"
android:id="@+id/textView2"/>
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/editText"
android:text="Wpisz tekst"
android:layout_below="@+id/textView2"
android:layout_centerHorizontal="true" />
</RelativeLayout>

559
FRAGMENTY - PRZYKŁAD 3
// FirstFragment.java

package edu.zsk.myapplication;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.fragment.app.Fragment;

public class FirstFragment extends Fragment {


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
return inflater.inflate(R.layout.fragment_first, container, false);
}
}

560
FRAGMENTY - PRZYKŁAD 3
<?xml version="1.0" encoding="utf-8"?>
<!--fragment_second.xml-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#dc3b53">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Fragment 2"
android:textColor="#000000"
android:textSize="30sp"
android:id="@+id/textView"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pobierz tekst"
android:id="@+id/button"
android:layout_below="@+id/textView"
android:layout_centerHorizontal="true" />
</RelativeLayout>

561
FRAGMENTY - PRZYKŁAD 3
// SecondFragment.java

package edu.zsk.myapplication;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;

public class SecondFragment extends Fragment {


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_second, container, false);
Button button = view.findViewById(R.id.button);
button.setOnClickListener(v -> {
FragmentActivity activity = getActivity();
assert activity != null;
EditText edit = activity.findViewById(R.id.editText);
Toast.makeText(activity, edit.getText().toString(), Toast.LENGTH_SHORT).show();
});
return view;
}
}

562
FRAGMENTY - PRZYKŁAD 3

563

You might also like