Różnice

Różnice między wybraną wersją a wersją aktualną.

Odnośnik do tego porównania

Both sides previous revision Poprzednia wersja
Nowa wersja
Poprzednia wersja
pl:dydaktyka:ztb:2011:projekty:przystanki:start [2011/09/11 17:31]
ztb2011
pl:dydaktyka:ztb:2011:projekty:przystanki:start [2019/06/27 15:50] (aktualna)
Linia 57: Linia 57:
 ====== 1.6 Data Flow Diagram ====== ====== 1.6 Data Flow Diagram ======
  
 +===== Data Flow Diagram - poziom zerowy =====
  
 +{{:​pl:​dydaktyka:​ztb:​2011:​projekty:​przystanki:​dfd01.jpg|}}
 +
 +===== Data Flow Diagram - poziom pierwszy =====
 +
 +{{:​pl:​dydaktyka:​ztb:​2011:​projekty:​przystanki:​dfd11.jpg|}}
  
 ====== 1.7 Wybór encji (obiektów) i ich atrybutów ====== ====== 1.7 Wybór encji (obiektów) i ich atrybutów ======
  
-  - Przystanki +  - Stops 
-    - przystanek_id ​(int) PK +    - stop_id ​(int) PK 
-    - lokalizacjaX ​(real) +    - localisationX ​(real) 
-    - lokalizacjaY ​(real) +    - localisationY ​(real) 
-    - nazwa (text)+    - name (text)
  
-  - Linie 
-    - linia_id (int) PK 
-    - numer (int) 
-    - skad (int) FK (references Przystanki(przystanek_id)) 
-    - dokad (int) FK (references Przystanki(przystanek_id)) 
-    - oznaczenia(txt) 
  
