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/18 15:21]
ztb2011
pl:dydaktyka:ztb:2011:projekty:przystanki:start [2019/06/27 15:50] (aktualna)
Linia 59: Linia 59:
 ===== Data Flow Diagram - poziom zerowy ===== ===== Data Flow Diagram - poziom zerowy =====
  
-{{:​pl:​dydaktyka:​ztb:​2011:​projekty:​przystanki:​dfd0.jpg|}}+{{:​pl:​dydaktyka:​ztb:​2011:​projekty:​przystanki:​dfd01.jpg|}}
  
 ===== Data Flow Diagram - poziom pierwszy ===== ===== Data Flow Diagram - poziom pierwszy =====
  
-{{:​pl:​dydaktyka:​ztb:​2011:​projekty:​przystanki:​dfd1.jpg|}} +{{:​pl:​dydaktyka:​ztb:​2011:​projekty:​przystanki:​dfd11.jpg|}}
- +
-===== Data Flow Diagram - poziom drugi ===== +
- +
-{{:​pl:​dydaktyka:​ztb:​2011:​projekty:​przystanki:​dfd2.jpg|}}+
  
 ====== 1.7 Wybór encji (obiektów) i ich atrybutów ====== ====== 1.7 Wybór encji (obiektów) i ich atrybutów ======
Linia 85: Linia 81:
  
  
-Connections+  - Connections
     - stop_id (int) FK (references Stops(stop _id))     - stop_id (int) FK (references Stops(stop _id))
     - line_id (int) FK (references Lines(line _id))     - line_id (int) FK (references Lines(line _id))
Linia 93: Linia 89:
     - legend (text)     - legend (text)
     - order (int)     - order (int)
- 
  
 ====== 1.8 Entity-Relationship Diagram ====== ====== 1.8 Entity-Relationship Diagram ======
Linia 101: Linia 96:
 ====== 1.9 State Transition Diagram ====== ====== 1.9 State Transition Diagram ======
  
-{{:​pl:​dydaktyka:​ztb:​2011:​projekty:​przystanki:​std.jpg|}}+{{:​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.1316352090.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