JAVA ANDROID 05 (p) - Sqlite database

JAVA ANDROID 05 (p) - Sqlite database
ukryj menu
SPEC
aktualizacja: 2022-03-29 09:17:14

T: Mechanizm notatek do zdjęć

Scenariusz aplikacji

- przycisk edytuj obok zdjęcia w galerii, otwiera się customowy Dialog z możliwością wprowadzenia notatki (tytuł, treść, kolor fonta)
- wprowadzone informacje zapisują się w lokalnej bazie danych Sqlite
- wszystkie wprowadzone notatki można zobaczyć w Activity uruchamianej na głównym ekranie. Activity zawiera ListView, korzystające z CustomArrayAdaptera


1. porządek w projekcie - opcjonalnie - jeśli się lubi porządek

podziel klasy projektu na pakiety (New / package) i przeciągnij do nich swoje klasy

- Activities
- Adapters
- Helpers


2. Dialog z własnym XML-em, inflater - wprowadzanie danych do bazy

przycisk edytuj obok zdjęcia wywołuje Dialog, z zaprojektowanym w osobnym pliku xml layoutem

res / New / Android resource file / podajemy nazwę np note_inputs_xml

xml zawiera

- pola EditText dla tytułu i treści notatki
- LinearLayout dla wybrania kolorystyki


dodanie layoutu do Dialoga:

View editView = View.inflate(context, R.layout.note_inputs_xml, null);
alert.setView(editView);kopiuj


przykładowe wyszukanie EditText w xmlu

EditText et1 = (EditText) editView.findViewById(R.id.et1);kopiuj

po naciśnięciu OK w dialogu, do bazy ma się dopisać nowy rekord, czyli wywołać funkcja insert z klasy DatabaseManager
która zostanie omówiona później

3. Kolory

najlepiej wykonać tablicę jak poniżej

String [] colors = {"#ff0000", "#00ff00",...};kopiuj

i na jej podstawie dynamicznie wygenerować dowolne View

po drodze być może będzie potrzebna funkcja

Color.parseColor("#ff0000")kopiuj
 
4. klasa DatabaseManager - test działania

Utwórz klasę

DatabaseManager extends SQLiteOpenHelper{}kopiuj

Będzie ona zawierać wszystkie potrzebne operacje na lokalnej bazie danych.
Dodaj (Generate) konstruktor i dwie dziedziczone (implements) metody onCreate, onUpgrade

w onCreate wpisz przykładowe zapytanie sql, tworzące tabelę


db.execSQL("CREATE TABLE tabela1 (_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 'a' TEXT, 'b' TEXT)");kopiuj

onUpgrade wykonuje się gdy zmienimy strukturę bazy, np typ danych lub dodamy dodatkowe pole

db.execSQL("DROP TABLE IF EXISTS tabela1");
onCreate(db);kopiuj


utworzenie obiektu klasy DatabaseManager, w tej Activity w której chcemy zapisywać notatki:

DatabaseManager db = new DatabaseManager (
   MyActivity.this, // activity z galerią zdjęć
   "NotatkiNazwiskoImie.db", // nazwa bazy
   null,
   1 //wersja bazy, po zmianie schematu bazy należy ją zwiększyć
);kopiuj


warto zwalniać zasoby bazy w szczególnych sytuacjach, w zdarzeniach onDestroy i onPause

db.close();kopiuj

testowe dodanie danych do tabeli - insert - dopiero wtedy można podglądać zawartość bazy danych (pkt 3)
poniższą funkcję dodajemy w klasie DatabaseManager


public boolean insert(String a, String b){

   SQLiteDatabase db = this.getWritableDatabase();

   ContentValues contentValues = new ContentValues();
   contentValues.put("a", a);
   contentValues.put("b", b);
      
   db.insertOrThrow("tabela1", null, contentValues); // gdy insert się nie powiedzie, będzie błąd
   db.close();
   return true;
}kopiuj


5. Jak podejrzeć zawartość bazy danych Sqlite

dodaj poniższą linię w obiekcie dependencies w pliku
Gradle scripts / build.gradle Module app (w widoku Android), potem kliknij 'sync now' w prawym górnym rogu

implementation 'com.amitshekhar.android:debug-db:1.0.0'kopiuj

wyloguj w MainActivity:

Log.d("xxx", DebugDB.getAddressLog());kopiuj

