Pobieranie prezentacji. Proszę czekać

Pobieranie prezentacji. Proszę czekać

Android WYKŁAD 4. Agenda Bazy danych – SQLite Zestawienie mapowania w LiteORM Wyświetlanie danych w ListView Pobieranie danych z sieci – Volley Zapytania.

Podobne prezentacje


Prezentacja na temat: "Android WYKŁAD 4. Agenda Bazy danych – SQLite Zestawienie mapowania w LiteORM Wyświetlanie danych w ListView Pobieranie danych z sieci – Volley Zapytania."— Zapis prezentacji:

1 Android WYKŁAD 4

2 Agenda Bazy danych – SQLite Zestawienie mapowania w LiteORM Wyświetlanie danych w ListView Pobieranie danych z sieci – Volley Zapytania GET i POST Zapytania JSON Przeglądanie obiektów JSON Wątki – Handler i AsyncTask Zakonczenie

3 Konsultacje projektów DATY: GODZINA: 15:00 – 16:30 MIEJSCE: B

4 SQLite Silnik relacyjnych baz danych oparty na plikach Wspierane przez narzędzia ORM takie jak Hibernate czy ORMLite Idealny do składowania strukturalnych danych będących w relacjach (np. listy obiektów) Wiele narzędzi do projektowania/podglądu i edycji: DB Browser for SQLite SQLiteStudio SQLite Expert

5 SQLite z ORM w Android Przykład: Aplikacja do ewidencji punktów w grze Zależności (app/build.gradle): dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.2.0' compile 'com.j256.ormlite:ormlite-android:4.48' } Gradle pobierze bibliotekę automatycznie z repozytorium, skompiluje i włączy do projektu

6 ORMLite – Model + mapowanie Modele public class Game = true) public int public Date public int = false, foreign = true, foreignAutoRefresh = true) public Player player; public Game() { } public Game(Date date, int score, Player player) { this.date = date; this.score = score; this.player = player; } } public class Player = true) public int = true) public String name; public Player(String name) { this.name = name; } public Player() { } } Automatyczne generowanie ID Klucz obcy Pusty konstruktor jest wymagany!

7 ORMLite – Model + mapowanie Skanowanie adnotacji jest bardzo kosztowne czasowo – szczególnie przy dużych bazach danych Skrypt należy uruchomić ręcznie w celu wygenerowania statycznej konfiguracji Plik res/raw/ormlite_config.txt zostanie utworzony automatycznie na podstawie adnotacji w klasach Czynność powtarzamy po każdej zmianie w modelu public class DatabaseConfigUtil extends OrmLiteConfigUtil { private static final Class [] classes = new Class[] { Player.class, Game.class }; public static void main(String[] args) throws SQLException, IOException { writeConfigFile(new File("[SCIEZKA_DO_PROJEKTU]\\app\\src\\main\\res\\raw\\orml ite_config.txt"), classes); } }

8 OrmLiteSqliteOpenHelper Klasa ułatwiająca obsługę podstawowych czynności wykonywanych na bazie danych Wymaga implementacji następujących metod: Konstruktor Ustawienie nazwy bazy, wersji, pliku z konfiguracją onCreate Zdarzenie towarzyszące stworzeniu bazy danych, czyli jakie tabele stworzyć i co mapować onUpgrade Zdarzenie towarzyszące aktualizacji bazy (kiedy zmienia się jej schemat). Miejsce na wykonanie migracji schematu.

9 OrmLiteSqliteOpenHelper - przykład public class DatabaseHelper extends OrmLiteSqliteOpenHelper { private static final String DATABASE_NAME = "scores.db"; private static final int DATABASE_VERSION = 2; private Dao gameDao; private Dao playerDao; public DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION, R.raw.ormlite_config); public void onCreate(SQLiteDatabase sqliteDatabase, ConnectionSource connectionSource) { try { TableUtils.createTable(connectionSource, Game.class); TableUtils.createTable(connectionSource, Player.class); } catch (SQLException e) { Log.e(DatabaseHelper.class.getName(), "Unable to create datbases", e); } } Przy każdej zmianie w modelach (mapowanych klasach JAVY) zmień tą wartość o jeden! Plik z bazą Data Access Object Dao

