11.15: Un “blog” personale per Android sfruttando Firebase: PostListActivity (la libreria Picasso)

Condividi su:

La nostra app adesso permette di aggiungere post all’interno del blog, salvando tutto il necessario nel cloud grazie a Firebase. Il passaggio da fare adesso è quello di mostrare i post salvati all’utente.




Il setup della RecyclerView

Abbiamo già l’activity adatta allo scopo: PostListActivity. Il layout di questa contiene una RecyclerView, ma non l’abbiamo ancora sfruttata, poiché finora ci mancava il dataset, che invece adesso abbiamo, quindi possiamo procedere:

public class PostListActivity extends AppCompatActivity {
    private FirebaseDatabase mDB;
    private DatabaseReference mDBRef;
    private FirebaseUser mUser;
    private FirebaseAuth mAuth;
    private RecyclerView recyclerView;
    private BlogRecyclerAdapter blogRecyclerAdapter;
    private List<Blog> blogList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_post_list);

        //Recuperiamo l'istanza di autenticazione e l'utente coorente
        mAuth = FirebaseAuth.getInstance();
        mUser = mAuth.getCurrentUser();

        /*
         * Recuperiamo l'istanza del database,
         * il riferimento alla posizione figlia in cui vogliamo memorizzare dati e
         * manteniamo il database sincronizzato tra dispositivo e cloud
         */
        mDB = FirebaseDatabase.getInstance();
        mDBRef = mDB.getReference().child("Blog");
        mDBRef.keepSynced(true);

        //Istanziamo la lista di post
        blogList = new ArrayList<>();

        //Istanziamo ed effettuiamo il setup della RecyclerView
        recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
        recyclerView.setHasFixedSize(true);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        //Creiamo il menù effettuando l'inflate del layout apposito
        getMenuInflater().inflate(R.menu.main_menu, menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        //Gestiamo la selezione degli item del menù
        switch (item.getItemId()){
            case R.id.action_add:
                /*
                 * Quando l'utente sceglie l'item per aggiungere un nuovo post
                 * lo direzioniamo verso l'activity appropriata
                 */
                if (mUser != null && mAuth != null){
                    startActivity(new Intent(PostListActivity.this, AddPostActivity.class ));
                    finish();
                }
                break;
            case R.id.action_signout:
                /*
                 * Quando l'utente sceglie l'item per effettuare il logout
                 * eseguiamo l'operazione e ritorniamo all'activity di login e registrazione
                 */
                if (mAuth != null){
                    mAuth.signOut();
                    startActivity(new Intent(PostListActivity.this, MainActivity.class ));
                    finish();
                }
                break;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onStart() {
        super.onStart();
        //Aggiungiamo un listener che monitori l'aggiunta di nuovi nodi figli nella posizione referenziata
        mDBRef.addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String s) {
                /*
                 * Questo metodo viene invocato quando vengono aggiunti nuovi nodi figli.
                 */

                //Preleviamo il post dal database
                Blog post = dataSnapshot.getValue(Blog.class);
                //Aggiungiamo il post alla lista
                blogList.add(post);
                //Invertiamo l'ordine la lista per visualizzare i nuovi post per primi
                Collections.reverse(blogList);
                //Istanziamo l'adapter
                blogRecyclerAdapter = new BlogRecyclerAdapter(PostListActivity.this, blogList);
                //Settiamo l'adapter sulla RecyclerView
                recyclerView.setAdapter(blogRecyclerAdapter);
                //Notifichiamo all'adapter che il dataset è cambiato
                blogRecyclerAdapter.notifyDataSetChanged();

            }

            @Override
            public void onChildChanged(DataSnapshot dataSnapshot, String s) {
                /*
                 * Questo metodo viene invocato quando vengono modificati dati sul nodo figlio.
                 */
            }

            @Override
            public void onChildRemoved(DataSnapshot dataSnapshot) {
                /*
                 * Questo metodo viene invocato quando viene rimosso un nodo figlio.
                 */
            }

            @Override
            public void onChildMoved(DataSnapshot dataSnapshot, String s) {
                /*
                 * Questo metodo viene invocato quando cambia la priorità della posizione dei nodi figli.
                 */
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                /*
                 * Questo metodo viene invocato quando non è stato possibile reperire il dato.
                 */
            }
        });
    }
}