uruchom w przeglądarce uzyskany adres IP telefonu w sieci lokalnej
pojawia się manager baz danych podłączonego urządzenia, w którym można testować polecenia sql przed ich implementacją wewnątrz projektu


dokumentacja biblioteki

https://github.com/amitshekhariitbhu/Android-Debug-Database


6. Select - klasa Note

Select (pobranie danych z bazy) wymaga przygotowania osobnej klasy będącej szkieletem na dane naszej notatki
Poniżej utworzymy przykładowa klasę na dane, zawierająca pola a i b, będące reprezentacją kolumn a i b w tabeli
Utwórz klasę Note i dodaj do niej dwa prywatne pola a i b


private String a;
private String b;kopiuj


potem Generate konstruktor, zaznacz oba pola i ok

mamy konstruktor:

public Note(String a, String b) {
   this.a = a;
   this.b = b;
}kopiuj


potem Generate getter / setter, zaznacz oba pola i ok

mamy gettery / settery:

public String getA() {
   return a;
}

public void setA(String a) {
   this.a = a;
}

public String getB() {
   return b;
}

public void setB(String b) {
   this.b = b;
}kopiuj


listę obiektów tej klasy będziemy zwracać z funkcji, zawartej w DatabaseManager

public ArrayList<Note> getAll(){
   SQLiteDatabase db = this.getReadableDatabase();
   ArrayList<Note> notes = new ArrayList<>();
   Cursor result = db.rawQuery("SELECT * FROM tabela1" , null);
   while(result.moveToNext()){
      notes.add( new Note(
         result.getString(result.getColumnIndex("a")),
         result.getString(result.getColumnIndex("b"))
                   
   ));

   }
   return notes;
}
kopiuj


dokumentacja

http://sqlite.org/


7. ListView i CustomArrayAdapter - lista notatek

poniższy opis to powtórka z poprzedniej lekcji, CustomArrayAdapter będzie działał tak samo jak ten do listy zdjęć w galerii
jedyna różnica to ArrayList przechowujący obiekty naszej klasy Note, a nie File czy String

Najpierw w xmlu tworzymy wiersz dla ListView, wiersz ma zawierać obrazek i  trzy TextView

do wyświetlenia i edycji danych z bazy utworzymy kolejne Activity (NotesActivity), z ListView, oraz utworzymy klasę dziedziczącą z ArrayAdapter


mój pakiet / New / Java class / kopiuj

Nazwa NotesArrayAdapter

dodajemy z czego dziedziczy (extends ArrayAdapter) i dostajemy


public class NotesArrayAdapter extends ArrayAdapter {}kopiuj

z menu kontekstowego (alt + insert) wybieramy

Generate / Constructor i wybieramy konstruktor z trzema parametrami

Context context, int resource, ArrayList objects

w klasie Adaptera dodajemy zmienne

private ArrayList<Note> _list
private Context _context;
private int _resource;kopiuj


które ustalamy w konstruktorze, aby z nich potem korzystać

this._list = objects;
this._context = context;
this._resource = resource;kopiuj


w klasie wpisujemy nazwę funkcji getView, Ctrl + spacja i dostajemy metodę zwracającą zawartość layoutu komórki którą stworzyliśmy w xml-u

@Override
    public View getView(int position, View convertView, ViewGroup parent) {
        return super.getView(position, convertView, parent);
    }kopiuj


usuwamy return-a i w ciele funkcji getView wpisujemy kod


// inflater - klasa konwertująca xml na kod javy
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.wiersz_layoutu_w_xml, null);
// convertView = inflater.inflate(_resource, null);
// szukamy każdego TextView w layoucie

TextView tv1 = (TextView) convertView.findViewById(R.id.tv1);
tv1.setText("tekst pobrany z listy, getterem");

// gdybyśmy chcieli klikać Imageview wewnątrz wiersza:
ImageView iv1 = (ImageView) convertView.findViewById(R.id.iv2);
iv1.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
       // klik w obrazek
}
});
      
return convertView;kopiuj



przypisanie adaptera do ListView w Activity

NotesArrayAdapter adapter = new NotesArrayAdapter(
   AnyActivity.this,
   R.layout.note_row,
   arraylist_z_danymi_z_bazy_danych
);
listView1.setAdapter(adapter);kopiuj