10 OrmLiteSqliteOpenHelper – przykład public void onUpgrade(SQLiteDatabase sqliteDatabase, ConnectionSource connectionSource, int oldVer, int newVer) { try { TableUtils.dropTable(connectionSource, Game.class, true); TableUtils.dropTable(connectionSource, Player.class, true); onCreate(sqliteDatabase, connectionSource); } catch (SQLException e) { Log.e(DatabaseHelper.class.getName(), "Unable to upgrade database from version " + oldVer + " to new " + newVer, e); } } public Dao getGameDao() throws SQLException { if (gameDao == null) { gameDao = getDao(Game.class); } return gameDao; } public Dao getPlayerDao() throws SQLException { if (playerDao == null) { playerDao = getDao(Player.class); } return playerDao; } Usuń tabele – ignoruj błędy Stwórz na nowo tabele Akcesory dla DAO (w razie potrzeby same inicjalizują obiekt)

11 Wizualizacja wpisów z bazy SQLITE ADAPTER LISTVIEW Pojedynczy wpis Adapter łączy obiekty bazodanowe DAO z pojedynczym wpisem na ListView Adapter jest podpięty do ListView w Activity

12 list_item – pojedynczy wpis w ListView Wymóg aby każdy widok zajął 1/3 miejsca dostępnego na szerokość

13 ORMLite – klasa Adapter Klasa łącząca widok (ListView) z obiektami DAO public class DatabaseAdapter extends ArrayAdapter { private List records; private Dao gameDao; public DatabaseAdapter(Context context, int itemView, List objects, Dao gameDao) { super(context, itemView, objects); this.records = objects; this.gameDao = gameDao; }

14 Adapter – public View getView(int position, View view, ViewGroup parent) { final Game game = records.get(position); try { gameDao.refresh(game); } catch (Exception e) { e.printStackTrace(); } if (view == null) { view = LayoutInflater.from(getContext()).inflate(R.layout.list_item, parent, false); } TextView playerTv = (TextView) view.findViewById(R.id.player_tv); playerTv.setText(game.player.name); SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); TextView dateTv = (TextView) view.findViewById(R.id.date_tv); dateTv.setText(dateFormat.format(game.date)); TextView scoreTv = (TextView) view.findViewById(R.id.score_tv); scoreTv.setText(String.valueOf(game.score)); return view; } } W przypadku relacji – odświeżamy również obiekty dołączone przez klucze obce Renderujemy pojedynczy widok – same kontrolki Wstawiamy dane w widoku na layoucie reprezentującym jeden wpis na liście

15 MainActivity - widok TableLayout z ListView do wyświetlania danych

