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