Componenti dell'architettura Android: creazione di un'app utilizzando Room, LiveData e ViewModel

Autore: John Stephens
Data Della Creazione: 26 Gennaio 2021
Data Di Aggiornamento: 18 Maggio 2024
Anonim
Componenti dell'architettura Android: creazione di un'app utilizzando Room, LiveData e ViewModel - Applicazioni
Componenti dell'architettura Android: creazione di un'app utilizzando Room, LiveData e ViewModel - Applicazioni

Contenuto


Dal punto di vista dell'utente, questa applicazione sarà composta da due attività:

  • Un'attività principale. Questa schermata mostra la lista della spesa dell'utente in un RecylerView e presenta un'icona della barra delle azioni, che porta l'utente dalla prima schermata alla seconda.
  • A NewItemActivity. Questa schermata conterrà un testo di modifica in cui l'utente può inserire articoli e un pulsante "Salva" che consente di salvare ciascun articolo nella propria lista della spesa. Nuovi elementi verranno aggiunti automaticamente a RecylerView.

In apparenza, questa sembra un'applicazione abbastanza semplice, ma dietro le quinte utilizzeremo una serie di componenti di architettura Android per offrire questa funzionalità in modo robusto, gestibile e segue tutte le ultime best practice di architettura Android.

Esploreremo ogni componente dell'architettura in modo più dettagliato quando li implementeremo, ma per ora otteniamo una panoramica di alto livello su come tutti questi componenti si incastrano:


  • Un ViewModel. Ogni volta che la configurazione del dispositivo cambia, Android risponderà distruggendo l'attività o il frammento corrente e quindi ricreandolo con la nuova configurazione. Se conservi i dati della tua applicazione in un componente dell'interfaccia utente, potresti potenzialmente perdere tali dati ogni volta che cambia la configurazione, incluso ogni volta che l'utente passa dalla modalità verticale a quella orizzontale. Per mantenere i nostri dati separati dall'interfaccia utente della nostra applicazione, li terremo in un ViewModel, progettato per resistere alle modifiche di configurazione.
  • Un repository. Questa classe gestisce una o più origini dati, inclusi servizi Web, cache e database Room.
  • Un database Room. Room offre un livello di astrazione su SQLite, aiutandoti a creare e mantenere un database SQLite locale, senza dover scrivere una tonnellata di codice del boilerplate. Se hai precedenti esperienze con SQLite, Room gestisce tutte le attività che in genere gestisci nella classe SQLiteOpenHelper.
  • Un DAO (Data Access Object). Questo contiene i metodi che utilizzerai per accedere al tuo database Room.
  • Un'entità. Questa è una classe annotata che rappresenta una tabella all'interno del database. Nella nostra applicazione, ogni articolo che l'utente aggiunge alla propria lista della spesa sarà rappresentato come un'istanza della classe entità.

Nella nostra applicazione, questo si tradurrà nelle seguenti classi:


Creazione di osservabili sensibili al ciclo di vita, con LiveData

Il LiveData la classe di dati osservabili è un componente di architettura Android che merita una menzione speciale, in quanto ci consentirà di aggiornare automaticamente RecylerView man mano che nuovi dati diventano disponibili, ovvero ogni volta che l'utente aggiunge un nuovo articolo alla sua lista della spesa.

Invece di scrivere la logica per elaborare i nuovi dati, possiamo modificare i nostri metodi DAO in modo che restituiscano oggetti LiveData. Gli oggetti LiveData supportano il modello Observer, quindi possiamo usare questi oggetti per creare relazioni Observer / Osservabili in cui gli Osservatori rilevanti vengono informati delle modifiche ai dati sottostanti. In questo modo, possiamo garantire che la nostra applicazione venga notificata ogni volta che è necessario aggiungere un nuovo elemento a RecylerView.

LiveData è inoltre sensibile al ciclo di vita, quindi è possibile utilizzarlo senza preoccuparsi di perdite di memoria o dei crash dell'applicazione che possono verificarsi se si tenta di aggiornare un componente inattivo. LiveData interromperà e riprenderà automaticamente l'osservazione a seconda dello stato dell'attività, del frammento o del servizio di osservazione, quindi notifica i componenti solo quando si trovano in uno stato del ciclo di vita attivo (INIZIO o RIPRISTINATO).

Infine, anche se non lo esploreremo in questo articolo, se sei un fan della popolare libreria RxJava, puoi utilizzare RxJava anziché LiveData: assicurati solo di distruggere i tuoi flussi quando non sono più necessari! In alternativa, puoi utilizzare LiveData insieme a RxJava, aggiungendo LiveDataReactiveStreams al tuo progetto.