16 MainActivity – dostęp do bazy private void connectToDatabase(){ Dao gameDao = null; try { gameDao = getHelper().getGameDao(); games = gameDao.queryForAll(); ListView lvScore = (ListView) findViewById(R.id.scoreLv); lvScore.setAdapter(new DatabaseAdapter(MainActivity.this, R.layout.list_item, games, gameDao)); } catch (SQLException e) { e.printStackTrace(); } } private DatabaseHelper getHelper() { if (databaseHelper == null) { databaseHelper = OpenHelperManager.getHelper(this,DatabaseHelper.class); } return databaseHelper; protected void onDestroy() { super.onDestroy(); if (databaseHelper != null) { OpenHelperManager.releaseHelper(); databaseHelper = null; } } Metoda dołącza Adapter do ListView Helper do helpera Zwolnienie dostępu do bazy po opuszczeniu Activity

17 MainActivity – dodawanie rekordów public void addNewPlayer(View view) { EditText playerNameEt = (EditText) findViewById(R.id.playerNameEt); String playerName = playerNameEt.getText().toString(); int score = new Random().nextInt(100); Date date = new Date(); try { final Dao playerDao = getHelper().getPlayerDao(); List playersList = playerDao.queryBuilder().where().eq("name", playerName).query(); Player player = null; if(playersList.size() == 0){ player = new Player(playerName); playerDao.create(player); } else { player = playersList.get(0); } final Dao gameDao = getHelper().getGameDao(); Game game = new Game(date, score, player); gameDao.create(game); refreshDatabase(); } catch (SQLException ex){ Log.i("MainActivity", ex.getMessage()); } } Pobranie danych z widoków Losowe punkty Szukamy gracza o podanym imieniu Jeśli go znajdziemy, to dopisujemy mu wynik Jeśli nie, to tworzymy takiego gracza Dodajemy

18 MainActivity – odświeżanie ListView private void refreshDatabase() throws SQLException{ final Dao gameDao = getHelper().getGameDao(); games = gameDao.queryForAll(); ListView lvScore = (ListView) findViewById(R.id.scoreLv); final DatabaseAdapter adapter = (DatabaseAdapter) lvScore.getAdapter(); adapter.clear(); adapter.addAll(games); } Odświeżenie adaptera po dodaniu nowego wpisu

19 Efekt

20 Uruchamianie Android Device Monitor Lub bezpośrednio przez: \android-sdk\tools\lib\monitor-x86_64\ w moim przypadku: c:\Users\Krzysztof\AppData\Local\Android\android-sdk\tools\lib\monitor-x86_64

21 Pobieranie bazy danych na komputer /data/data/[namespace]/databases/[nazwa.db]

22 SQLite DBBrowser – podgląd baz danych

23 JSON – JavaScript Object Notation Lekki format serializacji obiektów. Bardzo popularny w zastosowaniach sieciowych Zbudowany na zasadzie: "klucz" : "wartość", każdy element oddzielony przecinkami Podstawowe oznaczenia: [ ] – lista, elementy oddzielone przecinkami { } – obiekt [{ "name": "Krzysztof", "surname": "Bzowski", "classes": ["Programowanie w JAVA", "Systemy Wbudowane", "Inżynieria internetu"], "experiance": 5 }, { "name": "Gorzegorz", "surname": "Smyk", "classes": ["Programowanie obiektowe"], "experiance": 5 }, { "name": "Mateusz", "surname": "Sitko", "classes": ["Podstawy programowania", "Modelowanie wieloskalowe"], "experiance": 5 }] TEKSTSTRUKTURA

24 Volley Biblioteka sieciowa przeznaczona do efektywnej i szybkiej komunikacji poprzez protokół HTTP Pozwala na asynchroniczną pracę (bez blokowania GUI) Mnóstwo innych zalet: Docelowo ma zastąpić przestarzałe klasy: HttpUrlConnection i HttpClient Uprawnienia do dostępu do sieci: AndroidManifest.xml Zależności do projektu: \app\build.gradle: Gradle sam pobierze i skompiluje zależności! dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.2.0' compile 'com.mcxiaoke.volley:library:1.0.19' }

25 Volley – pierwsze starcie – pobranie strony www public void connectBtnClick(View view) { RequestQueue queue = Volley.newRequestQueue(this); String url = "http://www.google.com"; StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener () public void onResponse(String response) { // metoda uruchomi się asnychronicznie jeśli treść strony zostanie pobrana // zawartość (HTML) znajduje się w zmiennej response } }, new Response.ErrorListener() public void onErrorResponse(VolleyError error) { // Miejsce na obsługę błędów } }); queue.add(stringRequest); } GET, POST, PUT, DELETE…

26 Volley – wysyłanie danych metodą POST RequestQueue queue = Volley.newRequestQueue(this); String url = "[ADRES_URL]"; StringRequest postRequest = new StringRequest(Request.Method.POST, url, new Response.Listener () public void onResponse(String response) { // Odpowiedź serwera pozytywna } }, new Response.ErrorListener() public void onErrorResponse(VolleyError error) { // Coś poszło nie tak, błąd! } }) protected Map getParams(){ Map params = new HashMap (); params.put("value1", "4"); params.put("value2", "druga zmienna"); return params; } }; queue.add(postRequest);

27 Volley – pobieranie obrazków public ImageRequest(String url, Response.Listener listener, int maxWidth, int maxHeight, ScaleType scaleType, Config decodeConfig, Response.ErrorListener errorListener); RequestQueue queue = Volley.newRequestQueue(this); final ImageView mImageView; String url = "http://i.imgur.com/7spzG.png"; mImageView = (ImageView) findViewById(R.id.imageView); ImageRequest postRequest = new ImageRequest(url, new Response.Listener () public void onResponse(Bitmap bitmap) { mImageView.setImageBitmap(bitmap); // response zawiera obraz gotowy do wstawienia }}, 0, 0, ImageView.ScaleType.CENTER, Bitmap.Config.RGB_565, new Response.ErrorListener() public void onErrorResponse(VolleyError error) { // Błąd! mImageView.setImageResource(android.R.drawable.stat_notify_error); } }) { }; queue.add(postRequest);

28 Volley – wysyłanie i odbieranie obiektów JSON public JsonObjectRequest(int method, String url, JSONObject jsonRequest, Listener listener, ErrorListener errorListener) Map jsonParams = new HashMap<>(); jsonParams.put("key1", "value1"); jsonParams.put("key2", "value2"); JSONObject postData = new JSONObject(jsonParams); RequestQueue queue = Volley.newRequestQueue(this); String url = "[ADRES_URL]"; JsonObjectRequest postRequest = new JsonObjectRequest (Request.Method.POST, url, postData, new Response.Listener () public void onResponse(JSONObject response) { // response zawiera odpowiedź w postaci obiektu JSON } }, new Response.ErrorListener() public void onErrorResponse(VolleyError error) { // Błąd! } }) { }; queue.add(postRequest);

29 Volley – wysyłanie i odbieranie tablic obiektów JSON RequestQueue queue = Volley.newRequestQueue(this); String url = "[ADRES_URL]"; JsonArrayRequest postRequest = new JsonArrayRequest (Request.Method.POST, url, new Response.Listener () public void onResponse(JSONArray response) { // response zawiera odpowiedź w postaci listy obiektów JSON } }, new Response.ErrorListener() public void onErrorResponse(VolleyError error) { // Błąd! } }) { }; queue.add(postRequest); }

30 Co zrobić z JSONem ? Deserializacja Manualnie – metody JSONArray i JSONObject getJSONObject(int i) – pobiera i-ty element z tablicy JSON getJSONArray(string key) – pobiera tablice o nazwie danej kluczem getDouble(string key) – pobiera typ double o nazwie danej kluczem getBoolean(string key) – pobiera typ boolean o nazwie danej kluczem getInt(string key) – pobiera typ int o nazwie danej kluczem getString(string key) – pobiera typ String o nazwie danej kluczem Automatycznie google-gson – automatyczna serializacja/deserializacja obiektów do formatu JSON dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.2.0' compile 'com.mcxiaoke.volley:library:1.0.19' compile 'com.google.code.gson:gson:2.6.2' } app\build.gradle (biblioteka sama się pobierze i zainstaluje)

31 GSON – (de)serializacja obiektów JSON Model JSON: Deserializacja Problematyczne z niestrukturalnymi danymi! public class Teacher { public String name; public String surname; public List classes; public int experiance; } [{ "name": "Krzysztof", "surname": "Bzowski", "classes": ["Programowanie w JAVA", "Systemy Wbudowane", "Inżynieria internetu"], "experiance": 5 }, { "name": "Gorzegorz", "surname": "Smyk", "classes": ["Programowanie obiektowe"], "experiance": 5 }, { "name": "Mateusz", "surname": "Sitko", "classes": ["Podstawy programowania", "Modelowanie wieloskalowe"], "experiance": 5 }] Gson gson = new Gson(); String rawJson = response.toString(); List teachers = gson.fromJson(rawJson, new TypeToken >(){}.getType()); Teacher teacher = gson.fromJson(rawJson, Teacher.class); Obiekt typu JSONArray lub JSONObject

32 Po co wątki? Wszystkie metody uruchomione w Activity działają w ramach wątku GUI Czasochłonne metody (sieć, baza danych, obliczenia itd.) zablokują aplikację public void runBtn(View view) { final ProgressBar pb = (ProgressBar) findViewById(R.id.progressBar); for (int i = 0; i <= 100; i++) { timeConsumingWork(); pb.setProgress(i); } } private void timeConsumingWork() { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } ProgressBar

33 Sposób 1: Handler public void runBtn(View view) { final ProgressBar pb = (ProgressBar) findViewById(R.id.progressBar); Runnable runnable = new Runnable() public void run() { for (int i = 0; i <= 100; i++) { final int value = i; timeConsumingWork(); pb.post(new Runnable() public void run() { pb.setProgress(value); } }); } } }; new Thread(runnable).start(); } Czasochłonną operację umieszczamy w anonimowej klasie implementującej interfejs Runnable Progress raportujemy za pomocą metody post widoku ProgressBar do której również przesyłamy obiekt Runnable

34 Sposób 2: AsyncTask Klasa działająca asynchronicznie, musi dziedziczyć po AsyncTask private class ProgressAsync extends AsyncTask { private ProgressBar pb; public ProgressAsync(ProgressBar pb) { this.pb = pb; protected Void doInBackground(Void... params) { for (int i = 0; i <= 100; i++) { timeConsumingWork(); publishProgress(i); } return null; protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); pb.setProgress(values[0]); } } public void runBtn(View view) { ProgressBar pb = (ProgressBar) findViewById(R.id.progressBar); ProgressAsync pa = new ProgressAsync(pb); pa.execute(); } Miejsce na raportowanie postępu Miejsce na czasochłonne zadania AsyncTask pozwala na uruchomienie i nie czeka na zakończenie metody execute

35 Metody AsyncTask onPreExecute() – uruchamiane z wątku GUI przed uruchomieniem doInBackground. Miejsce przygotowanie widoków – np. pokazanie ProgressBar doInBackground(Params...) – uruchamiane w osobnym wątki zaraz po zakończeniu onPreExecute(). Miejsce na czasochłonne operacje. publishProgress(Progress...) metoda służąca raportowaniu postępu wewnątrz doInBackGround(). onProgressUpdate(Progress...), uruchamiane z wątku GUI samoczynnie po wykonaniu publishProgress(Progress...). Miejsce na wizualizację postępu zadania, np. poprzez zmianę wartości widoku. onPostExecute(Result), uruchamiane z wątku GUI po zakończeniu zadania. Jako parametr otrzymuje wynik działania doInBackground(). Miejsce na wyświetlenie podsumowania lub przekazanie sterowania dalej. doInBackgroundonPreExecuteonPostExecute onProgressUpdate publishProgress

36 To tyle… Co warto poczytać: Navigation Drawer Niestandardowe widoki https://github.com/wasabeef/awesome-android-ui Powiadomienia Obsługa sensorów (żyroskop, akcelerometr i inne) Obsługa GPS Usługi działające w tle Cloud messaging – powiadomienia PUSH https://developers.google.com/cloud-messaging/ Google API – dostęp do Map, Kalendarza itp. https://developers.google.com/google-apps/calendar/quickstart/android Google Analytics (statystyki naszej aplikacji) https://developers.google.com/analytics/devguides/collection/android/v4/ Tworzenie gier: https://github.com/libgdx/libgdx/ https://software.intel.com/en-us/android/blogs/2012/03/13/game-engines-for-android Umieszczenie aplikacji w Play Store


Pobierz ppt "Android WYKŁAD 4. Agenda Bazy danych – SQLite Zestawienie mapowania w LiteORM Wyświetlanie danych w ListView Pobieranie danych z sieci – Volley Zapytania."

Podobne prezentacje


Reklamy Google