Autore Topic: Problema con Listener e Fragments  (Letto 504 volte)

Offline nicopasso

  • Nuovo arrivato
  • *
  • Post: 32
  • Respect: +1
    • Mostra profilo
  • Dispositivo Android:
    Google Nexus 5
  • Sistema operativo:
    Windows 7, Mac OS X 10.5
Problema con Listener e Fragments
« il: 21 Gennaio 2014, 20:40:13 CET »
0
Buongiorno a tutti,
mi trovo di fronte ad un problema abbastanza snervante.
Vi spiego innanzitutto come è strutturata l'app e poi passo ad elencare il codice che mi crea problemi.

L'app è strutturata, come schermata iniziale, con un'activity che contiene un Fragment e questo fragment ha al suo interno un ViewPager. Il ViewPager ha poi 2 Fragment che, banalmente, sono due ListView.

E fin qui tutto ok.
Ora tramite una classe "singleton" recupero un JSON con Volley e una volta che il JSON è stato scaricato correttamente devo notificare l'avvenuto download e passare un ArrayList<E> al Fragment principale e ai 2 fragment del ViewPager.
Per fare ciò ho usato il Listener pattern, creando così una interfaccia pubblica che la Activity principale deve implementare per ottenere i nuovi dati.
Ho pensato di usare questa struttura in modo tale da effettuare il download una volta sola e propagare l'informazione dove serve.

Quando passo i dati al Fragment principale non ho problemi. Ho creato un metodo pubblico nel Fragment che chiamo all'interno della Callback nell'Activity.
Il guaio sorge quando faccio la stessa cosa con i due ListFragment. Chiamo il metodo pubblico, passo i dati e all'interno dei ListFragment aggiorno l'adapter con notifySetDataChange(). Qui però compare una NullPointerException in quanto l'adapter non viene minimamente riconosciuto come inizializzato nel ListFragment.

Passiamo al codice.
SINGLETON:
Codice (Java): [Seleziona]
   //Quando finisco di caricare i dati
    mCallback.onLoaded(fullArray);

    //...
    //...

    //Dichiarazione dell'Interfaccia
    public interface OnArrayLoaded {
        public void onLoaded(ArrayList<E> array);
    }

ACTIVITY:
Codice (Java): [Seleziona]
      @Override
      protected void onCreate(Bundle savedInstanceState) {

        //...

        //Inserisco il Fragment principale
        homeFragment = new HomeFragment();

        android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
        fragmentManager.beginTransaction()
                .replace(R.id.frame_content, homeFragment)
                .commit();

        //...
   } //end onCreate

//Implemento l'interfaccia
    public void onLoaded(ArrayList<E> array) {

        //Passo l'array al fragment HomeFragment che aggiorna una MapView
        if (homeFragment != null) {
            //Uso un metodo pubblico del fragment
            homeFragment.updateMap(array, mContext);
        }
    }

Questa porzione di codice funziona bene. Scaricati i dati, la mappa viene aggiornata correttamente.
Nel metodo onLoaded, ho provato anche a recuperare le istanze dei due ListFragment tramite il metodo getItem(int i) dell'Adapter del ViewPager di HomeFragment.

Codice (Java): [Seleziona]
//Implemento l'interfaccia
    public void onLoaded(ArrayList<E> array) {

        //Passo l'array al fragment HomeFragment che aggiorna una MapView
        if (homeFragment != null) {
            //Uso un metodo pubblico del fragment
            homeFragment.updateMap(array, mContext);
           
            ListFragment1 listFragment1 = (ListFragment1)homeFragment.mAdapter().getItem(0); //ad esempio
           listFragment1.updateListView(array, mContext);
        }
    }

 L'istanza che recupero ha la classe corretta, ma quando entro nel ListFragment per aggiornare i dati in questo modo:

Codice (Java): [Seleziona]
   

//Public method to respond to callback
    public void updateListView(ArrayList<E> newArray, Context context) {
        mOldArray = newArray; //mOldArray è l'array legato all'Adapter della ListView

        //Notifico il cambiamento di dati alla ListView
        mAdapter.notifyDataSetChanged();
    }

...mi torna un NullPointerException su mAdapter.
Vi chiedo: PERCHE'? Non sono riuscito a capirlo.

Ho già provato a fare vari tentativi.
Ho spostato dentro ad updateMap() di HomeFragment la chiamata al metodo pubblico del ListFragment ma nessun risultato.

Ho provato a dichiarare un nuovo adapter all'interno di updateListView(). In questo caso non ho un NullPointerException ma l'adapter non mostra niente di niente.

Sono arrivato al punto di non sapere più che pesci pigliare.
Spero che qualcuno di voi mi possa illuminare con qualche idea geniale  ;-)

iClaude

  • Visitatore
Re:Problema con Listener e Fragments
« Risposta #1 il: 22 Gennaio 2014, 10:46:18 CET »
0
Forse non c'entra nulla, però prova a forzare il caricamento di tutti i Fragment del ViewPager con setOffscreenPageLimit(int limit)

Non vorrei che quando richiami il metodo sui ListFragment questi non siano stati ancora caricati, o già scaricati.

Offline nicopasso

  • Nuovo arrivato
  • *
  • Post: 32
  • Respect: +1
    • Mostra profilo
  • Dispositivo Android:
    Google Nexus 5
  • Sistema operativo:
    Windows 7, Mac OS X 10.5
Re:Problema con Listener e Fragments
« Risposta #2 il: 22 Gennaio 2014, 11:30:36 CET »
0
Forse non c'entra nulla, però prova a forzare il caricamento di tutti i Fragment del ViewPager con setOffscreenPageLimit(int limit)

Non vorrei che quando richiami il metodo sui ListFragment questi non siano stati ancora caricati, o già scaricati.

Purtroppo neanche questo funziona.

Ho risolto però usando il pattern Obersver/Observable che non conoscevo e che è molto molto interessante.
Per chi non lo conoscesse, questo pattern coinvolge due classi: una classe che osserva (l'Observer) e una classe che viene osservata (l'Observable).

La classe che viene osservata deve estendere Observable e richiamare questi due metodi quando si vuole notificare una modifica di qualche variabile (o altro):

Codice (Java): [Seleziona]
setChanged();
notifyObservers();

Inoltre si crea nell'Observable un getter della variabile a cui l'Observer è interessato.

L'Observer invece viene dichiarato con:

Codice (Java): [Seleziona]
implements Observer
e al suo interno è necessario dichiarare che classe osserva
Codice (Java): [Seleziona]
mIstanzaObservable = new ClasseObservable();
mIstanzaObservble.addObserver(this);

e infine dove serve dichiarare un metodo dell'interfaccia Observer che all'interno conterrà il getter della variabile utile all'Observer

Codice (Java): [Seleziona]
@Override
public void update(Observable observable, Object data) {
     mVariabile = mIstanzaObservable.getVariabile();

      //...fare cose con la variabile...
}

Con questo pattern ho risolto il problema. Rimane il fatto che non capisco come mai prima non funzionasse...