Autore Topic: [Facile] Guida di base ai Fragment  (Letto 9674 volte)

Offline MarcoDuff

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1073
  • Respect: +202
    • Google+
    • marcoduff
    • Mostra profilo
    • MarcoDuff's Blog
  • Dispositivo Android:
    Samsung Galaxy Nexus
  • Play Store ID:
    MarcoDuff
  • Sistema operativo:
    Windows 7
[Facile] Guida di base ai Fragment
« il: 05 Ottobre 2012, 15:17:26 CEST »
+11
Livello di difficoltà: facile
Target SDK: 15
Min SDK: 4 (richieste libreria compatibility v4)

Sono in molti ad avere problemi con i fragment (compresi gli sviluppatori di Google), quindi creo questo tutorial per spiegare come usarli, come fare dialogare un fragment con l'activity che lo contiene, come fare dialogare due fragment.

L'esempio è quello standard, una semplice applicazione con due "pagine" (per il momento le chiamiamo in questo modo):
- Una pagina che contiene una lista di oggetti;
- una pagina che contiene il dettaglio di un oggetto.

Nel caso in cui il nostro dispositivo sia in modalità "portrait" vogliamo visualizzare una pagina per volta.
Nel caso in cui il nostro dispositivo sia in modalità "landscape" vogliamo visualizzare tutte e due le pagine: la lista a sinistra e il dettaglio a destra.

Tenterò in tutti i modi di seguire un punto di vista progettuale nella spiegazione dell'esempio in modo da poter estendere questi passi a tutti i possibili casi dei vostri progetti presenti e futuri.

Iniziamo con l'aspetto più difficile della progettazione di questa semplice applicazione: le responsabilità da assegnare ai componenti.

Le classi di tipo Fragment devono avere come responsabilità la sola visualizzazione dei dati (in un pattern MVC si occupano esclusivamente del livello View).
Le classi di tipo FragmentActivity devono avere come responsabilità il solo controllo delle viste (in un pattern MVC si occupano esclusivamente del livello Controller).