Creazione di un progetto Componente architettura Android

Room, ViewModel, DAO, LiveData: abbiamo molto da coprire, quindi crea un progetto Android usando il modello "Svuota attività" e cominciamo!

Aggiunta delle librerie Room, ViewModel e LiveData

Apri il tuo file build.gradle a livello di modulo e aggiungi tutte le librerie di Architecture Components che utilizzeremo durante questo progetto:

dipendenze {implementazione fileTree (dir: libs, include:) implementazione com.android.support:appcompat-v7:28.0.0 implementazione com.android.support.constraint: layout di vincolo: 1.1.3 testImplementazione junit: junit: 4.12 androidTestImplementation com .android.support.test: runner: 1.0.2 androidTestImplementation com.android.support.test.espresso: espresso-core: implementazione 3.0.2 com.android.support:design:28.0.0 // Room // implementazione "android .arch.persistence.room: runtime: 1.1.1 "annotationProcessor" android.arch.persistence.room:compiler:1.1.1 "androidTestImplementation" android.arch.persistence.room:testing:1.1.1 "// ViewModel e LiveData // implementazione "android.arch.lifecycle: extensions: 1.1.1" annotationProcessor "android.arch.lifecycle: compilatore: 1.1.1"}

Creazione dell'entità articolo

Ogni articolo nella lista della spesa dell'utente sarà rappresentato da un'entità, quindi dobbiamo creare una classe di entità e utilizzare le annotazioni per far sapere a Room quali parti di questa classe corrispondono alle entità nel database:

  • Creare una nuova classe Java, denominata "Item".
  • Contrassegna questa classe come entità, usando l'annotazione @Entity:

@Entity public class Item {}

  • Successivamente, è necessario assegnare un nome alla tabella nel database, utilizzando la proprietà "tableName". Se non specifichi un nome, Room utilizzerà il nome della classe per impostazione predefinita:

@Entity (tableName = "item_table") classe pubblica Item {}

  • Ogni entità deve definire almeno un campo come chiave primaria, usando l'annotazione @PrimaryKey. Per semplificare le cose, ogni elemento nel nostro database fungerà da chiave primaria:

@Entity (tableName = "item_table") classe pubblica Item {@PrimaryKey}

  • Successivamente, dobbiamo usare l'annotazione @NonNull per chiarire che il nostro valore di ritorno non può mai essere nullo:

@Entity (tableName = "item_table") classe pubblica Item {@PrimaryKey @NonNull}

  • Per impostazione predefinita, Room utilizza i nomi dei campi come nomi di colonna. In alternativa, puoi specificare un nome di colonna diverso, usando l'annotazione @ColumnInfo:

@Entity (tableName = "item_table") classe pubblica Item {@PrimaryKey @NonNull @ColumnInfo (name = "item")}

  • Quindi, aggiungi un costruttore che accetta "item" come argomento:

private String mItem; public Item (@NonNull String item) {this.mItem = item;}

  • Infine, dobbiamo creare un metodo "getter" per la nostra classe di entità; Sto usando "getItem". La tua classe di entità finita dovrebbe assomigliare a questa:

import android.arch.persistence.room.ColumnInfo; import android.arch.persistence.room.Entity; import android.support.annotation.NonNull; import android.arch.persistence.room.PrimaryKey; @Entity (tableName = "item_table") classe pubblica Item {@NonNull @PrimaryKey @ColumnInfo (name = "item") private String mItem; public Item (@NonNull String item) {this.mItem = item;} public String getItem () {return this.mItem;}}

Inserimento di elementi nel database: creazione di DAO

Il Data Access Object (DAO) è una classe annotata che fornisce un accesso astratto al nostro database Room, mappando le query SQL ai nostri metodi Java.

Esistono diverse domande di praticità che puoi utilizzare nella tua classe DAO, ma in questo articolo ci concentreremo su @Insert. Quando si annota un metodo con @Insert, Room genera un'implementazione che inserisce tutti i parametri nel database in una singola transazione - purché questi parametri siano tutte le classi annotate con @Entity.

Utilizzeremo anche @Query, che è un metodo che ci consente di eseguire operazioni di lettura / scrittura su un database. Sebbene non lo esploreremo in questo articolo, puoi anche utilizzare @Query per filtrare i tuoi dati, passando i parametri del metodo nelle tue query.

Infine, poiché desideriamo che l'interfaccia utente della nostra applicazione si aggiorni automaticamente ogni volta che sono disponibili nuovi dati, utilizzeremo un tipo di valore di ritorno di LiveData nella descrizione del metodo @Query.

Per creare un DAO:

  • Crea una nuova interfaccia denominata "ItemDao" (selezionando "Nuovo> Classe Java", quindi aprendo il menu a discesa "Tipo" e selezionando "Interfaccia".)
  • Apri ItemDAO e segna questa interfaccia come DAO, usando l'annotazione @Dao:

import android.arch.persistence.room.Dao; @Dao interfaccia pubblica ItemDao {

  • Crea un metodo chiamato "getItemList ()" e annotalo con una query SQL che recupererà tutti gli elementi dalla tua "tabella_elemento".

// Ottieni tutti gli articoli // @Query ("SELEZIONA * da item_table") <>> getItemList ();

  • Successivamente, dobbiamo modificare la descrizione del metodo @Query in modo che il risultato venga restituito come oggetto LiveData:

@Query ("SELECT * from item_table") // Aggiungi il tipo di valore "LiveData" alla descrizione del nostro metodo // LiveData<>> getItemList ();

  • La nostra prossima attività è dichiarare un metodo per inserire un elemento, usando l'annotazione @Insert:

@Insert void insert (Item item);

  • Nel nostro metodo @Insert, dobbiamo specificare una strategia di conflitto, quindi la nostra applicazione sa come gestire i dati duplicati, ad esempio se l'utente tenta di aggiungere due volte "Mele" alla propria lista della spesa. Userò OnConflictStrategy.REPLACE, che sostituirà il pezzo di dati più vecchio con il pezzo di dati duplicato più recente, ma in alternativa potresti usare OnConflictStrategy.ABORT, OnConflictStrategy.FAIL, OnConflictStrategy.IGNORE o OnConflictStrategy.

@Insert (onConflict = OnConflictStrategy.REPLACE) void insert (Item item);

Dopo aver completato tutti i passaggi precedenti, il codice finito dovrebbe essere simile al seguente:

import android.arch.lifecycle.LiveData; import android.arch.persistence.room.Dao; import android.arch.persistence.room.Insert; import android.arch.persistence.room.OnConflictStrategy; import android.arch.persistence.room.Query; import java.util.List; @Dao interfaccia pubblica ItemDao {// Annota il metodo insert () // @Insert (onConflict = OnConflictStrategy.REPLACE) void insert (Articolo Item); @Query ("SELECT * from item_table") <>> getItemList (); }

Se stai utilizzando RxJava, il metodo @Query di Room supporta anche i valori di ritorno di Observable, Publisher e Flowable.

SQLite reso semplice: creazione di un database con Room

Room è una libreria di mappatura oggetti SQLite che ti consente di archiviare i dati localmente sul dispositivo dell'utente, in modo che possano accedervi indipendentemente dallo stato della loro connessione Internet. Anche se l'utente fa dispone di una connessione Internet attiva, la memorizzazione dei dati in locale garantisce che l'applicazione non sprechi la larghezza di banda o la batteria del dispositivo scaricando nuovamente gli stessi dati più volte.

Lavorare con SQLite può essere complesso, ma Room utilizza il DAO per inviare query al database SQLite, sottraendo gran parte della complessità dell'utilizzo di tabelle SQL non elaborate.

Vediamo quanto è facile creare un database Room:

  • Creare una nuova classe Java denominata "ItemRoomDatabase".
  • Apri questa classe e contrassegnala come database Room, usando l'annotazione @Database:

import android.arch.persistence.room.Database; Classe pubblica @Database ItemRoomDatabase {}

  • Successivamente, è necessario dichiarare l'entità appartenente a questo database, che in questa istanza è la classe Item. In questa dichiarazione, sto anche specificando che questa è la versione 1 del nostro database e che non vogliamo esportare lo schema del database:

import android.arch.persistence.room.Database; // Elenco delle entità associate a questo database // @Database (entity = {Item.class}, version = 1, exportSchema = false) classe pubblica ItemRoomDatabase {}

  • Quindi, dichiarare che ItemRoomDatabase è astratto e che estende RoomDatabase:

import android.arch.persistence.room.Database; import android.arch.persistence.room.RoomDatabase; @Database (entity = {Item.class}, version = 1, exportSchema = false) classe astratta pubblica ItemRoomDatabase estende RoomDatabase {}

  • Dobbiamo quindi fare riferimento al nostro DAO; che in questo caso è la classe ItemDao:

import android.arch.persistence.room.Database; import android.arch.persistence.room.RoomDatabase; @Database (entity = {Item.class}, version = 1, exportSchema = false) classe astratta pubblica ItemRoomDatabase estende RoomDatabase {abstract pubblico ItemDao itemDao (); }

  • Infine, possiamo creare il nostro oggetto RoomDatabase, che chiamerò "item_list_database":

import android.content.Context; import android.arch.persistence.room.Database; import android.arch.persistence.room.Room; import android.arch.persistence.room.RoomDatabase; @Database (entity = {Item.class}, version = 1, exportSchema = false) classe astratta pubblica ItemRoomDatabase estende RoomDatabase {ItemRoomDatabase INSTANCE privato; abstract pubblico ItemDao itemDao (); getDatabase statico ItemRoomDatabase (contesto di contesto finale) {if (INSTANCE == null) {sincronizzato (ItemRoomDatabase.class) {if (INSTANCE == null) {// Acquisisci un'istanza del database // INSTANCE = Room.databaseBuilder (contesto. getApplicationContext (), ItemRoomDatabase.class, "item_list_database") .build (); }}} restituisce INSTANCE; }}

Non più SQLiteOpenHelper: creazione di un repository

Il repository è una classe che gestisce le operazioni sui dati e gestisce le attività che in genere esegui in una classe SQLiteOpenHelper separata.

Room può gestire dati da più origini, ma nella nostra applicazione recupereremo i dati da un singolo database Room:

  • Crea una nuova classe Java, chiamata "ItemRepository".
  • Aggiungi le variabili membro per i nostri DAO e LiveData:

import android.arch.lifecycle.LiveData; import java.util.List; public class ItemRepository {private ItemDao myItemsDao; LiveData privato<>> itemsList; }

  • Successivamente, aggiungi un costruttore che ottiene un handle per il database e inizializza le variabili membro:

ItemRepository (Applicazione) {ItemRoomDatabase database = ItemRoomDatabase.getDatabase (applicazione); myItemsDao = database.itemDao (); itemsList = myItemsDao.getItemList (); }}

  • Ora è necessario aggiungere un metodo wrapper che restituisce gli articoli come LiveData:

LiveData<>> getAllItems () {return itemsList; }

  • Per assicurarci di non bloccare l'importantissimo thread dell'interfaccia utente principale di Android, chiamerò il metodo insert () su un thread non dell'interfaccia utente, utilizzando AsyncTask:

public void insert (Item item) {new newAsyncTask (myItemsDao) .execute (item); }

  • Implementa insertAsyncTask come classe interna e il codice completato dovrebbe essere simile al seguente:

import android.app.Application; import android.arch.lifecycle.LiveData; import android.os.AsyncTask; import java.util.List; public class ItemRepository {private ItemDao myItemsDao; LiveData privato<>> itemsList; LiveData<>> getAllItems () {return itemsList; } public void insert (Item item) {// Esegui su un thread in background // new newAsyncTask (myItemsDao) .execute (item); } classe statica privata newAsyncTask estende AsyncTask {Private ItemDao myAsyncDao; newAsyncDao (ItemDao dao) {myAsyncDao = dao; } @Override protetto Void doInBackground (Final Item ... params) {myAsyncDao.insert (params); restituisce null; }} ItemRepository (Applicazione) {ItemRoomDatabase database = ItemRoomDatabase.getDatabase (applicazione); myItemsDao = database.itemDao (); itemsList = myItemsDao.getItemList (); }}

Modifiche alla configurazione sopravvissute: creazione di ViewModel

Successivamente, dobbiamo creare una classe ViewModel, che conterrà e gestirà tutti i dati relativi all'interfaccia utente dell'applicazione e fornirà un livello di comunicazione tra il repository e l'interfaccia utente dell'app.

Gli oggetti ViewModel sono progettati per sopravvivere alle modifiche alla configurazione, quindi anche se Android distrugge e ricrea la tua attività o frammento, i dati di ViewModel saranno immediatamente disponibili alla prossima istanza di tale attività o frammento.

Poiché il sistema conserva un'istanza ViewModel per tutto il ciclo di vita dell'applicazione, è fondamentale che ViewModel non contenga riferimenti diretti ad attività, frammenti o viste, poiché ciò può causare perdite a seguito di una modifica della configurazione.

Per garantire che i nostri oggetti LiveData possano sopravvivere alle modifiche alla configurazione di Android, li memorizzeremo nel nostro ViewModel.

Implementiamo tutto quanto sopra, in una classe ViewModel:

  • Creare una nuova classe "ItemViewModel".
  • Assicurati che ItemViewModel estenda AndroidViewModel:

import android.arch.lifecycle.AndroidViewModel; classe pubblica ItemViewModel estende AndroidViewModel {}

  • Successivamente, aggiungi le variabili dei membri privati ​​per contenere un riferimento al repository e all'elenco di elementi:

import android.arch.lifecycle.AndroidViewModel; import android.arch.lifecycle.LiveData; import java.util.List; classe pubblica ItemViewModel estende AndroidViewModel {private ItemRepository myRepository; LiveData privato<>> allItems; }

  • Aggiungi un costruttore che ottiene un riferimento al repository e recupera il suo elenco di elementi:

public ItemViewModel (Applicazione) {super (applicazione); myRepository = new ItemRepository (applicazione); allItems = myRepository.getAllItems (); }

  • Per incorporare il componente LiveData nella nostra app, è necessario includere il tipo di campo "LiveData" nel nostro ViewModel. Sto anche aggiungendo un metodo "getter", che recupererà il nostro elenco di elementi:

LiveData<>> getAllItems () {return allItems; }

  • Infine, crea un metodo insert () wrapper che chiama il metodo insert () del repository:

public void insert (Item item) {myRepository.insert (item); }

Il codice finito dovrebbe essere simile al seguente:

import android.app.Application; import android.arch.lifecycle.AndroidViewModel; import android.arch.lifecycle.LiveData; import java.util.List; classe pubblica ItemViewModel estende AndroidViewModel {private ItemRepository myRepository; LiveData privato<>> myAllItems; public ItemViewModel (Applicazione) {super (applicazione); myRepository = new ItemRepository (applicazione); myAllItems = myRepository.getAllItems (); } LiveData<>> getAllItems () {return myAllItems; } public void insert (Item item) {myRepository.insert (item); }}

Visualizzazione dei dati dell'architettura Android: creazione di RecyclerView

A questo punto, abbiamo implementato tutti i componenti dell'architettura Android di cui abbiamo bisogno per conservare i dati localmente, ma se l'utente ha mai intenzione di vedere uno di questi dati, quindi dobbiamo creare la nostra interfaccia utente.

Visualizzerò i dati come RecylerView a scorrimento continuo, quindi non c'è limite al numero di articoli che l'utente può aggiungere alla propria lista della spesa! Per impedire a questo articolo di crescere senza controllo, ho intenzione di sfogliare il processo di implementazione di RecyclerView, ma se desideri ulteriori informazioni, consulta il nostro articolo "Come utilizzare le visualizzazioni di riciclatore".

Crea un nuovo file res / layout, chiamato "item_layout" e aggiungi quanto segue:

Quindi, crea un nuovo file res / layout denominato "my_recylerview" e implementa il componente RecylerView:

Apri il tuo file activity_main.xml e aggiungi RecylerView al layout, usando il etichetta. Mentre sono qui, aggiungo anche alcuni altri elementi dell'interfaccia utente:

// Includi RecylerView //

Il passaggio successivo consiste nella creazione di un adattatore che estende la classe RecylerView.Adapter:

import android.content.Context; import android.view.LayoutInflater; import android.support.v7.widget.RecyclerView; import android.widget.TextView; import android.view.View; import android.view.ViewGroup; import java.util.List; classe pubblica ItemListAdapter estende RecyclerView.Adapter {class ItemViewHolder estende RecyclerView.ViewHolder {private final TextView textView; private ItemViewHolder (Visualizza itemView) {super (itemView); textView = itemView.findViewById (R.id.textView); }} Elenco privato myItems; layout finale privatoInflater myInflater; ItemListAdapter (Context context) {myInflater = LayoutInflater.from (context); } @Override public ItemViewHolder onCreateViewHolder (ViewGroup parent, int viewType) {Visualizza itemView = myInflater.inflate (R.layout.item_layout, parent, false); ritorna nuovo ItemViewHolder (itemView); } @Override void pubblico onBindViewHolder (ItemViewHolder holder, int position) {Item current = myItems.get (position); holder.textView.setText (current.getItem ()); } @Override public int getItemCount () {if (myItems! = Null) restituisce myItems.size (); altrimenti restituisce 0; } void setItems (Elenco items) {myItems = items; notifyDataSetChanged (); }}

Ora abbiamo svolto tutto il lavoro in background, aperto MainActivity e aggiunto RecylerView al metodo onCreate () dell'applicazione:

import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; classe pubblica MainActivity estende AppCompatActivity {@Override protetto void onCreate (Bundle savedInstanceState) {super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); RecyclerView myRecyclerView = findViewById (R.id.recyclerview); final ItemListAdapter myAdapter = new ItemListAdapter (this); myRecyclerView.setAdapter (myAdapter); myRecyclerView.setLayoutManager (nuovo LinearLayoutManager (questo)); }}

Costruire l'interfaccia utente: tocchi finali

Sebbene non sia essenziale fornire le funzionalità di base della nostra app, sto applicando alcuni stili alla nostra interfaccia utente. Apri il file styles.xml e aggiungi quanto segue:

Applica questi stili alla tua app, aprendo Manifest e modificando Android: attributi del tema per fare riferimento a questi nuovi stili:

Testare il tuo progetto

Installa questo progetto su uno smartphone o tablet Android o su un dispositivo virtuale Android (AVD). RecylerView dovrebbe caricarsi, ma c'è un problema: non ha dati da visualizzare!

Il passaggio successivo consiste nel creare un'attività in cui l'utente può aggiungere elementi al database di Room.

Creazione dell'attività di immissione dati

Inizia creando una nuova attività, denominata NewItemActivity e un corrispondente file di risorse di layout "activity_add_item.xml".

Nel file "activity_add_item.xml", ho intenzione di aggiungere un EditText in cui l'utente può digitare diversi articoli e un pulsante "Salva" in modo che possano salvare ogni articolo nella loro lista della spesa.

Questo ci dà il seguente layout:

Quindi, apri la tua classe NewItemActivity e digli di gonfiare il layout "activity_add_item":

import android.support.v7.app.AppCompatActivity; import android.os.Bundle; classe pubblica NewItemActivity estende AppCompatActivity {@Override public void onCreate (Bundle savedInstanceState) {super.onCreate (savedInstanceState); setContentView (R.layout.activity_add_item); }}

Non dimenticare di aggiungere NewItemActivity al tuo manifest:

Aggiunta di navigazione: creazione di un'icona della barra delle azioni

Successivamente, aggiungerò un'icona della barra delle azioni che consentirà all'utente di spostarsi da MainActivity a NewItemActivity.

Le icone della barra delle azioni vengono definite all'interno di un file di risorse del menu, che si trova all'interno della directory "res / menu". Se il tuo progetto non contiene una directory "menu", dovrai crearne una:

  • Fai clic tenendo premuto il tasto Ctrl sulla directory "res" del tuo progetto e seleziona "Nuovo> Directory risorse Android".
  • Apri il menu a discesa "Tipo di risorsa" e seleziona "menu".
  • Il "Nome directory" dovrebbe aggiornarsi automaticamente al "menu", ma in caso contrario dovrai rinominarlo manualmente. Fai clic su "OK".

Ora puoi creare il file di risorse del menu:

  • Fai clic tenendo premuto il tasto Ctrl sulla directory "menu" del progetto e seleziona "Nuovo> File delle risorse del menu".
  • Denominare questo file "my_menu".
  • Fai clic su "OK".
  • Apri il file "my_menu.xml" e aggiungi quanto segue:

Questo menu fa riferimento a una stringa "add_item", quindi apri il file res / valori / strings.xml del tuo progetto e crea questa risorsa:

Demo RoomLiveData Aggiungi articolo

Successivamente, dobbiamo creare l'icona "add_item" della barra delle azioni:

  • Seleziona "File> Nuovo> Risorse immagine" dalla barra degli strumenti di Android Studio.
  • Imposta il menu a discesa "Tipo di icona" su "Barra delle azioni e icone delle schede".
  • Fai clic sul pulsante "Clip Art".
  • Scegli un disegno; Sto usando "aggiungi cerchia".

  • Fai clic su "OK".
  • Per assicurarti che la nostra icona della barra delle azioni si distingua, apri il menu a discesa "Tema" e seleziona "HOLO_DARK".
  • Denominare questa icona "add_icon".
  • "Fai clic su" Avanti ", quindi su" Fine ".

Ora abbiamo creato la nostra icona della barra delle azioni, dobbiamo solo aggiungerla alla nostra MainActivity e dire alla nostra applicazione di avviare NewItemActivity ogni volta che l'utente interagisce con questa icona:

import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.Menu; import android.view.MenuItem; classe pubblica MainActivity estende AppCompatActivity {public static final int REQUEST_CODE = 1; @Override protetto void onCreate (Bundle savedInstanceState) {super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); RecyclerView myRecyclerView = findViewById (R.id.recyclerview); final ItemListAdapter myAdapter = new ItemListAdapter (this); myRecyclerView.setAdapter (myAdapter); myRecyclerView.setLayoutManager (nuovo LinearLayoutManager (questo)); } @Override pubblica booleana onCreateOptionsMenu (menu Menu) {getMenuInflater (). Inflate (R.menu.my_menu, menu); ritorno vero; } @Override pubblico booleano onOptionsItemSelected (voce MenuItem) {switch (item.getItemId ()) {case R.id.add_item: intent intent = new Intent (MainActivity.this, NewItemActivity.class); startActivityForResult (intent, REQUEST_CODE); } return false; }}

Test del tuo progetto: prendine due!

Installa il progetto aggiornato sul tuo dispositivo Android o AVD e dovresti incontrare un'icona della barra delle azioni che, una volta toccata, avvia NewItemActivity. Attualmente, è possibile digitare in EditText, ma non importa quante volte si tocca il pulsante "Salva", nessun nuovo elemento verrà aggiunto al database sottostante.

In questa sezione, recupereremo l'input dell'utente dal EditText, lo aggiungeremo al nostro database Room e quindi visualizzeremo questo nuovo elemento in RecylerView.

Recupero dell'input dell'utente

Cominciamo con l'attività più semplice: aggiornare il nostro NewItemActivity in modo che ogni volta che l'utente tocca il pulsante "Salva", il contenuto di EditText verrà inserito in un Intento e inviato al nostro MainActivity.

Ecco la classe NewItemActivity completata:

import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.Button; import android.widget.EditText; import android.content.Intent; import android.text.TextUtils; import android.view.View; classe pubblica NewItemActivity estende AppCompatActivity {private EditText myEditText; stringa statica finale pubblica EXTRA = ".REPLY"; @Override public void onCreate (Bundle savedInstanceState) {super.onCreate (savedInstanceState); setContentView (R.layout.activity_add_item); myEditText = findViewById (R.id.add_item); Pulsante Button finale = findViewById (R.id.save_item); button.setOnClickListener (new View.OnClickListener () {public void onClick (View view) {Intent reply = new Intent (); if (TextUtils.isEmpty (myEditText.getText ())) {setResult (RESULT_CANCELED, reply);} else {String item = myEditText.getText (). ToString (); reply.putExtra (EXTRA, item); setResult (RESULT_OK, reply);} finish ();}}); }}

Aggiornamento del database di Room

Ogni volta che l'utente tocca "Salva", è necessario aggiungere i propri input al database, quindi utilizzare LiveData per aggiornare RecylerView.

Per iniziare, apri la classe MainActivity e aggiungi ViewModel al metodo onCreate ():

myItemViewModel = ViewModelProviders.of (this) .get (ItemViewModel.class);

Tieni presente che il sistema può chiamare il metodo onCreate () più volte durante il ciclo di vita dell'Attività, ad esempio a seguito di una modifica della configurazione. Ogni volta che questa attività viene distrutta e quindi ricreata, riceverà la stessa istanza myItemViewModel. Poiché ViewModel viene ripristinato automaticamente, non è necessario aggiungere alcuna logica per gestire le modifiche alla configurazione.

Successivamente, dobbiamo recuperare l'input dell'utente, aggiungendo un callback onActivityResult () per NewItemActivity:

public void onActivityResult (int requestCode, int resultCode, Intent data) {super.onActivityResult (requestCode, resultCode, data);

Se l'attività restituisce RESULT_OK, chiameremo il metodo insert () e inseriremo l'articolo restituito nel database:

if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {Item item = new Item (data.getStringExtra (NewItemActivity.EXTRA)); myItemViewModel.insert (voce); }

Ora l'utente può aggiungere nuovi elementi al database, dobbiamo assicurarci che i nostri aggiornamenti di RecylerView riflettano queste modifiche.

Poiché stiamo utilizzando LiveData, ogni aggiunta al database attiverà un callback onChanged (). Possiamo usare questo callback per dire alla nostra applicazione come reagire a queste modifiche al database:

@Override public void onChanged (@Nullable Final List articoli) {// Aggiorna l'interfaccia utente // myAdapter.setItems (articoli); }

Successivamente, dobbiamo creare la relazione Observer / Observable, collegando l'oggetto Observer all'oggetto LiveData, usando il metodo observ ():

myItemViewModel.getAllItems (). observ (questo, nuovo osservatore<>>() {

A questo punto, l'oggetto Observer è iscritto all'oggetto LiveData e riceverà una notifica ogni volta che cambiano i dati sottostanti.

Poiché LiveData è consapevole del ciclo di vita, invocherà il callback onChanged () solo quando l'attività è in uno stato attivo, quindi non è necessario utilizzare il metodo onStop () per dire alla nostra applicazione di interrompere l'osservazione dei dati.

Dopo aver implementato tutto questo nella tua MainActivity, il tuo codice dovrebbe assomigliare a questo:

import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; import android.os.Bundle; import android.content.Intent; import android.view.Menu; import android.view.MenuItem; import android.arch.lifecycle.Observer; import android.arch.lifecycle.ViewModelProviders; import java.util.List; import android.support.annotation.Nullable; classe pubblica MainActivity estende AppCompatActivity {public static final int REQUEST_CODE = 1; privato ItemViewModel myItemViewModel; @Override protetto void onCreate (Bundle savedInstanceState) {super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); Barra degli strumenti myToolbar = (Barra degli strumenti) findViewById (R.id.toolbar); setSupportActionBar (MiaBarra); RecyclerView myRecyclerView = findViewById (R.id.recyclerview); final ItemListAdapter myAdapter = new ItemListAdapter (this); myRecyclerView.setAdapter (myAdapter); myRecyclerView.setLayoutManager (nuovo LinearLayoutManager (questo)); // Recupera ViewModel // myItemViewModel = ViewModelProviders.of (this) .get (ItemViewModel.class); // Osserva LiveData e invia una notifica ogni volta che i dati cambiano // myItemViewModel.getAllItems (). Observ (questo, nuovo Observer<>> () {@Override public void onChanged (@Nullable Final List articoli) {// Aggiorna l'interfaccia utente // myAdapter.setItems (articoli); }}); } @Override pubblica booleana onCreateOptionsMenu (menu Menu) {getMenuInflater (). Inflate (R.menu.my_menu, menu); ritorno vero; } @Override pubblico booleano onOptionsItemSelected (voce MenuItem) {switch (item.getItemId ()) {case R.id.add_item: intent intent = new Intent (MainActivity.this, NewItemActivity.class); startActivityForResult (intent, REQUEST_CODE); } return false; } public void onActivityResult (int requestCode, int resultCode, Intent data) {super.onActivityResult (requestCode, resultCode, data); if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {Item item = new Item (data.getStringExtra (NewItemActivity.EXTRA)); myItemViewModel.insert (voce); }}}

Test dell'app completata

Ora dovresti essere in grado di aggiungere elementi al database Room e vederli apparire automaticamente in RecylerView. Mettiamo questo alla prova:

  • Installa il progetto aggiornato sul tuo smartphone Android, tablet o AVD.
  • Dai un tocco all'icona della barra delle azioni.
  • Immettere un elemento in EditText.
  • Tocca "Salva" e verrai riportato a MainActivity, dove RecylerView dovrebbe essere aggiornato per includere il tuo nuovo elemento.
  • Risciacqua e ripeti per aggiungere altri elementi al tuo elenco.

Per verificare che i dati persistano per tutte le sessioni, chiudere l'applicazione e quindi riavviarla; l'applicazione dovrebbe avviarsi con l'elenco già popolato.

Dovresti anche testare come l'applicazione gestisce i dati duplicati. Poiché stiamo usando la strategia di conflitto REPLACE, ogni volta che provi a inserire lo stesso oggetto due volte l'app cancellerà il pezzo di dati originale, quindi lo sostituirà con i "nuovi" dati. Prova ad aggiungere un elemento già esistente nel tuo elenco, per verificare che l'applicazione stia davvero sostituendo il vecchio con il nuovo.

Puoi anche scaricare l'app completata da GitHub.

Avvolgendo

In questo articolo, abbiamo avuto un'introduzione pratica a diversi componenti chiave dell'architettura Android e abbiamo visto come possono aiutare a risolvere molti dei problemi più comuni incontrati dagli sviluppatori Android, tra cui la persistenza dei dati, la gestione del ciclo di vita ed evitare perdite di memoria.

Ci sono altri problemi comuni che vorresti vedere l'indirizzo di Android Architecture Components? Fateci sapere nei commenti qui sotto!

C'era una diviione molto chiara tra martphone di facia media e di facia alta. La grande notizia è che le linee ono empre più fumate negli ultimi anni. Oggi è facile trovare un telef...

Ci ono molti fantatici telefoni convenienti in India. e tai cercando il potere di punta, però, il più delle volte dovrai laciare cadere una buona fetta di denaro, con alcuni martphone con un...

Articoli Recenti