Tra i field sono stati aggiunti quelli necessari agli oggetti della RecyclerView, del suo adapter e della lista di post. All’interno dell'”onCreate()” abbiamo aggiunto il codice per istanziare la lista e la RecyclerView, nulla di nuovo, ma non settiamo ancora il suo adapter.

Sappiamo che per recuperare dati all’interno del database real-time di Firebase abbiamo bisogno di un listener, poiché è l’oggetto più adatto, essendo quello che rimane in ascolto di eventuali cambiamenti. Noi abbiamo il riferimento al nodo figlio “Blog”, ma all’interno di questo abbiamo abbiamo tanti altri nodi quanti sono i post salvati, quindi non possiamo sfruttare il listener “ValueEventListener”. Ovviamente Firebase offre anche un listener che monitora gli eventi sui nodi figli: “ChildEventListener“. Questo funziona allo stesso modo dell’altro, con l’unica differenza che offre qualche metodo in override in più, che vanno implementati anche se non utilizzati, poiché sono tutti astratti, trattandosi di un’interfaccia.

Al momento ci interessa solo “onChildAdded()”, che viene invocato ogni qualvolta viene aggiunto un nuovo nodo figlio all’interno del database. Sarà qui che preleveremo l’oggetto blog dal database, lo aggiungeremo alla lista e istanzieremo l’adapter fornendogli questa lista. Aggiungiamo le istruzioni necessarie ad effettuare queste operazioni, settiamo l’adapter sulla RecyclerView e gli notifichiamo cambiamenti sul dataset, forzandolo ad aggiornare le view.
Una particolarità è quella di aver utilizzato il metodo “reverse()” della classe “Collections” per poter invertire l’ordine della lista, in modo da avere prima il post più recente e per ultimo quello più datato.

Come potete notare il listener è stato aggiunto all’oggetto che contiene il riferimento a “Blog” all’interno del metodo “onStart()”, questo ci assicura che tali operazioni vengano effettuate solo con app non in backgroud.

Se provate l’app, dovrebbe funzionare tutto, tranne per un dettaglio, non viene visualizzata l’immagine del post. Tutto nella norma, poiché se ricordate non abbiamo completato l’adapter e abbiamo infatti anche dei riferimenti //ToDo.

La visualizzazione di immagini online tramite la libreria Picasso

Rechiamoci quindi all’interno della classe “BlogRecyclerAdapter” e nello specifico all’interno del metodo “onBindViewHolder()”, che è quello che viene invocato quando bisogna settare i dati sulle view.

Per poter visualizzare l’immagine, che si trova all’interno di una risorsa remota e non nel dispositivo, ne tantomeno tra le risorse interne all’app, ci avvarremo della libreria open-source Picasso.

Per aggiungerla al nostro progetto facciamo le stesse operazioni fatte con Volley. Ci rechiamo all’interno del menù “File”->”Project Structure…”. Nella schermata che si apre ci spostiamo nella sezione “Modules”->”app” e qui nel tab “Dependencies”. Cliccando su “+” e poi “Library dependency” possiamo ricercarla all’interno dei repository. Sfrutteremo quella fornita da SquareUp (com.squareup.picasso:picasso:2.5.2), che è il manutentore principale della libreria.La procedura aggiungerà la libreria tra le dipendenze dello script di Gradle e dopo alcuni secondi terminerà anche la sincronizzazione.

L’utilizzo della libreria si riduce ad una singola istruzione:

Picasso.with(context).load(imageURL).into(holder.image);

Il metodo “with()” necessita del context come parametro; mentre “load()” vuole l’url dell’immagine, che noi abbiamo già prelevato dall’oggetto Blog; infine col metodo “into()” specifichiamo la view dove andrà settata l’immagine.

Dopo questa piccola modifica all’adapter, eseguendo l’app, noterete che dopo qualche istante, necessario per il download delle immagini, la lista verrà popolata anche delle immagini dei post.



Anche con questo articolo possiamo fermarci qui, ci mancano ancora cose da implementare, come la possibilità di registrare nuovi utenti, che vedremo nel prossimo post.

Condividi su:

label, , , ,

About the author