Qui già si intuisce la grossissima differenza tra le API senza i Fragment (dove le Activity si occupavano sia del View che del Controller) e con i Fragment (dove le FragmentActivity abbandonano del tutto l'onere della visualizzazione). Tantissime persone si trovano spiazzate dai Fragment proprio perché sono abituate a fare con le Activity la parte della visualizzazione che adesso non possono più fare.

Sotto un punto di vista progettuale, quindi, l'inserimento dei Fragment ha portato un notevole balzo in avanti aumentando (o meglio inserendo) in modo netto la differenza tra View e Controller nel framework android.

Off-Topic:
C'è anche da dire che questa differenza, non avendo Google deprecato tutti i metodi di tipo View delle Activity, deve essere forzata e molto ben gestita dallo sviluppatore!

Una volta capito come assegnare le priorità possiamo passare alla progettazione del flusso dei dati!

Una volta aperta l'applicazione questa deve visualizzare due tipologia di layout diversi: uno nel caso in cui il dispositivo è in modalità "Portrait" ed un altro nel caso in cui è in "Landscape".

Modalità Portrait
Avviata l'applicazione deve essere visualizzata una pagina che visualizza la lista degli oggetti.
Non appena tocco un oggetto della lista deve essere visualizzata una nuova pagina che ne visualizza il dettaglio.

Questo significa che in modalità Portrait avrò bisogno di due differenti layout xml, uno per rappresentare la prima pagina (che chiamo activity_home) ed un altro che rappresenta la seconda pagina (che chiamo activity_detail).

/res/layout/activity_home
Codice (XML): [Seleziona]
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >
        <fragment
                android:name="com.marcoduff.fragmentcommunication.fragment.MyListFragment"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
</FrameLayout>

/res/layout/activity_detail
Codice (XML): [Seleziona]
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/detailContainer"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

Modalità Landscape
Avviata l'applicazione deve essere visualizzata una pagina che visualizza la lista degli oggetti a sinistra e il dettaglio dell'oggetto che seleziono nella lista a destra.

Questo significa che in modalità Landscape avrò bisogno di un solo layout xml (che chiamo activity_home) che metterò nella cartella layout-land per far capire ad android che questo deve essere utilizzato solo ed esclusivamente quando il dispositivo è in modalità landscape.

/res/layout-land/activity_home
Codice (XML): [Seleziona]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal" >
        <fragment
                android:name="com.marcoduff.fragmentcommunication.fragment.MyListFragment"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1" />
        <FrameLayout
                android:id="@+id/detailContainer"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="2" />
</LinearLayout>

Notate le analogie che vi sono in questi due layout.
- In tutti e due i casi la lista viene gestita dal fragment MyListFragment;
- In tutti e due i casi il layout che visualizza il dettaglio è un FrameLayout con id detailContainer.

Fatti gli xml dei layout (ovvero definite visivamente le View) iniziamo a occuparci di chi si occupa di questi: i Fragment.

Avendo due pagine da visualizzare abbiamo bisogno di due Fragment: uno che si occupa della visualizzazione della lista (che chiamo MyListFragment) mentre un altro che si occupa della visualizzazione del dettaglio (che chiamo MyDetailFragment).

A questo punto abbiamo una problematica: i due fragment devono in qualche modo comunicare tra di loro (quando premo un oggetto nella lista del fragment MyListFragment l'oggetto deve essere visualizzato nel fragment MyDetailFragment). Ma attenzione, proprio all'inizio di questo articolo abbiamo detto che i Fragment sono a livello View e di conseguenza non è loro responsabilità la comunicazione... anzi è un grave errore delegare ad un Fragment la comunicazione (ed dirò di più: l'esistenza) di un altro Fragment!!!

I Fragment devono affidarsi all'activity che li contiene. E' lei, che essendo ad un livello Controller, si occupa di gestire e smistare gli eventi.

Per fare questo il fragment MyListFragment deve inoltrare il click sulla lista all'activity che lo contiene, mentre il fragment MyDetailFragment deve ricevere dall'activity che lo contiene l'oggetto da visualizzare.

Il fragment MyListFragment deve quindi possedere al suo interno un meccanismo di callback verso l'activity. Questo meccanismo di solito viene risolto mediante l'uso di una interfaccia (che chiamo OnMyListFragmentItemClick). Ogni qual volta che viene premuto un oggetto della lista, il fragment deve soltanto occuparsi di fare una chiamata di Callback all'activity.

Questa azione presuppone due cose:
- L'activity deve implementare l'interfaccia di Callback in modo da essere abilitata alla ricezione dei messaggio provenienti dal Fragment;
- Il fragment deve riconoscere al momento dell'onAttach ad una activity se questa è compatibile o meno con l'interfaccia di Callback (se lo è viene memorizzato un riferimento a questa activity, altrimenti viene creato un Callback fittizio).

Ecco il codice di MyListFragment
Codice (Java): [Seleziona]
package com.marcoduff.fragmentcommunication.fragment;

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;

/**
 * Fragment che si occupa della visualizzazione di una lista di String.
 *
 * @author MarcoDuff [url=http://www.marcoduff.com/]MarcoDuff&#39;s Blog[/url]
 */

public class MyListFragment extends ListFragment {
        /**
         * Interfaccia di Callback per comunicare con l'activity che contiene il Fragment.
         */

        public static interface OnMyListFragmentItemClick {
                public void onClick(String item);
        }
       
        /**
         * Riferimento all'activity di Callback.
         */

        private OnMyListFragmentItemClick mActivityAttached;
       
        /**
         * Oggetti della lista da visualizzare.
         */

        private final String[] mObjectArray = new String[] {"Item1", "Item2", "Item3", "Item4", "Item5"};

        @Override
        public void onAttach(Activity activity) {
                super.onAttach(activity);
               
                if(activity instanceof OnMyListFragmentItemClick) {
                        // L'activity che contiene il fragment è compatibile con l'interfacci di Callback, mi memorizzo il riferimento.
                        mActivityAttached = (OnMyListFragmentItemClick)activity;
                }
                else {
                        // L'activity non è compatibile, creo un riferimento fittizzio.
                        mActivityAttached = new OnMyListFragmentItemClick() {
                                public void onClick(String item) {}
                        };
                }
        }
       
        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
                super.onActivityCreated(savedInstanceState);
               
                setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, mObjectArray));
        }
       
        @Override
        public void onListItemClick(ListView l, View v, int position, long id) {
                super.onListItemClick(l, v, position, id);
                // Richiamo il metodo di callback
                mActivityAttached.onClick(mObjectArray[position]);
        }
}