-  - Połączenie +  - Lines 
-    - przystanek_id ​(int) FK (references Przystanki(przystanek_id)+    - line_id ​(int) PK 
-    - linia_id ​(int) FK (references ​Linie(linia_id)) +    - number ​(int
-    - dzien (text) +    - from_id ​(int) FK (references ​Przystanki(stop _id)) 
-    - godzina ​(int) +    - destination_id ​(intFK (references Przystanki(stop _id))
-    - minuta (int)+
  
-====== 1.8 Entity-Relationship Diagram ====== 
  
 +  - Connections
 +    - stop_id (int) FK (references Stops(stop _id))
 +    - line_id (int) FK (references Lines(line _id))
 +    - day (text)
 +    - hour (int)
 +    - minute (int)
 +    - legend (text)
 +    - order (int)
  
 +====== 1.8 Entity-Relationship Diagram ======
 +
 +{{:​pl:​dydaktyka:​ztb:​2011:​projekty:​przystanki:​erd4.jpg|}}
  
 ====== 1.9 State Transition Diagram ====== ====== 1.9 State Transition Diagram ======
  
 +{{:​pl:​dydaktyka:​ztb:​2011:​projekty:​przystanki:​std2.jpg|}}
 +
 +====== 1.9 Wzorce projektowe ======
 +
 +Poniżej opisane zostają wzorce, które zostały użyte ​ projekcie w celu zoptymalizowania jej działania, głównie pod kątem bazy danych i operacji na niej.
 +
 +===== 1.9.1 Leniwe inicjowanie =====
 +
 +Wzorzec ten polega jak największym opóźnieniu utworzeniu obiektów aż do momentu zapotrzebowania na dany obiekt. Ma to na celu ograniczenie liczby zapytań kierowanych do bazy danych co powoduje jej odciążenie i zmniejszenie zużycia zasobów co przekłada się na zminimalizowanie zapotrzebowania na energie co w przypadku aplikacji mobilnych jest priorytetową sprawą.
 +W projekcie potrzebne linie i przystanki tworzone są w 2 przypadkach
 +  - gdy musimy je wyświetlić na mapie
 +  - gdy wyszukujemy je za pomocą wyszukiwarki
 +Zatem żeby odciążyć bazę obiekty opakowujące przystanki i linie są wywoływane tylko wtedy gdy znajdują się one na ekranie mapy bądź zaczynają się na daną literę bądź cyfrę wpisaną w wyszukiwarce. Po zainicjalizowaniu przechowywane są na liście stworzonych obiektów. Gdy zajdzie potrzeba ponownego ich wykorzystania program sprawdzając listę zobaczy, że obiekty były już utworzone i nie wywoła zapytania do bazy co odciąży zasoby i przyspieszy aplikację.
 +
 +===== 1.9.2 Mapowanie danych =====
 +
 +Z reguły w przypadku użycia wzorca leniwej inicjalizacji korzysta się również z drugiego wzorca - mapowania danych. Opisuje on tabele zawarte w bazie danych w postaci obiektów języka Java prezentując odpowiednie wiersze w postaci pól. Dodatkowo klasy te zawierają w sobie pomocnicze metody do przeszukiwania bazy z poziomu encji takie jak wyszukiwanie przystanków dla danego rejonu bądź linii na daną literę alfabetu. Przez zastosowanie tego wzorca ułatwiamy programiście dostęp do danych.
 +
 +===== 1.9.2 Obiekt zapytania =====
 +
 +Ostatnim użyty przez nas wzorzec naturalnie wypływa z używania technologii androidowych. Ponieważ bazę i zapytania do niej konstruujemy za pomocą DatabaseAdaptera to programista nie jest zmuszony do bezpośredniego wpisywania kwerend SQLowych, a używa funkcji w języku Java, które je obudowują. Przyczynia się to do zwiększenia przejrzystości kodu i łatwiejszego rozszerzania aplikacji.
 +
 +
 +====== 2. Projekt logiczny ======
 +
 +====== 2.1 Projektowanie tabel, kluczy, kluczy obcych, powiązań między tabelami, indeksów, etc. w oparciu o zdefiniowany diagram ERD ======
 +
 +<​code>​
 + // STOPS
 + public static final String PK_KEY_STOPID = "​stop_id";​
 + public static final String STOPID_OPTIONS = "​INTEGER PRIMARY KEY AUTOINCREMENT";​
 + public static final String KEY_LOCALISATIONX = "​localisationX";​
 + public static final String LOCALISATIONX_OPTIONS = "REAL NOT NULL";
 + public static final String KEY_LOCALISATIONY = "​localisationy";​
 + public static final String LOCALISATIONY_OPTIONS = "REAL NOT NULL";
 + public static final String KEY_NAME = "​name";​
 + public static final String NAME_OPTIONS = "TEXT NOT NULL";
 +
 + // LINES
 + public static final String PK_KEY_LINEID = "​line_id";​
 + public static final String LINEID_OPTIONS = "​INTEGER PRIMARY KEY AUTOINCREMENT";​
 + public static final String KEY_NUMBER = "​number";​
 + public static final String NUMBER_OPTIONS = "​INTEGER NOT NULL";
 + public static final String FK_KEY_FROMID = "​from_id";​
 + public static final String FROMID_OPTIONS = "​INTEGER NOT NULL";
 + public static final String FK_KEY_DESTINATIONID = "​destination_id";​
 + public static final String DESTINATIONID_OPTIONS = "​INTEGER NOT NULL";
 +
 + // CONNECTIONS
 + public static final String FK_KEY_STOPID = "​stop_id";​
 + public static final String STOPID_FK_OPTIONS = "​INTEGER NOT NULL";
 + public static final String FK_KEY_LINEID = "​line_id";​
 + public static final String LINEID_FK_OPTIONS = "​INTEGER NOT NULL";
 + public static final String KEY_ORDERID = "​order_id";​
 + public static final String ORDERID_OPTIONS = "​INTEGER NOT NULL";
 + public static final String KEY_DAY = "​day";​
 + public static final String DAY_OPTIONS = "TEXT NOT NULL";
 + public static final String KEY_HOUR = "​hour";​
 + public static final String HOUR_OPTIONS = "​INTEGER NOT NULL";
 + public static final String KEY_MINUTE = "​minute";​
 + public static final String MINUTE_OPTIONS = "​INTEGER NOT NULL";
 + public static final String KEY_LEGEND = "​legend";​
 + public static final String LEGEND_OPTIONS = "​TEXT";​
 +
 + // CREATE STOPS
 + private static final String CREATE_STOPS = "​create table " + TABLE_STOPS
 + + " (" + PK_KEY_STOPID + " " + STOPID_OPTIONS + ", "
 + + KEY_LOCALISATIONX + " " + LOCALISATIONX_OPTIONS + ", "
 + + KEY_LOCALISATIONY + " " + LOCALISATIONY_OPTIONS + ", " + KEY_NAME
 + + " " + NAME_OPTIONS + "​);";​
 +
 + // CREATE LINES
 + private static final String CREATE_LINES = "​create table " + TABLE_LINES
 + + " (" + PK_KEY_LINEID + " " + LINEID_OPTIONS + ", " + KEY_NUMBER
 + + " " + NUMBER_OPTIONS + ", " + FK_KEY_FROMID + " "
 + + FROMID_OPTIONS + ", " + FK_KEY_DESTINATIONID + " "
 + + DESTINATIONID_OPTIONS + ", " + "​FOREIGN KEY(" + FK_KEY_FROMID
 + + ") REFERENCES " + TABLE_STOPS + "​("​ + PK_KEY_STOPID + "), "
 + + "​FOREIGN KEY(" + FK_KEY_DESTINATIONID + ") REFERENCES "
 + + TABLE_STOPS + "​("​ + PK_KEY_STOPID + "​)"​ + "​);";​
 +
 + // CREATE CONNECTIONS
 + private static final String CREATE_CONNECTIONS = "​create table "
 + + TABLE_CONNECTIONS + " (" + FK_KEY_STOPID + " "
 + + STOPID_FK_OPTIONS + ", " + FK_KEY_LINEID + " "
 + + LINEID_FK_OPTIONS + ", " + KEY_ORDERID + " " + ORDERID_OPTIONS
 + + ", " + KEY_DAY + " " + DAY_OPTIONS + ", " + KEY_HOUR + " "
 + + HOUR_OPTIONS + ", " + KEY_MINUTE + " " + MINUTE_OPTIONS + ", "
 + + KEY_LEGEND + " " + LEGEND_OPTIONS + ", " + "​FOREIGN KEY("
 + + FK_KEY_STOPID + ") REFERENCES " + TABLE_STOPS + "​("​
 + + PK_KEY_STOPID + "), " + "​FOREIGN KEY(" + FK_KEY_LINEID
 + + ") REFERENCES " + TABLE_LINES + "​("​ + PK_KEY_LINEID + "​)"​ + "​);";​
 +</​code>​
 +
 +W języku SQL kwerendy te wyglądją następująco:​
 +
 +<​code>​
 +CREATE TABLE stops (
 + stop_id INTEGER PRIMARY KEY AUTOINCREMENT, ​
 + localisationX REAL NOT NULL, localisationy REAL NOT NULL, 
 + name TEXT NOT NULL);
 +
 +CREATE TABLE lines (
 + line_id INTEGER PRIMARY KEY AUTOINCREMENT, ​
 + number INTEGER NOT NULL, from INTEGER NOT NULL, 
 + destination INTEGER NOT NULL, 
 + FOREIGN KEY(from) REFERENCES stops(stop_id), ​
 + FOREIGN KEY(destination) REFERENCES stops(stop_id));​
 +
 +CREATE TABLE connections (
 + stop_id INTEGER NOT NULL, 
 + line_id INTEGER NOT NULL, 
 + order_id INTEGER NOT NULL, 
 + day TEXT NOT NULL, hour INTEGER NOT NULL, 
 + minute INTEGER NOT NULL, legend TEXT, 
 + FOREIGN KEY(stop_id) REFERENCES stops(stop_id), ​
 + FOREIGN KEY(line_id) REFERENCES lines(line_id));​
 +</​code>​
 +
 +====== 2.2 Słownik pól bazy danych ======
 +
 +  - Stops
 +    - stop_id (int) PK - unikalny identyfikator przystanka
 +    - localisationX (real) - szerokość geograficzna przystanka
 +    - localisationY (real) - długość geograficzna przystanka
 +    - name (text) - nazwa przystanka
 +
 +
 +  - Lines
 +    - line_id (int) PK - unikalny identyfikator linii
 +    - number (int) - numer linii
 +    - from_id (int) FK (references Przystanki(stop _id)) - przystanek źródłowy linii
 +    - destination_id (int) FK (references Przystanki(stop _id)) - przystanek docelowy linii
 +
 +
 +  - Connections
 +    - stop_id (int) FK (references Stops(stop _id)) - referencja do identyfikatora przystanka
 +    - line_id (int) FK (references Lines(line _id)) - referencja do identyfikatora linii
 +    - day (text) - rodzaj dnia tygodnia dla tabel czasowych MPK
 +    - hour (int) - godzina dla poszczególnego elementu tabel czasowych MPK
 +    - minute (int) - minuta dla poszczególnego elementu tabel czasowych MPK
 +    - legend (text) - dodatkowe informacje dla poszczególnego elementu tabel czasowych MPK
 +    - order (int) - kolejność przejazdu przez przystanki danej linii
 +
 +====== 2.3 Analiza zależności funkcyjnych i normalizacja tabel ======
 +
 +Baza danych spełnia 1NF ponieważ każda składowa w każdej kropce jest atomowa i nie da się jej podzielić.
 +
 +Baza danych spełnia 2NF ponieważ spełnia 1NF oraz każdy element jest zależnie funkcyjny od kluczy poszczególnych tabeli (jedyną tabelą, która nie posiada klucza głównego jest tabela connections,​ jest ona tabelą asocjacyjną i nie posiada niekluczowych elementów).
 +
 +Baza danych spełnie 3NF ponieważ spełnia 2NF oraz każdy atrybut jest bezpośrednio zależny od klucza głównego w poszczególnych tabelach.
 +
 +====== 2.4 Projektowanie operacji na danych ======
 +
 +W projekcie operacje na danych przeprowadzane są dwupoziomowo. Budowa bezpośrednich zapytań jest funkcjonalnością klasy DatabaseAdapter natomiast wstępne formowanie argumentów jest zadaniem odpowiednich klas obudowujących - Stop, Line i Connection.
 +
 +===== 2.4.1 Projektowanie operacji na danych z poziomu Database Adaptera =====
 +
 +<​code>​
 + public Cursor getAllStops() {
 + String[] columns = { PK_KEY_STOPID,​ KEY_LOCALISATIONX,​
 + KEY_LOCALISATIONY,​ KEY_NAME };
 + return _database.query(TABLE_STOPS,​ columns, null, null, null, null,
 + null);
 + }
 +
 + public Cursor getAllLines() {
 + String[] columns = { PK_KEY_LINEID,​ KEY_NUMBER, FK_KEY_FROMID,​
 + FK_KEY_DESTINATIONID };
 + return _database.query(TABLE_LINES,​ columns, null, null, null, null,
 + null);
 + }
 +
 + public Cursor getAllConnections() {
 + String[] columns = { FK_KEY_STOPID,​ FK_KEY_LINEID,​ KEY_ORDERID,​
 + KEY_DAY,​ KEY_HOUR, KEY_MINUTE, KEY_LEGEND };
 + return _database.query(TABLE_CONNECTIONS,​ columns, null, null, null,
 + null, null);
 + }
 +
 + public Cursor getStop(int stopId) {
 + String[] columns = { PK_KEY_STOPID,​ KEY_LOCALISATIONX,​
 + KEY_LOCALISATIONY,​ KEY_NAME };
 + String where = PK_KEY_STOPID + "​="​ + stopId;
 + Cursor cursor = _database.query(true,​ TABLE_STOPS,​ columns, where,
 + null, null, null, null, null);
 + return cursor;
 + }
 +
 + public Cursor getStop(String name) {
 + String[] columns = { PK_KEY_STOPID,​ KEY_LOCALISATIONX,​
 + KEY_LOCALISATIONY,​ KEY_NAME };
 + String where = KEY_NAME + "= '"​ + name + "'";​
 + Cursor cursor = _database.query(true,​ TABLE_STOPS,​ columns, where,
 + null, null, null, null, null);
 + return cursor;
 + }
 +
 + public Cursor getStopsExcept(Area area, List<​Integer>​ stopIds) {
 + String[] columns = { PK_KEY_STOPID,​ KEY_LOCALISATIONX,​
 + KEY_LOCALISATIONY,​ KEY_NAME };
 + String where = area.getLeft().toString() + " < " + KEY_LOCALISATIONX
 + + " AND " + KEY_LOCALISATIONX + " < "
 + + area.getRight().toString() + " AND "
 + + area.getBottom().toString() + " < " + KEY_LOCALISATIONY
 + + " AND " + KEY_LOCALISATIONY + " < "
 + + area.getTop().toString();​
 + if (!stopIds.isEmpty()) {
 + where = where + " AND " + PK_KEY_STOPID + " NOT IN (";
 + for (Integer id : stopIds) {
 + if (!where.endsWith("​("​)) {
 + where = where + ", ";
 + }
 + where = where + id.toString();​
 + }
 + where = where + "​)";​
 + }
 + Cursor cursor = _database.query(true,​ TABLE_STOPS,​ columns, where,
 + null, null, null, null, null);
 + return cursor;
 + }
 +
 + public Cursor getLine(int lineId) {
 + String[] columns = { PK_KEY_LINEID,​ KEY_NUMBER, FK_KEY_FROMID,​
 + FK_KEY_DESTINATIONID };
 + String where = PK_KEY_LINEID + " = " + lineId;
 + Cursor cursor = _database.query(true,​ TABLE_LINES,​ columns, where,
 + null, null, null, null, null);
 + return cursor;
 + }
 +
 + public Cursor getConnection(int stopId, int lineId) {
 + String[] columns = { FK_KEY_STOPID,​ FK_KEY_LINEID,​ KEY_ORDERID,​
 + KEY_DAY,​ KEY_HOUR, KEY_MINUTE, KEY_LEGEND };
 + String where = FK_KEY_STOPID + "​="​ + stopId + " AND " + FK_KEY_LINEID
 + + "​="​ + lineId;
 + Cursor cursor = _database.query(TABLE_CONNECTIONS,​ columns,
 + where, null, null, null, null);
 + return cursor;
 + }
 +
 + public Cursor getStops(Character letter, List<​Integer>​ ids) {
 + String[] columns = { PK_KEY_STOPID,​ KEY_LOCALISATIONX,​
 + KEY_LOCALISATIONY,​ KEY_NAME };
 + String where = KEY_NAME + " LIKE '"​ + Character.toUpperCase(letter)
 + + "​%'";​
 + if (ids.size() > 0) {
 + where += PK_KEY_STOPID + " IS NOT IN (";
 + for(Integer i : ids) {
 + if(! where.endsWith("​("​)) {
 + where += ", ";
 + }
 + where += i;
 + }
 + where += "​)";​
 + }
 + return _database.query(TABLE_STOPS,​ columns, where, null, null, null,
 + KEY_NAME);​
 + }
 +
 + public Cursor getLinesByStopId(int stopId) {
 + String[] columns = {FK_KEY_LINEID};​
 + String where = FK_KEY_STOPID + "​="​ + stopId;
 + return _database.query(true ,​TABLE_CONNECTIONS,​ columns, where, null, null, null,
 + KEY_ORDERID,​ null);
 + }
 +
 + public Cursor getStopsByLineId(int lineId) {
 + String[] columns = {FK_KEY_STOPID};​
 + String where = FK_KEY_LINEID + "​="​ + lineId;
 + return _database.query(true ,​TABLE_CONNECTIONS,​ columns, where, null, null, null,
 + KEY_ORDERID,​ null);
 + }
 +
 + public Cursor getLinesByLetter(Character letter) {
 + String[] columns = { PK_KEY_LINEID,​ KEY_NUMBER, FK_KEY_FROMID,​
 + FK_KEY_DESTINATIONID };
 + String where = "​CAST("​ + KEY_NUMBER + " AS TEXT) LIKE '"​ + letter
 + + "​%'";​
 + return _database.query(TABLE_LINES,​ columns, where, null, null, null,
 + null);
 + }
 +</​code>​
 +
 +===== 2.4.2 Projektowanie operacji na danych z poziomu Stop =====
 +
 +<​code>​
 + private static Stop getStopFromCache(final int id) {
 + for (Stop stop : _stopList) {
 + if (stop.get_id() == id)
 + return stop;
 + }
 + return null;
 + }
 +
 + public static Stop getStopFromCache(String name) {
 + for (Stop stop : _stopList) {
 + if (stop.getName() == name)
 + return stop;
 + }
 + return null;
 + }
 +
 + private static Stop getStopFromCursor(final Cursor cursor) {
 + final int id = (int) cursor.getLong(cursor
 + .getColumnIndex(DatabaseAdapter.PK_KEY_STOPID));​
 + final Pair<​Double,​ Double> coordinates = new Pair<​Double,​ Double>(
 + (double) cursor.getFloat(cursor
 + .getColumnIndex(DatabaseAdapter.KEY_LOCALISATIONY)),​
 + (double) cursor.getFloat(cursor
 + .getColumnIndex(DatabaseAdapter.KEY_LOCALISATIONX)));​
 + final String name = cursor.getString(cursor
 + .getColumnIndex(DatabaseAdapter.KEY_NAME));​
 + return new Stop(id, coordinates,​ name);
 + }
 +
 + private static List<​Stop>​ changeCursorInToList(Cursor cursor) {
 + final List<​Stop>​ stops = new ArrayList<​Stop>​();​
 + if (cursor != null && cursor.moveToFirst())
 + while (true) {
 + stops.add(getStopFromCursor(cursor));​
 + if (!cursor.moveToNext())
 + break;
 + }
 + return stops;
 + }
 +
 + private static Stop getStopFromDB(final int id, final DatabaseAdapter dba) {
 + final Cursor cursor = dba.getStop(id);​
 + Stop result = null;
 + if (cursor.moveToFirst())
 + result = getStopFromCursor(cursor);​
 + cursor.close();​
 + return result;
 + }
 +
 + private static Stop getStopFromDB(final String name,
 + final DatabaseAdapter dba) {
 + final Cursor cursor = dba.getStop(name);​
 + Stop result = null;
 + if (cursor.moveToFirst())
 + result = getStopFromCursor(cursor);​
 + cursor.close();​
 + return result;
 + }
 +
 + public static Stop getStop(int id, DatabaseAdapter dba) {
 + Stop stop = getStopFromCache(id);​
 + if (stop == null) {
 + stop = getStopFromDB(id,​ dba);
 + if (stop != null) {
 + _stopList.add(stop);​
 + }
 + }
 + return stop;
 + }
 +
 + public static Stop getStop(String name, DatabaseAdapter dba) {
 + Stop stop = getStopFromCache(name);​
 + if (stop == null) {
 + stop = getStopFromDB(name,​ dba);
 + if (stop != null) {
 + _stopList.add(stop);​
 + }
 + }
 + return stop;
 + }
 +
 + public static Stop getStop(final Pair<​Double,​ Double> coordination,​
 + final DatabaseAdapter dba) {
 + Double radius = BASE_RADIUS;​
 + Area area = null;
 + Stop stop = null;
 + while (stop == null || radius < 5 * BASE_RADIUS) {
 + Pair<​Double,​ Double> topLeft = new Pair<​Double,​ Double>(
 + coordination.first + radius, coordination.second - radius);
 + Pair<​Double,​ Double> bottomRight = new Pair<​Double,​ Double>(
 + coordination.first - radius, coordination.second + radius);
 + area = new Rectangle(topLeft,​ bottomRight);​
 + final List<​Stop>​ stopsFromDB = getStops(area,​ dba);
 + _stopList.addAll(stopsFromDB);​
 + stop = getStopFromCache(coordination,​ radius);
 + radius = radius + BASE_RADIUS;​
 + }
 + return stop;
 + }
 +
 + private static Stop getStopFromCache(
 + final Pair<​Double,​ Double> coordination,​ final Double radius) {
 + Pair<​Double,​ Stop> result = new Pair<​Double,​ Stop>​(Double.MAX_VALUE,​
 + null);
 + for (Stop stop : _stopList) {
 + Double distance = Math.sqrt(Math.pow(stop.get_coordinates().first
 + - coordination.first,​ 2)
 + + Math.pow(stop.get_coordinates().second
 + - coordination.second,​ 2));
 + if (distance < radius && distance < result.first) {
 + result = new Pair<​Double,​ Stop>​(distance,​ stop);
 + }
 + }
 + return result.second;​
 + }
 +
 + private static List<​Stop>​ getStopsFromCache(final Area area) {
 + final List<​Stop>​ stopsInArea = new ArrayList<​Stop>​();​
 + for (Stop stop : _stopList) {
 + if (area.isPointInArea(stop.get_coordinates()))
 + stopsInArea.add(stop);​
 + }
 + return stopsInArea;​
 + }
 +
 + private static List<​Stop>​ getStopsFromCache(final String name) {
 + final List<​Stop>​ stopsByLetter = new ArrayList<​Stop>​();​
 + for (Stop stop : _stopList) {
 + if (stop.getName().toUpperCase().startsWith(name.toUpperCase()))
 + stopsByLetter.add(stop);​
 + }
 + return stopsByLetter;​
 + }
 +
 + private static List<​Stop>​ getStopsFromDB(final Area area,
 + final DatabaseAdapter dba) {
 + final List<​Integer>​ except = new ArrayList<​Integer>​();​
 + final List<​Stop>​ stopsInArea = getStopsFromCache(area);​
 + for (Stop stop : stopsInArea)
 + except.add(stop.get_id());​
 + Cursor cursor = dba.getStopsExcept(area,​ except);
 + final List<​Stop>​ result = changeCursorInToList(cursor);​
 + cursor.close();​
 + return result;
 + }
 +
 + private static int getStopIdFromCursor(final Cursor cursor) {
 + return (int) cursor.getLong(cursor
 + .getColumnIndex(DatabaseAdapter.FK_KEY_STOPID));​
 + }
 +
 + private static List<​Stop>​ getStopsByLineIdFromDB(final int lineId,
 + final DatabaseAdapter dba) {
 + final List<​Stop>​ stops = new ArrayList<​Stop>​();​
 + final Cursor cursor = dba.getStopsByLineId(lineId);​
 + if (cursor != null && cursor.moveToFirst())
 + while (true) {
 + Stop result = getStop(getStopIdFromCursor(cursor),​ dba);
 + stops.add(result);​
 + if (!cursor.moveToNext())
 + break;
 + }
 + cursor.close();​
 + return stops;
 + }
 +
 + private static List<​Stop>​ getStopsFromDB(final Character letter,
 + final DatabaseAdapter dba) {
 + List<​Integer>​ intsList = new ArrayList<​Integer>​();​
 + List<​Stop>​ stopsList = getStopsFromCache(letter.toString().toUpperCase());​
 + for(Stop s : stopsList) {
 + intsList.add(s.get_id());​
 + }
 + Cursor cursor = dba.getStops(letter,​ intsList);
 + List<​Stop>​ sl = changeCursorInToList(cursor);​
 + cursor.close();​
 + return sl;
 + }
 +
 + public static List<​Stop>​ getStops(final Area area, final DatabaseAdapter dba) {
 + if (area != null) {
 + final List<​Stop>​ stops = getStopsFromDB(area,​ dba);
 + _stopList.addAll(stops);​
 + }
 + return getStopsFromCache(area);​
 + }
 +
 + public static List<​Stop>​ getStops(final String name,
 + final DatabaseAdapter dba) {
 + Character letter = null;
 + if (name.length() > 0) {
 + letter = name.toUpperCase().charAt(0);​
 + }
 + if (letter == null) {
 + return null;
 + }
 + if (!_letters.contains(letter)) {
 + final List<​Stop>​ stops = getStopsFromDB(letter,​ dba);
 + _stopList.addAll(stops);​
 + _letters.add(letter);​
 + }
 + return getStopsFromCache(name);​
 + }
 +
 + public static List<​Stop>​ getStopsByLineId(int lineId, DatabaseAdapter dba) {
 + return getStopsByLineIdFromDB(lineId,​ dba);
 + }
 +</​code>​
 +
 +===== 2.4.3 Projektowanie operacji na danych z poziomu Line =====
 +
 +<​code>​
 + private static Line getLineFromCache(final int id) {
 + for (Line line : _lineList) {
 + if (line.get_id() == id)
 + return line;
 + }
 + return null;
 + }
 +
 + private static List<​Line>​ getLinesFromCache(final String name) {
 + final List<​Line>​ linesByLetter = new ArrayList<​Line>​();​
 + for (Line line : _lineList) {
 + if (new Integer(line.getNumber()).toString().toUpperCase()
 + .startsWith(name.toUpperCase()))
 + linesByLetter.add(line);​
 + }
 + return linesByLetter;​
 + }
 +
 + private static Line getLineFromCursor(final Cursor cursor) {
 + final int id = (int) cursor.getLong(cursor
 + .getColumnIndex(DatabaseAdapter.PK_KEY_LINEID));​
 + final int number = (int) cursor.getLong(cursor
 + .getColumnIndex(DatabaseAdapter.KEY_NUMBER));​
 + final int from = (int) cursor.getLong(cursor
 + .getColumnIndex(DatabaseAdapter.FK_KEY_FROMID));​
 + final int destination = (int) cursor.getLong(cursor
 + .getColumnIndex(DatabaseAdapter.FK_KEY_DESTINATIONID));​
 + return new Line(id, number, from, destination);​
 + }
 +
 + private static int getLineIdFromCursor(final Cursor cursor) {
 + return (int) cursor.getLong(cursor
 + .getColumnIndex(DatabaseAdapter.FK_KEY_LINEID));​
 + }
 +
 + private static List<​Line>​ getLineByStopIdFromDB(final int stopId,
 + final DatabaseAdapter dba) {
 + final List<​Line>​ lines = new ArrayList<​Line>​();​
 + final Cursor cursor = dba.getLinesByStopId(stopId);​
 + if (cursor != null && cursor.moveToFirst())
 + while (true) {
 + Line result = getLine(getLineIdFromCursor(cursor),​ dba);
 + lines.add(result);​
 + if (!cursor.moveToNext())
 + break;
 + }
 + cursor.close();​
 + return lines;
 + }
 +
 + private static Line getLineFromDB(final int id, final DatabaseAdapter dba) {
 + final Cursor cursor = dba.getLine(id);​
 + Line result = null;
 + if (cursor.moveToFirst())
 + result = getLineFromCursor(cursor);​
 + cursor.close();​
 + return result;
 + }
 +
 + private static List<​Line>​ changeCursorInToList(Cursor cursor) {
 + final List<​Line>​ lines = new ArrayList<​Line>​();​
 + if (cursor != null && cursor.moveToFirst())
 + while (true) {
 + lines.add(getLineFromCursor(cursor));​
 + if (!cursor.moveToNext())
 + break;
 + }
 + return lines;
 + }
 +
 + private static List<​Line>​ getLinesFromDB(final Character letter,
 + final DatabaseAdapter dba) {
 + List<​Integer>​ intsList = new ArrayList<​Integer>​();​
 + List<​Line>​ linesList = getLinesFromCache(letter.toString().toUpperCase());​
 + for(Line s : linesList) {
 + intsList.add(s.get_id());​
 + }
 + Cursor cursor = dba.getLinesByLetter(letter);​
 + List<​Line>​ ll = changeCursorInToList(cursor);​
 + cursor.close();​
 + return ll;
 + }
 +
 + public static Line getLine(int id, DatabaseAdapter dba) {
 + Line line = getLineFromCache(id);​
 + if (line == null) {
 + line = getLineFromDB(id,​ dba);
 + if (line != null) {
 + _lineList.add(line);​
 + }
 + }
 + return line;
 + }
 +
 + public static List<​Line>​ getLines(final String name,
 + final DatabaseAdapter dba) {
 + Character letter = null;
 + if (name.length() > 0) {
 + letter = name.toUpperCase().charAt(0);​
 + }
 + if (letter == null) {
 + return null;
 + }
 + if (!_letters.contains(letter)) {
 + final List<​Line>​ stops = getLinesFromDB(letter,​ dba);
 + _lineList.addAll(stops);​
 + _letters.add(letter);​
 + }
 + return getLinesFromCache(name);​
 + }
 +
 + public static List<​Line>​ getLinesByStopId(int stopId, DatabaseAdapter dba) {
 + return getLineByStopIdFromDB(stopId,​ dba);
 + }
 +</​code>​
 +
 +===== 2.4.4 Projektowanie operacji na danych z poziomu Connection =====
 +
 +<​code>​
 + private static Connection getConnectionFromCache(final int stopId,
 + final int lineId) {
 + for (Connection conn : _connectionList) {
 + if (conn.get_stopId() == stopId && conn.get_lineId() == lineId)
 + return conn;
 + }
 + return null;
 + }
 +
 + private void addTime(Pair<​String,​ Pair<​Integer,​ Integer>>​ time) {
 + if (_TimeTable.containsKey(time.first)) {
 + List<​Pair<​Integer,​ Integer>>​ timeList = _TimeTable.get(time.first);​
 + timeList.add(time.second);​
 + _TimeTable.put(time.first,​ timeList);
 + } else {
 + List<​Pair<​Integer,​ Integer>>​ timeList = new ArrayList<​Pair<​Integer,​ Integer>>​();​
 + timeList.add(time.second);​
 + _TimeTable.put(time.first,​ timeList);
 + }
 + }
 +
 + private static Connection getConnectionFromCursor(final Cursor cursor) {
 + final int stopId = (int) cursor.getLong(cursor
 + .getColumnIndex(DatabaseAdapter.FK_KEY_STOPID));​
 + final int lineId = (int) cursor.getLong(cursor
 + .getColumnIndex(DatabaseAdapter.FK_KEY_LINEID));​
 + final int orderId = (int) cursor.getLong(cursor
 + .getColumnIndex(DatabaseAdapter.KEY_ORDERID));​
 + final String legend = cursor.getString(cursor
 + .getColumnIndex(DatabaseAdapter.KEY_LEGEND));​
 + return new Connection(stopId,​ lineId, orderId, legend);
 + }
 +
 + private static Pair<​String,​ Pair<​Integer,​ Integer>>​ getTimeFromCursor(
 + final Cursor cursor) {
 + final String day = cursor.getString(cursor
 + .getColumnIndex(DatabaseAdapter.KEY_DAY));​
 + final int hour = (int) cursor.getLong(cursor
 + .getColumnIndex(DatabaseAdapter.KEY_HOUR));​
 + final int minute = (int) cursor.getLong(cursor
 + .getColumnIndex(DatabaseAdapter.KEY_MINUTE));​
 + return new Pair<​String,​ Pair<​Integer,​ Integer>>​(day,​
 + new Pair<​Integer,​ Integer>​(hour,​ minute));
 + }
 +
 + private static Connection getConnectionFromDB(final int stopId,
 + final int lineId, final DatabaseAdapter dba) {
 + final Cursor cursor = dba.getConnection(stopId,​ lineId);
 + Connection result = null;
 + if (cursor.moveToFirst())
 + result = getConnectionFromCursor(cursor);​
 + while (true) {
 + result.addTime(getTimeFromCursor(cursor));​
 + if (!cursor.moveToNext())
 + break;
 + }
 + cursor.close();​
 + return result;
 + }
 +
 + public static Connection getConnection(int stopId, int lineId,
 + DatabaseAdapter dba) {
 + Connection conn = getConnectionFromCache(stopId,​ lineId);
 + if (conn == null) {
 + conn = getConnectionFromDB(stopId,​ lineId, dba);
 + if (conn != null) {
 + _connectionList.add(conn);​
 + }
 + }
 + return getConnectionFromDB(stopId,​ lineId, dba);
 + }
 +</​code>​
 +
 +
 +====== 3. Raport końcowy ======
 +
 +====== 3.1 Implementacja bazy danych ======
 +
 +Baza danych aplikacji mobilnej została zaimplementowana z wykorzystaniem motoru bazy SQLite. Elementy tworzące bazę, zostały zaprezentowane w projekcie logicznym.
 +
 +====== 3.2 Interfejsy do obsługi danych ======
 +
 +W aplikacji istnieją następujące przepływy danych przez widoku (aktywności Androida):
 +
 +  - Mapa
 +    - odnalezienie pobliskiego przystanku na mapie (widok mapy)
 +    - wybranie odpowiadającej użytkownikowi linii (widok linii dla danego przystanka)
 +    - sprawdzenie godzin odjazdów danej linii z danego przystanka (widok połączenia)
 +  - Wyszukiwarka przystanków
 +    - wyszukanie przystanku po nazwie (widok wyszukiwarki)
 +    - wybranie odpowiadającej użytkownikowi linii (widok linii dla danego przystanka)
 +    - sprawdzenie godzin odjazdów danej linii z danego przystanka (widok połączenia)
 +  - Wyszukiwarka przystanków
 +    - wyszukanie przystanku po numerze (widok wyszukiwarki)
 +    - wybranie odpowiadającego użytkownikowi przystanku (widok przystanków dla danej linii)
 +    - sprawdzenie godzin odjazdów danej linii z danego przystanka (widok połączenia)
 +
 +Każdorazowo pobierane są odpowiednie dane z bazy (przystanki,​ linie, połączenia) ze zminimalizowanym obciążeniem bazy danych poprzez zastosowanie interfejsu lazy load (dane inicjowane są dopiero gdy są potrzebne i są przechowywane żeby uniknąć niepotrzebnych zapytać do bazy).
 +
 +Widok mapy
 +
 +{{:​pl:​dydaktyka:​ztb:​2011:​projekty:​przystanki:​mapa.jpg|}}
 +
 +Widok linii przy wyszukiwaniu
 +
 +{{:​pl:​dydaktyka:​ztb:​2011:​projekty:​przystanki:​search.jpg|}}
 +
 +Widok linii dla danego przystanka
 +
 +{{:​pl:​dydaktyka:​ztb:​2011:​projekty:​przystanki:​linie.jpg|}}
 +
 +====== 3.3 Dalszy rozwój aplikacji mobilnej ======
 +
 +Aplikacja aktualnie spełnia wszystkie podstawowe założenia,​ które założyliśmy w fazie projektowej. W przyszłości planujemy rozwój:
 +  - wyznaczanie tras dojścia do najbliższych przystanków
 +  - wyświetlanie czasu odjazdów dla aktualnej i zadanej pory
 +  - wyświetlanie tras przejazdu danej linii
 +
 +====== 3.4 Wnioski ======
 +
 +Google dostarczyło nam narzędzie, które jest łatwo przyswajalne i dobrze opisane w dokumentacji wraz z licznymi przykładami użycia. Sprawiło to, że napisanie aplikacji na system Android nie sprawiło zespołowi problemów.
 +SQLite jako baza danych dla aplikacji mobilnych wydaje się odpowiednim wyborem. Nie dostarcza co prawda zbyt wielu funkcjonalności,​ ale jest prosta w obsłudze, a do tego lekka (co powoduje małe zużycie energii co w aplikacjach mobilnych jest kluczowe) i szybka.
 +
 +====== 3.4 Literatura ======
  
 +  - http://​developer.android.com/​index.html
 +  - http://​www.sqlite.org/​docs.html
pl/dydaktyka/ztb/2011/projekty/przystanki/start.1315755081.txt.gz · ostatnio zmienione: 2019/06/27 15:57 (edycja zewnętrzna)
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0