1.
Treści programowe:
Baza danych SQLite, bibliotekę Room Persistence Library, encje,
DAO (Data Access Objects), pobieranie, zapisywanie danych oraz starszej
metody SQLiteOpenHelper.
2.
Cel zajęć:
Celem zajęć jest poznanie mechanizmu zarządzania informacjami w
lokalnej bazie danych SQLite używając architektury Room.
3.
Materiały dydaktyczne
SQLite jest
bardzo „lekkim”, darmowym systemem zarządzania relacyjną bazą danych
wykorzystującym bibliotekę napisaną w języku C pozwalająca na używanie języka
SQL. System uruchamia bazę danych bez uruchamiania oddzielnego procesu. Jest to
podstawa do używania go np. w systemach wbudowanych. Wszystko co jest potrzebne
znajduję się w jednym pliku. Programując w systemie operacyjnym Android możemy
używać SQLite bez instalowania dodatkowych
sterowników. Bazę tą możemy używać również w aplikacjach desktopowych w różnych
językach programowania. SQLite jest rekomendowane
przez Google jako lokalna baza danych.
Dokumentacja: https://developer.android.com/training/data-storage/room#kts
ü Room
Room został stworzony, aby pomóc deweloperom w tworzeniu
solidnych, skalowalnych i łatwych w utrzymaniu baz danych na platformie
Android.
Niezbędne zależności (kotlin):
val room_version = "2.8.3"
implementation("androidx.room:room-runtime:$room_version")
annotationProcessor("androidx.room:room-compiler:$room_version")
I. Entity
1. Adnotacja @Entity
2. Adnotacja @PrimaryKey
public class User {
@PrimaryKey(autoGenerate = true)
private int
id;
}
Definicja klucza złożonego klucza głównego primaryKeys:
@Entity(primaryKeys = {"firstName", "lastName"})
public class User {
public String firstName;
public String lastName;
}
3. Adnotacja @ColumnInfo
@ColumnInfo(name = "first_name")
private String firstName;
@ColumnInfo(name = "last_name")
private String lastName;
4. Adnotacja @Ignore
@Entity
public class User {
@PrimaryKey
public int id;
public String firstName;
public String lastName;
@Ignore
Bitmap picture;
}
Gdy klasa główna dziedziczy pola z klasy nadrzędnej, zazwyczaj
łatwiej jest użyć ignoredColumn właściwości atrybutu @Entity
@Entity(ignoredColumns =
"picture")
public class RemoteUser
extends User {
@PrimaryKey
public int id;
public boolean hasVpn;
}
------------------------------------------------------------------------
Obiekt reprezentujący tabelę – jednostka danych entitiy:
Plik User.java
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
// 1. Określamy nazwę tabeli w bazie danych
@Entity(tableName = "users")
public class User {
// 2. Definicja
Klucza Głównego (Primary Key)
// autoGenerate
= true oznacza, że SQLite
automatycznie wygeneruje unikalny ID
@PrimaryKey(autoGenerate = true)
private int
id;
// 3. Definicja
kolumn tabeli
// Określamy nazwę kolumny w bazie
@ColumnInfo(name = "first_name")
private String firstName;
@ColumnInfo(name = "last_name")
private String lastName;
@ColumnInfo(name = "age")
private int
age;
// Konstruktor do
tworzenia obiektu
// Room
użyje tego konstruktora do wstawiania danych do bazy
// oraz do odczytu danych z bazy (lub
konstruktora bez argumentów, jeśli jest obecny)
public User(String firstName,
String lastName, int age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
// --- Gettery i Settery ---
// W Javie są one niezbędne, aby Room mógł odczytywać i ustawiać wartości pól.
public int getId() {
return
id;
}
// Room wymaga settera dla Primary Key, jeśli używamy autoGenerate = true
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return
firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return
lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public int getAge() {
return
age;
}
public void setAge(int age) {
this.age = age;
}
}
II. Główny
punkt dostępu
Poniższy kod definiuje klasę AppDatabase,
która jest głównym punktem dostępu i konfiguracji dla bazy danych Room w systemie Android.
AppDatabase jest centralną klasą, która łączy Twoje encje (User) i
DAO (UserDao), zarządzając bazą danych SQLite.
Plik AppDatabase.java
import androidx.room.Database;
import androidx.room.RoomDatabase;
@Database(entities = {User.class}, version = 2)
public abstract class
AppDatabase extends RoomDatabase {
public abstract UserDao userDao();
}
|
Element |
Opis |
|
extends RoomDatabase |
Abstrakcyjna
klasa bazy danych Room. Room
automatycznie generuje jej implementację podczas kompilacji. |
|
@Database(...) |
Adnotacja
konfigurująca bazę danych. |
|
entities = {User.class} |
Określa,
że w tej bazie danych znajduje się jedna tabela, reprezentowana przez encję User.
Jeśli byłoby więcej tabel, byłyby one tutaj wymienione. |
|
version = 1 |
Ustala
wersję schematu bazy danych. Wymaga zwiększenia tego numeru, jeśli zmieniasz
strukturę tabel (np. dodajesz kolumny), co wymusza uruchomienie migracji. |
|
public abstract UserDao userDao(); |
Abstrakcyjna
metoda służąca do uzyskiwania dostępu do DAO (UserDao).
Pozwala to na wykonywanie operacji na danych (zapytań) w tabeli User. |
III. DAO
(Data Access Objects)
DAO (ang. Data Access Object – Obiekt Dostępu do
Danych) to wzorzec projektowy w programowaniu oraz kluczowy komponent
biblioteki Room w systemie Android.
DAO to "słownik" lub "katalog" wszystkich
operacji, które możesz wykonać na danych w swojej bazie, oddzielając w
ten sposób logikę dostępu do danych od reszty aplikacji.
--------------------------------------------------------------------------------------------
Przykład pokazujący deklarację interfejsu do obsługi danych reprezentowanych
przez klasę User:
Plik UserDao.java
import androidx.lifecycle.LiveData;
import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;
import androidx.room.Update;
import java.util.List;
// Adnotacja @Dao oznacza, że ten interfejs jest Data Access
Object dla Room
@Dao
public interface UserDao {
/**
* Wstawia jednego lub więcej
użytkowników do bazy danych.
* @param user Użytkownik do wstawienia.
* @return Zwraca ID nowo wstawionego
wiersza.
*/
@Insert
long insert(User user);
/**
* Wstawia wielu użytkowników do bazy
danych.
* @param user obiekty użytkowników do wstawienia.
*/
@Insert
void insertUsers(User ... user);
/**
* Wstawia wielu użytkowników do bazy
danych.
* @param users jest listą użytkowników do wstawienia.
*/
@Insert
void insertAll(List<User> users);
/**
* Aktualizuje istniejącego
użytkownika.
* @param user Użytkownik do zaktualizowania (zgodnie z jego ID).
* @return Liczba zaktualizowanych
wierszy (zazwyczaj 1).
*/
@Update
int update(User user);
/**
* Usuwa użytkownika z bazy danych.
* @param user Użytkownik do usunięcia.
* @return Liczba usuniętych wierszy
(zazwyczaj 1).
*/
@Delete
int delete(User user);
// --- Metody
zapytań
/**
* Pobiera wszystkich użytkowników z
tabeli "users".
* Zwraca Listę obiektów User.
*/
@Query("SELECT *
FROM users ORDER BY last_name
ASC")
List<User> getAllUsersList();
/**
* Pobiera wszystkich użytkowników z
tabeli "users".
* Zwraca LiveData,
aby umożliwić reaktywne obserwowanie zmian w danych.
*/
@Query("SELECT *
FROM users ORDER BY last_name
ASC")
LiveData<List<User>>
getAllUsers();
/**
* Pobiera pojedynczego użytkownika
na podstawie jego ID.
* @param userId ID użytkownika.
* @return Obiekt User lub null, jeśli nie znaleziono.
*/
@Query("SELECT *
FROM users WHERE id = :userId")
User getUserById(int userId);
/**
* Usuwa wszystkie rekordy z tabeli
"users".
*/
@Query("DELETE FROM
users")
void deleteAll();
}
IV. Room Database
Utworzenie instancji bazy danych oraz wykorzystanie
zadeklarowanych wcześniej zasobów:
Plik MainActivity.java
import android.os.Bundle;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.room.Room;
import java.util.ArrayList;
import java.util.List;
public class MainActivity
extends AppCompatActivity {
private TextView textView;
@Override
protected void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
// Utworzenie obiektu db reprezentującego
bazę danych „baza”
AppDatabase
db = Room.databaseBuilder(getApplicationContext(),
AppDatabase.class, "baza").build();
// Uchwyt do zasobów DAO
UserDao
userDao = db.userDao();
new Thread(new Runnable() {
@Override
public void run() {
// userDao.deleteAll();
User user1 = new User("Jan", "Ptak",
33);
userDao.insert(user1);
//
//
user1.setFirstName("Janusz");
// user1.setId(1);
// userDao.update(user1);
User user2 = new User("Wincenty", "Kowalski",
22);
User user3 = new User("Monika",
"Nowak", 49);
userDao.insertUsers(user2, user3);
User user4 = new User("Mariola",
"Zychowaska", 23);
User user5 = new User("Monika",
"Nowakowska", 44);
List<User> lista = new ArrayList<>();
lista.add(user4);
lista.add(user5);
userDao.insertAll(lista);
User userNew
= userDao.getUserById(1);
if (userNew!=null) {
String dane = userNew.toString();
runOnUiThread(()
-> textView.setText(dane));
}
List<User> users = userDao.getAllUsersList();
for (User user: users) {
runOnUiThread(()
-> textView.append(user.toString()+"\n"));
}
}
}).start();
}
}
------------------------------------------------------------------------------------------
ü Łączenie danych z dwóch tabel
Tabela users:

Tabela Work:

Plik AppDatabase.java
import androidx.room.Database;
import androidx.room.RoomDatabase;
@Database(entities = {User.class, Work.class}, version = 4)
public abstract class
AppDatabase
extends RoomDatabase
{
public abstract UserDao userDao();
}
Klasa Work.java
import androidx.room.Entity;
import androidx.room.PrimaryKey;
@Entity
public class Work{
@PrimaryKey(autoGenerate = true)
public int id;
public String name;
public int id_user;
public Work(String name, int id_user) {
this.name = name;
this.id_user = id_user;
}
}
Plik UserDao.java
//…należy
dodać do istniejącego pliku
@Query("SELECT first_name, name FROM users INNER JOIN work ON users.id
= work.id_user")
List<UserWork> getUserWork();
Plik UserWork.java
public class UserWork
{
public String first_name;
public String name;
}
Plik MainActivity.java
// ……
new Thread(new Runnable() {
@Override
public void run() {
User user1 = new User("Jan", "Kowalski", 33);
User user2 = new User("Janina",
"Kowalski", 36);
User user3 = new User("Balbina",
"Nowak", 41);
userDao.insertUsers(user1,
user2, user3);
Work
work1 = new Work("Sprzatanie", 2);
Work
work2 = new Work("Pranie",
3);
userDao.insertWork(work1);
userDao.insertWork(work2);
List<UserWork>
userWorks = userDao.getUserWork();
for
(UserWork userWork
: userWorks) {
runOnUiThread(()->textView.append(userWork.first_name
+ " " + userWork.name + "\n"));
}
}
}).start();

--------------------------------------------------------------------------------------------
ü Metoda wykorzystująca klasę SQLiteOpenHelper
Tworzenie
i modyfikacja bazy danych wspierane jest przez klasę SQLiteOpenHelper.
Pusta
klasa obsługująca bazę danych wygenerowana automatycznie poprzez narzędzia InteliJ Idea:
public class BazaDanych
extends SQLiteOpenHelper{
public BazaDanych(Context context, String name, SQLiteDatabase.CursorFactory
factory, int version) {
super(context, name,
factory, version);
}
@Override
public void onCreate(SQLiteDatabase db)
{
}
@Override
public void onUpgrade(SQLiteDatabase db,
int oldVersion,
int newVersion)
{
}
}
Stałe
Definicja
stałych pozwala na zebranie wszystkich wykorzystywanych w bazie danych nazw
tabel, kolumn, jak również samej bazy danych na początku klasy. W przypadku
zmiany np. nazwy tabeli musimy tej zmiany dokonać raz przy deklaracji. Jest to
dobry zwyczaj, który na dłuższą metę sprawia, iż zmiany dokonujemy w jednym
miejscu zwiększając tym samym czytelność kodu.
Stała
DATABASE_VERSION określa wersję bazy danych. Jeśli numer nie będzie się zgadzał
z tym ostatnio użytym program wywoła metodę onUpdate
co spowoduje zamianę istniejącej bazy na nową pusta w nowej wersji.
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "lista_zakupow";
private static final String TABLE_ARTICLES = "baza_towarow";
private static final String KEY_ID =
"id";
private static final String KEY_NAME =
"name";
private static final String KEY_CHECK = "checkk";
private static final String KEY_NR_LIST = "nr_list";
Modyfikacja konstruktora
Ponieważ nazwa tabeli oraz wersja są zdefiniowane w
klasie BazaDanych modyfikujemy konstruktor tak aby
podczas wywoływania przekazywany był tyko kontekst klasy, w której tworzona
jest instancja bazy danych. Kontekst to obiekt przechowujący informację o
stanie obiektu. W naszym przypadku przekazujemy kontekst do aktywności, w
której używać będziemy bazy danych.
public BazaDanych(Context context) {
super(context, DATABASE_NAME, null,
DATABASE_VERSION);
}
Modyfikacja metody onCreate w
klasie BazaDanych:
Metoda
onCreate wywoływana jest na początku wtedy, gdy baza
danych jeszcze nie istnieje.
String CREATE_CONTACTS_TABLE =
"CREATE TABLE " + TABLE_ARTICLES + "("+
KEY_ID + "
INTEGER PRIMARY KEY AUTOINCREMENT," +
KEY_NAME + "
TEXT,"+
KEY_CHECK+ "
INTEGER," +
KEY_NR_LIST+" INTEGER"+
")";
db.execSQL(CREATE_CONTACTS_TABLE);
Modyfikacja klasy onUpdate
onUpdate – metoda ściśle związana z wersją bazy danych. Zawarty tu
kod powoduje usunięcie istniejącej tabeli oraz wywołując metody onCreate tworzy nową pustą. Zmieniając wartość stałej DATABASE_VERSION
(przed kompilacją) musimy pamiętać o zrobieniu kopi tabeli. Najlepiej zrobić
kopię całej bazy danych
db.execSQL("DROP
TABLE IF EXISTS " + TABLE_ARTICLES);
onCreate(db);
Pomocnicza klasa Towar
Klasa pomocna w organizowaniu danych zebranych w
ramach jednego towaru.
public class Towar {
private String nazwa;
private boolean
check=false;
public Towar(String nazwa, boolean check) {
super();
this.nazwa = nazwa;
this.check=check;
}
public String getNazwa() {
return
nazwa;
}
public boolean isCheck() {
return
check;
}
public void setCheck(boolean check) {
this.check = check;
}
public void setNazwa(String nazwa) {
this.nazwa = nazwa;
}
}
Metoda dodająca dane do bazy danych:
public void dodajTowar(Towar
towar, int nrListy) {
SQLiteDatabase
db = this.getWritableDatabase();
ContentValues
values = new ContentValues();
values.put(KEY_NAME,
towar.getNazwa());
values.put(KEY_CHECK,
towar.isCheck());
values.put(KEY_NR_LIST,
nrListy);
//db.insert(TABLE_ARTICLES, null, values);
db.insertOrThrow(TABLE_ARTICLES, null, values);
db.close();
Log.d(">>>> Baza danych: ", "Dodano dane !!!");
}
Metoda usuwająca dane z bazy danych:
public void deleteTowar(Towar
towar, int nrListy) {
SQLiteDatabase
db = this.getWritableDatabase();
db.delete(TABLE_ARTICLES,
KEY_NAME + " = ? and " + KEY_NR_LIST + " =?", new String[]{String.valueOf(towar.getNazwa()), "" + nrListy});
db.close();
}
Metoda pobierająca dane z bazy danych w formie ciągu
znaków:
public String getAllRecords(int nrListy) {
SQLiteDatabase
db = this.getReadableDatabase();
String string="";
Cursor cursor = db.query(TABLE_ARTICLES,
null, KEY_NR_LIST + "=?",
new String[] { String.valueOf(nrListy) },
null, null, null, null);
cursor.moveToFirst();
int nr=1;
do{
boolean check =false;
if(cursor.getInt(2)>1)
check=true;
string+=nr+". "+cursor.getString(1)+" "+check +"\n";
nr++;
Log.d(">>>> Baza danych", "Pobrano dane: "+ string);
} while(cursor.moveToNext());
return string;
}
Metoda pobierająca dane z bazy danych w formie listy:
public int updateTowar(Towar
towar, String staraNazwa, int nr_listy) {
SQLiteDatabase
db = this.getWritableDatabase();
ContentValues
values = new ContentValues();
values.put(KEY_NAME,
towar.getNazwa());
int check=0;
if(towar.isCheck()) check=1;
values.put(KEY_CHECK,
check);
return db.update(TABLE_ARTICLES,
values, KEY_NAME + "
= ? and "+KEY_NR_LIST+" =?" , new String[] {staraNazwa, ""+nr_listy});
}
Metoda aktualizująca dane w bazy danych:
public int updateTowar(Towar
towar, String staraNazwa, int nr_listy) {
SQLiteDatabase
db = this.getWritableDatabase();
ContentValues
values = new ContentValues();
values.put(KEY_NAME,
towar.getNazwa());
int check=0;
if(towar.isCheck()) check=1;
values.put(KEY_CHECK,
check);
return db.update(TABLE_ARTICLES,
values, KEY_NAME + "
= ? and "+KEY_NR_LIST+" =?" , new String[] {staraNazwa, ""+nr_listy});
}
Przykładowa klasa Aktywności z jednym komponentem
graficznym TextView wykorzystująca obiekt bazy danych
(zapisywanie, pobieranie i wyświetlanie danych):
public class MainActivity
extends AppCompatActivity {
@Override
protected void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView
textView = (TextView) findViewById(R.id.textView2);
BazaDanych
bazaDanych = new BazaDanych(this);
Towar towar1 = new Towar("Mleko",
false);
bazaDanych.dodajTowar(towar1,
1);
Towar towar2 = new Towar("Maslo", false);
bazaDanych.dodajTowar(towar2,
1);
Towar towar3 = new Towar("Woda",
false);
bazaDanych.dodajTowar(towar3,
2);
Towar towar4 = new Towar("Sok", false);
bazaDanych.dodajTowar(towar4,
2);
List<Towar> towarList = new ArrayList<Towar>();
towarList=bazaDanych.getAllTowary(1);
for
(int i = 0; i < towarList.size(); i++) {
System.out.println(towarList.get(i));
textView.append(towarList.get(i).getNazwa().toString()+” “+towarList.get(i).isCheck()+"\n");
}
}
PRZYKŁADOWY PROGRAM:

Klasa BazaDanych:
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class BazaDanych extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 2;
private static final String DATABASE_NAME = "lista_zakupow";
private static final String TABLE_ARTICLES = "baza_towarow";
private static final String KEY_ID = "id";
private static final String KEY_NAME = "name";
private static final String KEY_CHECK = "checkk";
private static final String KEY_NR_LIST = "nr_list";
public BazaDanych(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase
db) {
String CREATE_CONTACTS_TABLE = "CREATE TABLE " + BazaDanych.TABLE_ARTICLES + "("+
BazaDanych.KEY_ID + " INTEGER PRIMARY KEY
AUTOINCREMENT," +
BazaDanych.KEY_NAME + " TEXT,"+
BazaDanych.KEY_CHECK+ " INTEGER," +
BazaDanych.KEY_NR_LIST+" INTEGER"+ ")";
db.execSQL(CREATE_CONTACTS_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase
db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_ARTICLES);
onCreate(db);
}
public void dodajTowar(Towar towar, int nrListy) {
SQLiteDatabase
db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_NAME, towar.getNazwa());
values.put(KEY_CHECK, towar.isCheck());
values.put(KEY_NR_LIST, nrListy);
//db.insert(TABLE_ARTICLES,
null, values);
db.insertOrThrow(TABLE_ARTICLES, null, values);
db.close();
}
public void deleteTowar(Towar towar, int nrListy) {
SQLiteDatabase
db = this.getWritableDatabase();
db.delete(TABLE_ARTICLES, KEY_NAME + " = ? and " + KEY_NR_LIST + " =?", new String[]{String.valueOf(towar.getNazwa()), "" + nrListy});
db.close();
}
public String getAllRecords(int nrListy) {
SQLiteDatabase
db = this.getReadableDatabase();
String string="";
Cursor cursor
= db.query(TABLE_ARTICLES, null, KEY_NR_LIST + "=?",
new String[] { String.valueOf(nrListy) }, null, null, null, null);
cursor.moveToFirst();
int nr=1;
do{
boolean check =false;
if(cursor.getInt(2)>1)
check=true;
string+=nr+". "+cursor.getString(1)+" "+check +"\n";
nr++;
} while(cursor.moveToNext());
return string;
}
}
Klasa Towar:
public class Towar {
private String nazwa;
private boolean
check=false;
public Towar(String nazwa, boolean check) {
super();
this.nazwa = nazwa;
this.check=check;
}
public String getNazwa() {
return nazwa;
}
public boolean
isCheck() {
return check;
}
public void setCheck(boolean check) {
this.check = check;
}
public void setNazwa(String nazwa)
{
this.nazwa = nazwa;
}
}
Klasa gówna MainActivity:
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BazaDanych db = new BazaDanych(this);
Towar mleko = new Towar("Mleko", true);
db.dodajTowar(mleko, 1);
Towar chleb = new Towar("Chleb", true);
db.dodajTowar(chleb, 1);
String towary
= db.getAllRecords(1);
TextView textViewTowar
= (TextView)findViewById(R.id.textViewTowar);
textViewTowar.setText(towary);
}
}
plik activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#123"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:layout_marginTop="16dp"
android:text="Lista zakupów"
android:textColor="#fff"
android:textSize="27dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.04000002" />
<TextView
android:id="@+id/textViewTowar"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="24dp"
android:layout_marginBottom="16dp"
android:text="TextView"
android:textSize="24dp"
android:textColor="#fff"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView2" />
</androidx.constraintlayout.widget.ConstraintLayout>
-------------------------------------------------------------------
4.
Zadania
Zadanie 1.
Napisz aplikację przechowującą i
zarządzającą danymi studenta: imie, nazwisko,
kierunek, rok_studiow. Wszystkie dane powinny być
wprowadzane z widoku. Dostępne funkcje to: dodawanie, usuwanie,
aktualizacja, pobieranie rekordów z poziomu interfejsu
użytkownika.
Zadanie 2.
Napisz aplikację, która pozwoli
przechowywać dane w dwóch tabelach bazy danych o nazwie „serwis_komputerowy” .
Pierwsza tabela to „naprawy”, w którym możemy zapisać takie dane, jak:
- nazwa_naprawy,
- cena,
- id_klienta.
Druga tabela to klient z następującymi
polami:
- imie,
- nazwisko,
- pesel.
Zaprojektuj interfejs użytkownika,
który pozwoli zarządzać danymi, tzn. wprowadzać dane do obu tabel oraz
wyświetlać dane łącząc dwie tabele.