Off-Topic:
Notate due cose: 1. nel caso in cui l'activity non è compatibile vado a generare un oggetto fittizio in modo che il riferimento all'activity (variabile mActivityAttached) non sia mai null e non dover inserire nel codice tanti test del tipo if(mActivityAttached!=null). 2. Il metodo di callback non invio troppe informazioni inutili per lo strato di Controller ma esclusivamente le informazioni che mi servono (ovvero l'oggetto cliccato)

Dall'altra parte, invece avrò il fragment MyDetailFragment che deve occuparsi della visualizzazione dell'oggetto. L'oggetto gli verrà passato dallo strato di Controller tramite Bundle negli arguments. Quindi il fragment si limita a leggere gli arguments e visualizzare il testo al suo interno.

Ecco il codice di MyDetailFragment
Codice (Java): [Seleziona]
package com.marcoduff.fragmentcommunication.fragment;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

/**
 * Fragment che si occupa della visualizzazione dei dettagli.
 *
 * @author MarcoDuff [url=http://www.marcoduff.com/]MarcoDuff&#39;s Blog[/url]
 */

public class MyDetailFragment extends Fragment {
        /**
         * Chiave per l'argomento che viene passato.
         */

        public static final String ARGUMENT_ITEM = "ITEM";
       
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
                super.onCreateView(inflater, container, savedInstanceState);
                TextView textView = new TextView(getActivity());
                textView.setGravity(Gravity.CENTER);
                Bundle arguments = getArguments();
                textView.setText("Item selected: "+arguments.getString(ARGUMENT_ITEM));
                return textView;
        }
}

Finito con lo strato di View saliamo di un livello, passiamo ai Controller ovvero alle FragmentActivity!

Una parte di fase di Controller (per fortuna) la fa il framework android. E' lui infatti a decidere il file xml più opportuno da caricare in base allo stato del nostro dispositivo. E' il framework infatti a decidere di caricare il nostro file di layout activity_home proveniente dalla cartella layout o dalla cartella layout-land in base all'orientamento del dispositivo. La nostra activity di partenza (che chiamo HomeActivity) si limita soltanto ad indicare quale layout caricare ed ad implementare il metodo di callback onClick dell'interfaccia MyListFragment.OnMyListFragmentItemClick. Ed è sopratutto in questo metodo che questo Controller deve capire se è possibile visualizzare il dettaglio senza richiamare una nuova Activity o se ha la necessità di richiamare una nuova Activity.

Come fa a capirlo? Semplicemente deve controllare se nella View corrente esiste o meno un layout capace di contenere il dettaglio, ovvero un layout a cui noi abbiamo assegnato l'id detailContainer. Se questo esiste vuol dire che ho spazio per visualizzare il dettaglio, altrimenti ho necessità di lanciare una nuova Activity.

Ecco il codice della HomeActivity
Codice (Java): [Seleziona]
package com.marcoduff.fragmentcommunication.ui;

import com.marcoduff.fragmentcommunication.R;
import com.marcoduff.fragmentcommunication.fragment.MyDetailFragment;
import com.marcoduff.fragmentcommunication.fragment.MyListFragment;

import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.View;

/**
 * Activity principale.
 *
 * @author MarcoDuff [url=http://www.marcoduff.com/]MarcoDuff&#39;s Blog[/url]
 */

public class HomeActivity extends FragmentActivity implements MyListFragment.OnMyListFragmentItemClick {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                // Mi limito a caricare il layout, è android che inserirà in modo opportuno quello portrait o landscape (o altri!).
                setContentView(R.layout.activity_home);
        }

        @Override
        public void onClick(String item) {
                // Preparo l'argomento da passare al Fragment o all'Activity. Questo argomento contiene l'oggetto cliccato.
                Bundle arguments = new Bundle();
                arguments.putString(MyDetailFragment.ARGUMENT_ITEM, item);
               
                // Recupero la vista detailContainer
                View detailView = findViewById(R.id.detailContainer);
                if(detailView==null) {
                        // Non esiste spazio per la visualizzazione del dattagli, quindi ho necessità di lanciare una nuova activity.
                        // Carico gli arguments nell'intent di chiamata.
                        Intent intent = new Intent(this, DetailActivity.class);
                        intent.putExtras(arguments);
                        startActivity(intent);
                }
                else {
                        // Esiste lo spazio, procedo con la creazione del Fragment!
                        MyDetailFragment myDetailFragment = new MyDetailFragment();
                        // Imposto gli argument del fragment.
                        myDetailFragment.setArguments(arguments);
                       
                        // Procedo con la sostituzione del fragment visualizzato.
                        FragmentManager fragmentManager = this.getSupportFragmentManager();
                        fragmentManager.beginTransaction()
                        .replace(R.id.detailContainer, myDetailFragment)
                        .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
                        .commit();
                }
        }
}

