Mantenere dati persistenti un un DB

Slides:



Advertisements
Presentazioni simili
1 Le s-espressioni. 2 Un nuovo esempio completo: le s-espressioni Sexpr 4 alberi binari (possibilmente vuoti) che hanno sulle foglie atomi (stringhe)
Advertisements

1 Progettazione gerarchica delle s- espressioni, utilizzando lereditarietà
Interfacce Java.
Microsoft SQL Server 2008 Utilizzo. Creazione DataBase CREATE DATABASE CREATE DATABASE Cinema.
1 Teaching Cloud Computing and Windows Azure in Academia Domenico Talia UNIVERSITA DELLA CALABRIA & ICAR-CNR Italy Faculty Days 2010.
Luca Bianchi Windows Development Day Bologna 28 gennaio 2005 SQL Server Desktop Engine (MSDE) & SQL Server 2005 Express.
Vincenzo Campanale PM Security & Management System Center, DSI e la Roadmap.
SQL (Standard query language) Istruzioni per la creazione di una tabella: Create table ( tipo, (, [vincoli]) Primary key ( ) CHIVE PRIMARIA Foreign key(
JPA Overview della tecnologia. Java Persistence Architecture Definita nella JSR-220 EJB 3.0 ( Tentativo di unificare EJB2.1 con.
Sequential Statements. – Il VHDL simula lo svolgersi in parallelo di varie operazioni – Loggetto fondamentale e il PROCESS – Un PROCESS contiene una serie.
Seam.
1.E un algoritmo ricorsivo: Tutti le istanze di oggetti raggiungibili da un oggetto persistente diventano anchessi persistenti.
Un DataBase Management System (DBMS) relazionale client/server.
MySQL Esercitazioni. Ripasso Connessione a MySQL. Creazione delle basi di dati e delle tablelle. Inserimento dei dati. Interrogazioni.
Raffaele Cirullo Head of New Media Seconda Giornata italiana della statistica Aziende e bigdata.
EJB Enterprise Java Beans B. Pernici. Approccio Java.
Layouts and Graphics. component - container - layout Un Container contiene [0 o +] Components Il Layout specifica come i Components sono disposti nel.
Model – View - Controller
Esempio: Tombola! Parte seconda.
Unified Modeling Language class C {…} class B extends C {…} Esiste una notazione grafica per mostrare le relazioni di ereditarietà. Object StringC B Tutte.
Richiami di Java Multithreading. Threads (subclassing) public class A { public void a_method { C t = new C(); //C t = new C(String name); t.start(); …
Sezione: Costruttori Costruttori. Definizione dei costruttori Se per una classe A non scrivo nessun costruttore, il sistema automaticamente crea il costruttore.
prompt> java SumAverage
1 struct Pila { private: int size; int defaultGrowthSize; int marker; int * contenuto; void cresci(int increment); public: Pila(int initialSize) ; Pila();
Costruzione di Interfacce Lezione 10 Dal Java al C++ parte 1
1. Conoscere luso delle collezioni in Java Comprendere le principali caratteristiche nelle varie classi di Collection disponibili Saper individuare quali.
1 Esercitazione sui segnali Problema: creare un programma analizzatore di file testuali che prenda come argomenti il nome di un file e una sequenza di.
Programming with JXTA Hello World Peer discovery Peer Group discovery Creating Peer group Joining a Peer Group.
2000 Prentice Hall, Inc. All rights reserved. 1 Capitolo 3 - Functions Outline 3.1Introduction 3.2Program Components in C++ 3.3Math Library Functions 3.4Functions.
Primi esempi di interfacce grafiche con Android
© CEFRIEL Ricettario dei principali pattern GoF Docente: Gabriele Lombardi
© CEFRIEL Cenni su XML in Java Docente: Gabriele Lombardi
2000 Prentice Hall, Inc. All rights reserved. 1 Capitolo 6: Classi e astrazione dati 1.Introduzione 2.Definizione delle strutture 3.Accedere ai membri.
FONDAMENTI DI INFORMATICA III WfMC-1. FONDAMENTI DI INFORMATICA III WfMC-2 WFMC Cose WfMC Workflow Management Coalition (WfMC), Brussels, è unorganizzazione.
New Features + Improvements Miglioramenti alle Situazioni contabili Distribuzione costi Intragruppo in registrazione fatture di acqusti Varie.
Sequence. CREARE UNA SEQUENCE CREATE SEQUENCE nome [INCREMENT BY n] [START WITH n] [MAXVALUE n | NOMAXVALUE] [MINVALUE n | NOMINVALUE] [CYCLE | NOCYCLE]
PRODOTTO CARTESIANO Otteniamo un prodotto cartesiano quando: viene omessa la condizione di join una condizione di join non è valida tutte le righe della.
FUNZIONI DI GRUPPO Le funzioni di gruppo operano su un set di record restituendo un risultato per il gruppo. AVG ([DISTINCT|ALL] n) media, ignora i valori.
Constraints.
Componenti dell’architettura Oracle
SQL per la definizione di basi di dati SQL non è solo un linguaggio di interrogazione (Query Language), ma Un linguaggio per la definizione di basi di.
Palermo, may 2010 F.Doumaz, S.Vinci (INGV-CNT- Gruppo di telerilevamento)
Università degli studi di Modena e Reggio Emilia Facoltà di Ingegneria di Modena Corso di Laurea Specialistica in Ingegneria Informatica Analisi e valutazione.
Microsoft Access Maschere.
Filtered Index and Statistics Filtered Indexes Sergio Govoni
Moduli o Form I Moduli permettono all'utente di immettere informazioni...
Facelets case study: Ricettario Docente: Gabriele Lombardi
1 Lucidi delle esercitazioni di Sistemi di Elaborazione in Rete Università degli Studi della Calabria Corso di Laurea in Ingegneria Informatica A.A. 2003/2004.
24 aprile 2002 Avvisi: Risultati 1 o Esonero: (entro) lunedi 27 disponibili nella pag. WEB, ma anche esposti nella bacheca fuori dal corridoio 2 o dente,
Multiset. Progettare (specifica con identificazione delle eventuali astrazioni necessarie, incluse eccezioni, e implementazione) del tipo di dato Multiset,
VB.NET Sviluppo Applicazioni Desktop
Visual Studio Tools for Office: Developer Solutions Platform Fulvio Giaccari MCSD.NET / MCT Responsabile Usergroup ShareOffice Blog:
SQL Server 2005 Sicurezza Davide Mauri Factory Software
Test con JUnit. zJUnit è un ambiente di test per programmi Java ySviluppato da Kent Beck É possibile usare JUnit allinterno di Eclipse per eseguire i.
1 Simulated multiple inheritance Sandro Pedrazzini Approfondimento Simulated multiple inheritance in Java.
SUBQUERY Chi ha un salario maggiore di quello di Abel? Occorre scomporre la query in due sotto problemi: MAIN : quali impiegati hanno un salario maggiore.
2000 Prentice Hall, Inc. All rights reserved. I file Apertura e chiusura I file ad accesso sequenziale I file ad accesso casuale Apre un file già esistente.
Introduzione al linguaggio C. Cos’e’ il C? Il C e’ un linguaggio ad alto livello Un compilatore C prende in input un file contenente codice sorgente C.
1 Basi di dati (Sistemi Informativi) Scuola di Dottorato in Scienze Veterinarie per la Salute Animale e la Sicurezza Alimentare a.a Ing. Mauro.
Collection & Generics in Java
Introduction to automatic ABMs documentation Keywords: Doxygen ODD protocol MASON documentation Simone Romano.
Sistemi di elaborazione dell’informazione Modulo 3 -Protocolli applicativi Unità didattica 4 - Protocolli del Web Ernesto Damiani Lezione 3 – Esempi HTTP.
SQL Developer Lanciare sqldeveloper (alias sul desktop) / c:\Oracle\sqldeveloper Associare tutti i tipi di file, se volete Tasto destro sulla spina “connection”
Dynamic SQL.
JDBC Java DataBase Connectivity SISTEMI ITIS B. CASTELLI Anno Scolastico
Nuove funzionalitA’ e caratteristiche del linguaggio
SQLite. Introduzione a SQLite Oltre alla possibilità di memorizzare informazioni persistenti attraverso Preferences e files, Android mette a disposizione.
* R AMAN K AZHAMIAKIN O SCAR Z G IOVANNI D E ITT M. B UONARROTI, T RENTO A NDROID D EVELOPMENT P ERSISTENZA.
PROGRAMMAZIONE BASH – ISTRUZIONE IF
Studente : Andrea Cassarà Classe: 5AII A.S. 2014/2015 Link Sito
Transcript della presentazione:

Mantenere dati persistenti un un DB Docente: Gabriele Lombardi lombardi@dsi.unimi.it © 2012 - CEFRIEL

The present original document was produced by CEFRIEL and the Teacher for the benefit and internal use of this course, and nobody else may claim any right or paternity on it. No right to use the document for any purpose other than the Intended purpose and no right to distribute, disclose, release, furnish or disseminate it or a part of it in any way or form to anyone without the prior express written consent of CEFRIEL and the Teacher. © copyright Cefriel and the Teacher-Milan-Italy-23/06/2008. All rights reserved in accordance with rule of law and international agreements. © 2012 - CEFRIEL

Sommario SQLite Lavorare sul DB App di esempio ContentProvider SLIDE CONTENUTO SQLite Da riga di comando, tools in Android Lavorare sul DB DDL e operazioni CRUD App di esempio Creiamo un ricettario con persistenza su DB ContentProvider Dati a disposizione delle app… in sicurezza ORM ed Entities Object Relational Mapping e nostra lib ORM Hadi Tutto in Java… al DB ci pensa qualcun altro © 2012 - CEFRIEL

Citando http://www.sqlite.org/: Cos’è SQLite Citando http://www.sqlite.org/: «SQLite is a software library that implements a self-contained, serverless, zero-configuration, transactional SQL database engine.» Caratteristiche: lavora su un file singolo per ogni db; ha un’impronta contenutissima (completo in Android); supporta la maggior parte dello standard SQL92; molto più veloce per molte operazioni; è supportato nativamente in Android; … Particolarità: tipi di dato suggeriti per le colonne, non obbligatori. © 2012 - CEFRIEL

Usiamolo da riga di comando accediamo alla shell (dell’emulatore in esecuzione): adb shell creiamo un nuovo database (che elimineremo): sqlite3 prova.db creiamo una tabella: create table note(_id integer primary key autoincrement, content text not null); elenchiamo le tabelle e vediamone lo schema: .tables .schema note inseriamo un dato di esempio: insert into note(content) values('una nota di esempio'); vediamo lo in HTML (provare anche cvs, tabs, …): .mode html select * from note; dump di tutto il db come istruzioni SQL: .output myDump .dump .output stdout fine sessione: .exit © 2012 - CEFRIEL

Il Framework ci offre alcuni strumenti: In Android… Il Framework ci offre alcuni strumenti: gestione delle versioni del DB (per gli aggiornamenti); wrapping in Java delle API; astrazione dei cursori; composizione di query e DDL con metodi comodi. Per l’interfaccia utente: adattatori dedicati alla fruizione di dati da DB. Per l’accesso ai dati: la possibilità di realizzare ContentProvider: accedere ai dati da altre applicazioni; offrire un nuovo tipo di content URI; accesso locale nella nostra app (primo esempio). © 2012 - CEFRIEL

…cosa manca? ORM: Cosa vedremo noi? esistono dei progetti a riguardo: http://ormlite.com/  reflection su annotazioni stile JPA http://hadi.sourceforge.net/  come sopra ma più JPA-oso http://greendao-orm.com/  code generation http://code.google.com/p/hiberdroid/  Hibernate per Android più altri framework generici per l’ORM: http://www.avaje.org/ http://cayenne.apache.org/ ma niente ancora di standard; spesso si tende a fare ORM «a manina». Cosa vedremo noi? Utilizzo «piatto» del DB; ORM «a manina» con uno strumento nostro; hadi come esempio di ORM su Android. © 2012 - CEFRIEL

serve un gestore centralizzato del DB; Qualcuno ci da una mano SQLiteOpenHelper: classe da estendere per accedere a un DB; ci offre dei metodi per la «connesione» al DB; invoca i nostri metodi per il mantenimento: onCreate: DB mancante, prima esecuzione, creazione schema; onUpgrade: se cambia la versione vorremmo aggiornare lo schema. Gestore del DB: la nostra app accederà al DB da diverse activity: serve un gestore centralizzato del DB; gestisce l’accesso al DB nascondendo i dettagli; offre le operazioni che ci interessa svolgere sul DB. © 2012 - CEFRIEL

Un nostro DbManager private class RecipesHelper extends SQLiteOpenHelper { public static final String RECIPES_TABLE_CREATE = …; public static final String RECIPES_TABLE_DROP = …; … public RecipesHelper(Context context, String name, CursorFactory factory, int version) { super(context, name, factory, version); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(INGREDIENTS_TABLE_CREATE); db.execSQL(RECIPES_TABLE_CREATE); db.execSQL(RECIPES_INGREDIENTS_TABLE_CREATE); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL(RECIPES_INGREDIENTS_TABLE_DROP); db.execSQL(RECIPES_TABLE_DROP); db.execSQL(INGREDIENTS_TABLE_DROP); onCreate(db); } } © 2012 - CEFRIEL

DbManager: offrire funzionalità private RecipesHelper helper; private SQLiteDatabase db = null; public DbManager(Context ctx) { helper = new RecipesHelper(ctx, RECIPES_DB_NAME, null, RECIPES_DB_VERSION); } public synchronized void open() { if (db==null) db = helper.getWritableDatabase(); if (!db.isReadOnly()) db.execSQL("PRAGMA foreign_keys=ON;"); public synchronized void close() { if (db!=null) { db.close(); db = null; } private void checkDb() { if (db==null) throw new IllegalStateException("DB non opened."); © 2012 - CEFRIEL

DbManager: offrire funzionalità public synchronized Cursor getRecipeDescriptions() { checkDb(); return db.query(RECIPES_TABLE, new String[] {RECIPES_ID, RECIPES_NAME, RECIPES_DESC}, null, null, null, null, RECIPES_NAME); } Tabella a cui accedere Campi della proiezione WHERE e argomenti GROUP BY e HAVING ORDER BY Volendo limit Cursor c = db.rawQuery("SELECT " + RECIPES_NAME + … " WHERE " + RECIPES_ID + "=?", new String[] {Long.toString(id)}); Argomenti gestiti in stile JDBC db.insert(INGREDIENTS_TABLE, null, ingredient2content(ingredient)); db.replace(INGREDIENTS_TABLE, null, ingredient2content(ingredient)); db.delete(RECIPES_TABLE, RECIPES_ID + "=?", new String[] {Long.toString(id)}); Operazioni CRUD ContentValues values = new ContentValues(); values.put(RECIPES_INGREDIENTS_RECIPE, recipe.get_id()); values.put(RECIPES_INGREDIENTS_INGREDIENT, ingredient.get_id()); values.put(RECIPES_INGREDIENTS_QTA, ingredient.getQta()); Dati come ContentValues © 2012 - CEFRIEL

SQLiteQuery e SQLiteQueryBuilder Dinamicità nella creazione di query? Query dalla struttura dinamica possono esser create: per concatenazione di stringhe: rende difficile la produzione di statement validi se parti diverse dell’app devono «metterci il proprio» (parti differenti); Soluzione alternativa: builder per la query a cui dichiarare ciò che si vuole; aggiunta programmatica di parti di query; Altre soluzioni: framework esterni che offrono criteria-query: http://code.google.com/p/infinitum-framework/ http://code.google.com/p/hiberdroid/ © 2012 - CEFRIEL

Atomiche: come fossero eseguite istantaneamente Transazioni A volte una sequenza di più operazioni su un DB deve avere le seguenti caratteristiche: Atomiche: come fossero eseguite istantaneamente Consistenti: con i vincoli imposti dal DB (relazioni, vincoli) Isolate: se concorrenti non interferiscono Durature: modifiche con successo sono permanenti anche a crash In Android usiamo il seguente pattern: db.beginTransaction(); try { … // Operazioni su DB che possono fallire. db.setTransactionSuccessful(); // Segno la transazione come buona. } catch (Exception e) { … } finally { db.endTransaction(); // Fine transazione. } © 2012 - CEFRIEL

Rendiamo il nostro DbManager accessibile Come gestire qualcosa di «globale» in una app? Le attività vanno e vengono, scomodo usare lo stato; i servizi possono sopravvivere indefinitamente… … ma comunicare con essi non è particolarmente agile; attributi statici pubblici (o con getter e laziness) possono aiutare ad affrontare il problema… …ma offrono in realtà un modello «sporco» di lavoro. Il contesto… non è sono l’attività: il concetto di contesto è più ampio di quanto si pensi; l’app possiede un contesto indipendente dalle attività; creiamo la nostra classe applicazione: potremo personalizzarne il ciclo di vita; offriremo il DbManager mantenuto in vita. © 2012 - CEFRIEL

Una applicazione… nostra! public class RecipesApplication extends Application { private DbManager dbManager = null; public DbManager getDbManager() { if (dbManager==null) { dbManager = new DbManager(this); dbManager.open(); } return dbManager; Attenti a non sfruttare il metodo onTerminate… serve solo in emulazione <activity android:name=".RecipesActivity" android:label="@string/app_name" android:launchMode="singleTop"> Specificando name nel manifest specifichiamo anche la classe private RecipesApplication app; app = ((RecipesApplication)getApplication()); app.getDbManager().getRecipeDescriptions() Dichiarata e ottenuta nel metodo onCreate… …offre accesso ai dati! © 2012 - CEFRIEL

Un ricettario sul telefono… Vogliamo gestire un ricettario su Android… schema del (semplice) DB (che estenderemo): recipes name desc preparation ingredients recipes_ingredients qta Una ricetta molti ingredienti Un ingrediente molte ricette CREATE TABLE ingredients(_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE NOT NULL, desc TEXT NOT NULL); CREATE TABLE recipes(_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE NOT NULL, desc TEXT NOT NULL,preparation TEXT NOT NULL); CREATE TABLE recipes_ingredients(recipe_id INTEGER NOT NULL REFERENCES recipes ON DELETE CASCADE, ingredient_id INTEGER NOT NULL REFERENCES ingredients,qta TEXT ,PRIMARY KEY (recipe_id, ingredient_id)); © 2012 - CEFRIEL

Progettazione dell’interfaccia RecipesActivity: attività principale, elenca le attività; RecipeDetailsActivity: consultazione ed eventuale editing di una ricetta; IngredientsActivity: gestione degli ingredienti, creazione, modifica. Nome ricetta Descrizione breve Nome ricetta Descrizione breve Preparazione dettagliata Ingrediente Quantità Descrizione Nome ingrediente Descrizione breve © 2012 - CEFRIEL

Consultazione ricette: Casi d’uso e sequenze Consultazione ricette: L’utente può leggere la lista di ricette, accedendo al menu po’ crearne una nuova, o selezionarne una esistente per consultarla (modalità di lettura). L’attività di consultazione mostra i dettagli della ricetta in sola lettura, il menu consente di passare alla modalità di enditing (automatica per ricette nuove). Editing di una ricetta nuova o vecchia: I campi di testo divengono modificabili, il menu mostra voci in più (salvataggio, aggiunta ingrediente). Se non si salva si mantiene una copia temporanea. Dal menu si passa da una modalità all’altra. Editing degli ingredienti: Possono essere creati, eliminati, modificati da una lista tramite un menu contestuale. © 2012 - CEFRIEL

Anche l’aspetto ha il suo valore… 9 (patches) Aspetto accattivante della ricetta consultata: campi di testo come su carta con una piega; aspetto normale in modalità di editing vogliamo una sola immagine per tutte e tre i campi. Disegniamo una nine-patch: prepariamo un’immagine png della carta; usiamo draw9patch per definire la patch. Utilizziamo un drawable XML (selector): <selector xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/selector_paper"> <!-- Stato associato al disabilitato: --> <item android:state_enabled="false" android:drawable="@drawable/paper_img"/> <!-- Stato di default mantenuto negli altri casi: --> <item android:state_enabled="true" android:drawable="@android:drawable/edit_text«/> </selector> © 2012 - CEFRIEL

Offriamo accesso ai dati come ContentProvider Vogliamo rendere le nostre ricette disponibili… …anche ad altre applicazioni (altri processi); tramite cursori direttamente dal DB; mantenendo controllo sui permessi di scrittura; mantenendo indipendenza tra l’applicazione che offre i contenuti e quella che ne usufruisce. Soluzione: implementare un ContentProvider: ogni ricetta viene mappata con un uri «content://…»; devono essere noti (oltre l’uri) i nomi delle colonne: non obbligatoriamente, solo se si intende proiettare; spesso si utilizza una classe contratto contenente le costanti; un ContentResolver permette poi di accedere ai dati: inconsapevolmente rispetto alla sorgente li ha prodotti. © 2012 - CEFRIEL

Un po’ di configurazione <provider android:name= "com.gab.tests.android.recipes.model.RecipesContentProvider" android:authorities="com.gab.tests.android.recipes.provider" android:writePermission= "com.gab.tests.android.recipes.WRITE_RECIPES" android:label="Recipes content provider" android:icon="@drawable/ic_launcher"/> Nome «logico» e nome «fisico» Il permesso in scrittura va garantito per operazioni diverse da «query» private static final int RECIPES = 1; private static final String PATH = "com.gab.tests.android.recipes"; private static final String AUTHORITY = PATH + ".provider"; static final String RECIPES_CONTENT_TYPE = "vnd.android.cursor.dir/vnd." + PATH + ".provider." + DbManager.RECIPES_TABLE; static final Uri RECIPES_CONTENT_URI = Uri.parse( "content://" + AUTHORITY + "/" + DbManager.RECIPES_TABLE); private static final UriMatcher uriMatcher; static { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(AUTHORITY, DbManager.RECIPES_TABLE, RECIPES); } Scegliamo il tipo Scegliamo l’uri © 2012 - CEFRIEL

Inizializzazione, tipo, operazioni private RecipesApplication app; @Override public boolean onCreate() { app = (RecipesApplication)getContext().getApplicationContext(); return true; } @Override public String getType(Uri uri) { switch (uriMatcher.match(uri)) { case RECIPES: return RECIPES_CONTENT_TYPE; default: throw new IllegalArgumentException("Unknown URI "); } } Ci serve il riferimento all’applicazione Dobbiamo verificare gli uri che ci arrivano @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); switch (uriMatcher.match(uri)) { case RECIPES: qb.setTables(DbManager.RECIPES_TABLE); qb.setProjectionMap(projectionMap); break; default: throw new IllegalArgumentException("Unknown URI "); } Cursor c = qb.query(app.getDbManager().getDb(), projection, selection, selectionArgs, null, null, sortOrder); c.setNotificationUri(getContext().getContentResolver(), uri); return c; } Query costruita con un QueryBuilder Osserviamo l’uri in caso di cambiamento © 2012 - CEFRIEL

Una applicazione «client» Per verificare il nostro provider dobbiamo: creare una applicazione separata che lo utilizzi; mostriamo (banalmente) in una ListView le ricette. Proviamo assieme a modificare il «client» per sfogliare solamente le ricette «as they are» (senza ingredienti). Proviamo a offrire/mostrare anche gli ingredienti. @Override protected Cursor doInBackground(Void... params) { ContentResolver resolver = getContentResolver(); Uri uri = Uri.parse("content://com.gab.tests.android.recipes.provider/recipes"); return resolver.query(uri, columns, null, null, "name"); } @Override protected void onPostExecute(Cursor result) { SimpleCursorAdapter adapter = new SimpleCursorAdapter( RecipesClientActivity.this, android.R.layout.two_line_list_item, result, columns, new int[] { 0, android.R.id.text1, android.R.id.text2 }); setListAdapter(adapter); // Aggiornamento della lista (nel main thread). } © 2012 - CEFRIEL

Offriamo l’attività di consultazione Come per le call… anche la nostra app può: registrarsi per un uri custom  recipe:<id> mostrarsi come strumento di consultazione; venire interpellata in maniera trasparente. Uri uri = intent.getData(); // Ottengo l'uri e lo parso. if (uri!=null && "recipe".equals(uri.getScheme())) { String id = uri.getSchemeSpecificPart(); // Estraggo l'id in un uri del tipo "recipe:<id>". try { // Carico la ricetta se possibile: recipe = app.getDbManager().getRecipe(Long.parseLong(id)); canEdit = false; // Mi metto in nodalità solo consulto. } catch (Exception e) { throw new IllegalArgumentException(“…"); } } onCreate <activity android:name=".RecipeDetailsActivity" android:screenOrientation="landscape"> <intent-filter > <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.DEFAULT"/> <data android:scheme="recipe"/> </intent-filter> </activity> Da dichiarare startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("recipe:" + id))); In un’altra app… © 2012 - CEFRIEL

Chi cerca trova Android offre una funzionalità di ricerca: a volte con un tasto fisico sul dispositivo; noi possiamo offrire sempre un tool di avvio ricerca. Per abilitarlo: lo dichiariamo nel manifest; ne catturiamo la richiesta come intent. <activity android:name=".RecipesClientActivity" …> … <intent-filter> <action android:name="android.intent.action.SEARCH" /> </intent-filter> <meta-data android:name="android.app.searchable" android:resource="@xml/searchable"/> </activity> <searchable xmlns:android="http://schemas.android.com/apk/res/android" android:label="@string/app_name" android:hint="@string/search_hint"/> Intent intent = getIntent(); if (Intent.ACTION_SEARCH.equals(intent.getAction())) { // Questa stringa la useremo nella query verso il ContentResolver: query = intent.getStringExtra(SearchManager.QUERY); } © 2012 - CEFRIEL

ORM  Object Relational Mapping: Cos’è l’ORM? ORM  Object Relational Mapping: lavoriamo sempre a oggetti nella nostra app; qualcun altro si preoccupa di fare traduzione tra modello di dati OO e modello di dati relazionale; auto-magicamente i dati divengono persistenti! Modello a oggetti Database relazionale Mapping tra oggetti e relazioni Object-relational mapper © 2012 - CEFRIEL

Un nostro Object Relational Mapper Solo un cenno di architettura, per dare l’idea: public abstract class Entity { protected abstract String getTableName(); protected abstract String[] getFieldNames(); public void createTable() throws Exception { StringBuilder sb = new StringBuilder( "CREATE TABLE " + getTableName() + "(_id integer primary key autoincrement"); for (String name: getFieldNames()) { Class type = getClass().getField(name).getType(); String typeName = "text"; if (type.equals(Integer.class)) typeName = integer; … sb.appen("," + name + " " + typeName + "NOT NULL"); } getDb().rawQuery(sb.toString() + ");"); public Entity byId(long id) { // Query tramite concatenazione. // Istanziazione e assegnamento valori tramite reflection. } … Facciamolo assieme! © 2012 - CEFRIEL

Proviamo ad utilizzare Hadi In Hadi vengono utilizzate le annotazioni: porzioni di informazione «annotate» sul codice; proviamo anche in un nostro ORMapper! DefaultDAO dao = new DefaultDAO(this); Book b1 = new Book(); b1.name = "Who Moved My Cheese"; b1.sn = "sn123456789"; dao.insert(b1); b1.sn = "sn987654321"; dao.update_by_primary(b1); String[] args = {"0"}; List<Book> books = (List<Book>)dao.select(Book.class, false, " id > ?", args, null, null, null, null); b1.id = 1; dao.delete_by_primary(b1); @Table(name="Hello") public class Book{ @Column(autoincrement=true) public int id; @Column(name="sn") public String sn; @Column(name = "") public String name; } © 2012 - CEFRIEL

Da qui? Esiste anche il lato oscuro della persistenza: accesso diretto a file su telefono o SD; utilizzo di SharedPreferences; utilizzo di file classici con java.io. La persistenza non è tutto nella vita: i dati potrebbero provenire da altre fonti: internet e servizi HTTP (RESTful); servizi di localizzazione; sensori di vario tipo. spesso si usano strumenti misti, ad esempio se volessimo aggiungere un’immagine per ricetta salveremmo un URI, mantenendo l’immagine su SD. Considerare i tempi di accesso: quanto fatto dovrebbe venir modificato per lavorare in differita da un thread diverso da quello principale. © 2012 - CEFRIEL