L'ultimo pezzo del progetto è dato proprio dall'activity richiamata dalla HomeActivity nel caso in cui non vi sia spazio per visualizzare il dettaglio. L'unica responsabilità di questa activity (che chiamo DetailActivity) è di costruire il corretto Bundle da passare al fragment MyDetailFragment in base all'intent di chiamata.

Questo è il suo codice:
Codice (Java): [Seleziona]
package com.marcoduff.fragmentcommunication.ui;

import com.marcoduff.fragmentcommunication.R;
import com.marcoduff.fragmentcommunication.fragment.MyDetailFragment;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;

/**
 * Activity che si occupa del dettaglio.
 *
 * @author MarcoDuff [url=http://www.marcoduff.com/]MarcoDuff&#39;s Blog[/url]
 */

public class DetailActivity extends FragmentActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_detail);
               
                // Crea gli argomenti da passare al fragment in base all'intent di chiamata.
                Bundle arguments = getIntent().getExtras();
               
                // Crea il fragment.
                MyDetailFragment myDetailFragment = new MyDetailFragment();
                myDetailFragment.setArguments(arguments);
               
                // Visualizza il fragment.
                FragmentManager fragmentManager = this.getSupportFragmentManager();
                fragmentManager.beginTransaction()
                .replace(R.id.detailContainer, myDetailFragment)
                .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
                .commit();
        }
}

Conclusioni:
I Fragment, se utilizzati in modo opportuno e con le responsabilità che gli appartengono, hanno aumentato il distacco tra il Controller e il View nel framework android. Se si seguono semplici regole di responsabilità si riesce a scrivere un codice pulito, scalabile e molto mantenibile.

Off-Topic:
Se questo tutorial ti è stato utile premi il tasto nella testata di questo messaggio che devo raggiungere Ricky` che si è paurosamente allontanato! XD

Bibliografia:

Offline eloc

  • Nuovo arrivato
  • *
  • Post: 1
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    tablet
Re:[Facile] Guida di base ai Fragment
« Risposta #1 il: 16 Ottobre 2012, 04:27:17 CEST »
0
Ciao,
interessante tutorial sui fragment.
Premetto che sono nuovo nel mondo android e che stò cercando d'inparare.
Ho provato a fare un progettino demo con gli script da te evidenziati, ma non riesco a compilare dato che mi segnala due errori:
  • HomeActivity su  ".replace(R.id.detailContainer, myDetailFragment)" segnala di rosso il replace, motivavazione: The method replace(int, Fragment) in the type FragmentTransaction is not applicable for the arguments (int, MyDetailFragment)
  • DetailActivity, stesso errore

Cosa sbaglio?????
Grazie

Offline MarcoDuff

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1073
  • Respect: +202
    • Google+
    • marcoduff
    • Mostra profilo
    • MarcoDuff's Blog
  • Dispositivo Android:
    Samsung Galaxy Nexus
  • Play Store ID:
    MarcoDuff
  • Sistema operativo:
    Windows 7
Re:[Facile] Guida di base ai Fragment
« Risposta #2 il: 17 Ottobre 2012, 18:12:30 CEST »
0
Sicuro che MyDetailFragment faccia l'extend corretto a Fragment?

Offline MarcoDuff

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1073
  • Respect: +202
    • Google+
    • marcoduff
    • Mostra profilo
    • MarcoDuff's Blog
  • Dispositivo Android:
    Samsung Galaxy Nexus
  • Play Store ID:
    MarcoDuff
  • Sistema operativo:
    Windows 7
Re:[Facile] Guida di base ai Fragment
« Risposta #3 il: 17 Ottobre 2012, 18:21:57 CEST »
0
Mi sono imbattuto in un altro tutorial scritto da bradipao sui fragment che mi ero totalmente dimenticato!

Questo tutorial non e' altro che un doppione di quello, quindi prima di scrivere qui vi prego di dare una lettura a quel tutorial che e' gia' pieno di commenti (meglio ancora se continuiamo la discussione sui fragment direttamente li).

Ecco il link: [medio] Introduzione ai Fragment - Android Developers Italia

Grazie!

Offline lelletta

  • Utente junior
  • **
  • Post: 68
  • Respect: 0
    • Mostra profilo
Re:[Facile] Guida di base ai Fragment
« Risposta #4 il: 05 Novembre 2012, 21:44:06 CET »
0
Ciao MarcoDuff,
ottima guida. Volevo chiederti qualche info ulteriore in merito all'MVC. Quindi nel caso dei fragment abbiamo View=fragment Controll=FActivity.
1. se dovessi recuperare/inserire dati dal/nel Db (nel mio caso specifico ho realizzato un DAO quindi una mappatura manuale delle tabelle + classi model) i vari metodi (CRUD) li chiamo nelle fragment?
2. sempre in merito all'MVC, le actvity normali (no fragment) sono delle View? in merito ci sono svariati opinioni. cosa ne pensi?
Grazie

Offline MarcoDuff

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1073
  • Respect: +202
    • Google+
    • marcoduff
    • Mostra profilo
    • MarcoDuff's Blog
  • Dispositivo Android:
    Samsung Galaxy Nexus
  • Play Store ID:
    MarcoDuff
  • Sistema operativo:
    Windows 7
Re:[Facile] Guida di base ai Fragment
« Risposta #5 il: 08 Novembre 2012, 18:27:48 CET »
+1
Le query non vanno mai fatte dalla View ma esclusivamente nel model. Quest'ultimo poi notifica tramite pattern observer le modifiche allo strato di View.

Per le Activity usate nel modo tradizionale c'e' veramente poco da dire: sotto il punto di vista del framework android si occupano della visualizzazione e della composizione della UI e hanno al suo interno tutti i listener decidendo cosa far vedere e quando farlo vedere. Quindi sono sia View che Controller. E non appena ci metti dentro un paio di variabili diventano pure Model!

Il problema e' che l'MVC, a differenza di quello che si crede, NON e' un pattern ma un insieme di Pattern. In particolare l'MVC e' composto dal pattern Observer (che decide l'interazione tra Model e View), dal pattern Strategy (che decide l'interazione tra View e Controller) ed dal pattern Composite (che decide la composizione delle View).

Usare l'MVC significa applicare tutti questi pattern con delle interfacce (quindi si capisce bene che NESSUNO alla fine applica un pattern mvc alla lettera ma si avvicina molto a questa filosofia).

Offline lelletta

  • Utente junior
  • **
  • Post: 68
  • Respect: 0
    • Mostra profilo
Re:[Facile] Guida di base ai Fragment
« Risposta #6 il: 09 Novembre 2012, 17:00:17 CET »
0
Grazie per la risposta. Sei stato molto chiaro in merito al pattern MVC. Per l'altra domanda, forse non mi sono spiegato bene. Es. concreto:
Ho una Classe model Utente (qui ho semplicemente dei metodi get e set degli attributi: id, nome ecc...). Poi ho una classe DataHelper che estende SQLiteOpenHelper. Poi ho una classe UtenteAdapter che esegue le classiche operazioni CRUD.
Codice (Java): [Seleziona]
// Adding new utente
        public void addUtente(Utente utente) {

                ContentValues values = new ContentValues();
                values.put(UtenteTable.USERNAME, utente.getUsername()); // User utente
                values.put(UtenteTable.SESSO, utente.getSesso()); // sesso utente
                values.put(UtenteTable.EMAIL, utente.getEmail()); // email utente
                values.put(UtenteTable.AVATAR, utente.getIdAvatar()); // avatar utente

                // inserimento della riga
                database.insert(UtenteTable.TABLE_NAME, null, values);
        }

Quindi come vedi qui richiamo qui uso i metodi della classe Utente model.
Ora nell'activity solitamente faccio:
Codice (Java): [Seleziona]
UtenteAdapter datasource;
datasource = new UtenteAdapter(context);
datasource.open();
datasource.addUtente(utente);
datasource.close();

Le domande per chiarire il tutto sono:
è sbagliato? Dove dovrei introdurre il pattern observer ?(link con un esempio)
Nel contesto del tuo tutorial se io dovessi recuperare dei dati da che classe dovrei fare le richieste Fragment o FragmentActivity?

Grazie per la disponibilità. :-)

Offline MarcoDuff

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1073
  • Respect: +202
    • Google+
    • marcoduff
    • Mostra profilo
    • MarcoDuff's Blog
  • Dispositivo Android:
    Samsung Galaxy Nexus
  • Play Store ID:
    MarcoDuff
  • Sistema operativo:
    Windows 7
Re:[Facile] Guida di base ai Fragment
« Risposta #7 il: 11 Novembre 2012, 14:30:46 CET »
+1
Se la tua classe Utente ha soltanto dei metodi che effettuano get e set piu' che chiamarlo "model" chiamarei quella classe Bean (seguendo la filosofia J2EE).

Nel tuo caso sia la classe Utente che la classe DataHelper che la UtenteAdapter fanno parte della parte model del tuo progetto (hanno tutte a che fare con il modello!).

Se la tua view visualizza il Bean Utente, allora il pattern observer va implementato proprio nella classe Utente (ovvero ogni volta che viene richiamato un metodo set questo effettua un notifyObserver, mentre le view si registrano come listener alla classe Utente).

Nel momento che devi aggiungere un nuovo utente quello che accade, teoricamente, e' questo:
Nella view (Fragment) viene gestita l'azione di aggiungi utente (viene premuto un pulsante, un menu, ecc...)
La view richiama il controller (activity) che o visualizza una nuova view se hai bisogno di dettagli (nome, cognome, ecc...) oppure, se tutte le azioni sono state compiute richiama l'azione addUtente sul model con il tuo bean Utente gia' riempito.
Il model, non appena avra' finito, notifichera' la modifica a tutte le view connesse.

Su android, per l'implementazione del pattern observer, puoi con molta semplicita' utilizzare i broadcast intent (anzi devo dire che e' la migliore scelta possibile!).
Il model definisce un intent, ad esempio new Intent("com.marcoduff.utente.ACTION_UTENTE_AGGIORNATO")
ogni volta che un utente viene aggiornato nel modello viene inviato come broadcast quell'intent (e magari in un extra il bean appena aggiornato).
La view, che si registra nella ricezione di quell'intent, non appena lo riceve si occupa dell'aggiornamento della vista.
Questa, secondo il mio parere, e' il miglior modo di implementare il pattern observer nel framework android.

Offline lelletta

  • Utente junior
  • **
  • Post: 68
  • Respect: 0
    • Mostra profilo
Re:[Facile] Guida di base ai Fragment
« Risposta #8 il: 11 Novembre 2012, 18:16:22 CET »
0
GraziE||| :-P

Offline lelletta

  • Utente junior
  • **
  • Post: 68
  • Respect: 0
    • Mostra profilo
Re:[Facile] Guida di base ai Fragment
« Risposta #9 il: 14 Gennaio 2013, 18:24:46 CET »
0
Scusate ma è sbagliato cumunicare tra due fragment ( cioè fare getFragmentManager() ) senza passare per l'actvity?


Offline Fenicexx

  • Nuovo arrivato
  • *
  • Post: 23
  • Respect: 0
    • Mostra profilo
Re:[Facile] Guida di base ai Fragment
« Risposta #10 il: 09 Marzo 2014, 09:40:34 CET »
0
Ciao,
grazie per la guida. L'ho seguita per un mio progetto, ma quando provo a fare un test l'app va in crash, questo è il logcat:
Codice: [Seleziona]
03-06 15:24:53.788: E/AndroidRuntime(1682): FATAL EXCEPTION: main
03-06 15:24:53.788: E/AndroidRuntime(1682): java.lang.RuntimeException: Unable to start activity ComponentInfo{it.wonder_italia.iwonder/it.wonder_italia.iwonder.CatalogActivity}: android.view.InflateException: Binary XML file line #7: Error inflating class fragment
03-06 15:24:53.788: E/AndroidRuntime(1682):         at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2110)
03-06 15:24:53.788: E/AndroidRuntime(1682):         at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2135)
03-06 15:24:53.788: E/AndroidRuntime(1682):         at android.app.ActivityThread.access$700(ActivityThread.java:140)
03-06 15:24:53.788: E/AndroidRuntime(1682):         at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1237)
03-06 15:24:53.788: E/AndroidRuntime(1682):         at android.os.Handler.dispatchMessage(Handler.java:99)
03-06 15:24:53.788: E/AndroidRuntime(1682):         at android.os.Looper.loop(Looper.java:137)
03-06 15:24:53.788: E/AndroidRuntime(1682):         at android.app.ActivityThread.main(ActivityThread.java:4921)
03-06 15:24:53.788: E/AndroidRuntime(1682):         at java.lang.reflect.Method.invokeNative(Native Method)
03-06 15:24:53.788: E/AndroidRuntime(1682):         at java.lang.reflect.Method.invoke(Method.java:511)
03-06 15:24:53.788: E/AndroidRuntime(1682):         at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1027)
03-06 15:24:53.788: E/AndroidRuntime(1682):         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794)
03-06 15:24:53.788: E/AndroidRuntime(1682):         at dalvik.system.NativeStart.main(Native Method)
03-06 15:24:53.788: E/AndroidRuntime(1682): Caused by: android.view.InflateException: Binary XML file line #7: Error inflating class fragment
03-06 15:24:53.788: E/AndroidRuntime(1682):         at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:704)
03-06 15:24:53.788: E/AndroidRuntime(1682):         at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
03-06 15:24:53.788: E/AndroidRuntime(1682):         at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
03-06 15:24:53.788: E/AndroidRuntime(1682):         at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
03-06 15:24:53.788: E/AndroidRuntime(1682):         at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
03-06 15:24:53.788: E/AndroidRuntime(1682):         at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:313)
03-06 15:24:53.788: E/AndroidRuntime(1682):         at android.app.Activity.setContentView(Activity.java:1924)
03-06 15:24:53.788: E/AndroidRuntime(1682):         at it.wonder_italia.iwonder.CatalogActivity.onCreate(CatalogActivity.java:25)
03-06 15:24:53.788: E/AndroidRuntime(1682):         at android.app.Activity.performCreate(Activity.java:5206)
03-06 15:24:53.788: E/AndroidRuntime(1682):         at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1094)
03-06 15:24:53.788: E/AndroidRuntime(1682):         at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2074)
03-06 15:24:53.788: E/AndroidRuntime(1682):         ... 11 more
03-06 15:24:53.788: E/AndroidRuntime(1682): Caused by: java.lang.IllegalArgumentException: Binary XML file line #7: Must specify unique android:id, android:tag, or have a parent with an id for it.wonder_italia.MyListFragment
03-06 15:24:53.788: E/AndroidRuntime(1682):         at android.app.Activity.onCreateView(Activity.java:4830)
03-06 15:24:53.788: E/AndroidRuntime(1682):         at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:680)
03-06 15:24:53.788: E/AndroidRuntime(1682):         ... 21 more

Ho provato a capire cosa potesse causare quei due errori:
Codice: [Seleziona]
03-06 15:24:53.788: E/AndroidRuntime(1682): Caused by: android.view.InflateException: Binary XML file line #7: Error inflating class fragmente
Codice: [Seleziona]
03-06 15:24:53.788: E/AndroidRuntime(1682): Caused by: java.lang.IllegalArgumentException: Binary XML file line #7: Must specify unique android:id, android:tag, or have a parent with an id for it.wonder_italia.MyListFragment
anche cercando un po' sul web, ma sono bloccato da 3 giorni e non riesco a risolvere.

Qualche idea???

Grazie

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:[Facile] Guida di base ai Fragment
« Risposta #11 il: 09 Marzo 2014, 09:58:17 CET »
+1
Un aiuto può venirti da questa riga di LogCat, che ti indica la riga 25 di un tuo file java:

Codice: [Seleziona]
at it.wonder_italia.iwonder.CatalogActivity.onCreate(CatalogActivity.java:25)
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline Fenicexx

  • Nuovo arrivato
  • *
  • Post: 23
  • Respect: 0
    • Mostra profilo
Re:[Facile] Guida di base ai Fragment
« Risposta #12 il: 09 Marzo 2014, 10:19:48 CET »
0
Era riferito alla riga
Codice: [Seleziona]
setContentView(R.layout.activity_catalog);
e in effetti ricontrollando l'xml avevo fatto un errore nel percorso android:name="../../"


Grazie infinite!!

Offline Fenicexx

  • Nuovo arrivato
  • *
  • Post: 23
  • Respect: 0
    • Mostra profilo
Re:[Facile] Guida di base ai Fragment
« Risposta #13 il: 02 Aprile 2014, 09:02:29 CEST »
0
Eccomi con un'altra richiesta.

Sto cercando di implementare il tutto usando BaseAdapter perchè le mie righe sono formate da immagine+testo.

Il problema nasce quando devo passare il mio "mObjectArray" in onClick() che non sarà più un array di tipo String, ma nel mio caso di tipo Menu. Come gestirlo in particolare in onListItemClick()?

Spero possiate aiutarmi.


Grazie

Offline Saltasco

  • Nuovo arrivato
  • *
  • Post: 1
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Samsung S6 edge +
  • Sistema operativo:
    Windows 10
Re:[Facile] Guida di base ai Fragment
« Risposta #14 il: 23 Dicembre 2015, 15:57:49 CET »
0
Ho lo stesso problema di Fenixx a cui chiedo di specificare cosa hai corretto nel percorso del nome android.
Di seguito il LogCat:
12-23 14:54:51.111 17213-17213/com.example.ns295823.firstsalva E/AndroidRuntime: FATAL EXCEPTION: main
                                                                                 Process: com.example.ns295823.firstsalva, PID: 17213
                                                                                 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.ns295823.firstsalva/com.example.ns295823.firstsalva.HomeActivity}: android.view.InflateException: Binary XML file line #7: Error inflating class fragment
                                                                                     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3155)
                                                                                     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3263)
                                                                                     at android.app.ActivityThread.access$1000(ActivityThread.java:197)
                                                                                     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1687)
                                                                                     at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                                     at android.os.Looper.loop(Looper.java:145)
                                                                                     at android.app.ActivityThread.main(ActivityThread.java:6897)
                                                                                     at java.lang.reflect.Method.invoke(Native Method)
                                                                                     at java.lang.reflect.Method.invoke(Method.java:372)
                                                                                     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404)
                                                                                     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)
                                                                                  Caused by: android.view.InflateException: Binary XML file line #7: Error inflating class fragment
                                                                                     at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:770)
                                                                                     at android.view.LayoutInflater.rInflate(LayoutInflater.java:813)
                                                                                     at android.view.LayoutInflater.inflate(LayoutInflater.java:511)
                                                                                     at android.view.LayoutInflater.inflate(LayoutInflater.java:415)
                                                                                     at android.view.LayoutInflater.inflate(LayoutInflater.java:366)
                                                                                     at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:458)
                                                                                     at android.app.Activity.setContentView(Activity.java:2358)
                                                                                     at com.example.ns295823.firstsalva.HomeActivity.onCreate(HomeActivity.java:24)
                                                                                     at android.app.Activity.performCreate(Activity.java:6550)
                                                                                     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1120)
                                                                                     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3108)
                                                                                     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3263) 
                                                                                     at android.app.ActivityThread.access$1000(ActivityThread.java:197) 
                                                                                     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1687) 
                                                                                     at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                                                     at android.os.Looper.loop(Looper.java:145) 
                                                                                     at android.app.ActivityThread.main(ActivityThread.java:6897) 
                                                                                     at java.lang.reflect.Method.invoke(Native Method) 
                                                                                     at java.lang.reflect.Method.invoke(Method.java:372) 
                                                                                     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404) 
                                                                                     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199) 
                                                                                  Caused by: java.lang.IllegalArgumentException: Binary XML file line #7: Must specify unique android:id, android:tag, or have a parent with an id for com.example.ns295823.firstsalva.MyListFragment
                                                                                     at android.support.v4.app.FragmentManagerImpl.onCreateView(FragmentManager.java:2256)
                                                                                     at android.support.v4.app.FragmentController.onCreateView(FragmentController.java:111)
                                                                                     at android.support.v4.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:314)
                                                                                     at android.support.v4.app.BaseFragmentActivityHoneycomb.onCreateView(BaseFragmentActivityHoneycomb.java:31)
                                                                                     at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:79)
                                                                                     at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:740)
                                                                                     at android.view.LayoutInflater.rInflate(LayoutInflater.java:813) 
                                                                                     at android.view.LayoutInflater.inflate(LayoutInflater.java:511) 
                                                                                     at android.view.LayoutInflater.inflate(LayoutInflater.java:415) 
                                                                                     at android.view.LayoutInflater.inflate(LayoutInflater.java:366) 
                                                                                     at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:458) 
                                                                                     at android.app.Activity.setContentView(Activity.java:2358) 
                                                                                     at com.example.ns295823.firstsalva.HomeActivity.onCreate(HomeActivity.java:24) 
                                                                                     at android.app.Activity.performCreate(Activity.java:6550) 
                                                                                     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1120) 
                                                                                     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3108) 
                                                                                     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3263) 
                                                                                     at android.app.ActivityThread.access$1000(ActivityThread.java:197) 
                                                                                     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1687) 
                                                                                     at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                                                     at android.os.Looper.loop(Looper.java:145) 
                                                                                     at android.app.ActivityThread.main(ActivityThread.java:6897) 
                                                                                     at java.lang.reflect.Method.invoke(Native Method) 
                                                                                     at java.lang.reflect.Method.invoke(Method.java:372)
                                   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404) 
                                                                                     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)