DevCorner: ArrayList di articoli e ListView [FeedReader]

DevCorner: ArrayList di articoli e ListView [FeedReader]
Giuseppe Tripodi
Giuseppe Tripodi

L'estate sta finendo, ma il caldo e le vacanze non ci hanno (ancora!) impedito di portare avanti il nostro lavoro certosino e di guidarvi nella creazione di un'applicazione complessa per la lettura dei feed. Dopo aver visto due settimane fa come effettuare una chiamata asincrona e parsare l'XML, alla fine di questo episodio ci ritroveremo con un ArrayList di oggetti di tipo Articolo e un abbozzo di ListView con titoli e autori. Pronti ad iniziare?

La prima cosa che andiamo a fare è preparare l'interfaccia per i nostri task: aggiungiamo una listView all'XML dell'Activity principale e definiamo un'interfaccia chiamata Row.xml che rappresenta la singola riga della nostra lista: al suo interno piazziamo un'immagine (che per il momento non verrà gestita e al suo interno troveremo solo un placeholder) e due TextView, per contenere rispettivamente Titolo e Autore dell'articolo.





    

    

    


A questo punto creiamo una nuova classe, che funga da Adapter per la nostra ListView: non brillando per fantasia l'abbiamo chiamata ArticoloAdapter e, per il momento, l'unica cosa che fa è estrapolare le stringhe titolo e autore da un ArrayList di oggetti di tipo Articolo per piazzarli all'interno della lista.
Il codice e la spiegazione di questo passaggio sono molto simili a quanto illustrato in questo precedente tutorial: Creiamo una listView con layout custom.

Fatto ciò non ci rimane che rendere effettivamente disponibile questo ArrayList e, per farlo, riapriamo il nostro XMLParser e creiamo un oggetto di tipo Articolo per ogni item parsato dall'XML, poi aggiungiamolo al nostro ArrayList.
Per fare in modo di aggiornare la listView solo quando il download e il parsing degli elementi è concluso, abbiamo implementato il pattern Observer, come spiegato in questo precedente episodio del DevCorner.
La nostra classe, quindi, ha ottenuto più o meno questo aspetto:

public class XMLParser extends Observable {

    private static XMLParser xmlParser = null;
    private ArrayList listaArticoli;
    Articolo articoloCorrente;
    public static XMLParser getInstance(){
        if(xmlParser == null)
        {
            xmlParser = new XMLParser();
        }
        return xmlParser;
    }

    public XMLParser()
    {
        listaArticoli = new ArrayList();
        articoloCorrente = new Articolo();

    }

    public void parseXML (String xml)
            throws XmlPullParserException, IOException
    {

        XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
        factory.setNamespaceAware(false);
        XmlPullParser xpp = factory.newPullParser();

        xpp.setInput(new StringReader(xml));

        boolean insideItem = false;

        int eventType = xpp.getEventType();

        while (eventType != XmlPullParser.END_DOCUMENT) {
            if (eventType == XmlPullParser.START_TAG) {
                if (xpp.getName().equalsIgnoreCase("item")) {
                    insideItem = true;
                } else if (xpp.getName().equalsIgnoreCase("title")) {
                    if (insideItem)
                    {
                        String titolo= new String(xpp.nextText());
                        articoloCorrente.setTitolo(titolo);
                    }
                    }
                else if (xpp.getName().equalsIgnoreCase("link")) {
                    if (insideItem)
                    {
                        String link= new String(xpp.nextText());
                        articoloCorrente.setLink(link);
                    }
                }else if (xpp.getName().equalsIgnoreCase("dc:creator")) {
                    if (insideItem)
                        {
                            String autore= new String(xpp.nextText());
                            articoloCorrente.setAutore(autore);
                        }
                }else if (xpp.getName().equalsIgnoreCase("description")) {
                    if (insideItem) {
                        String intro= new String(xpp.nextText());
                        articoloCorrente.setIntro(intro);
                    }
                }
            } else if (eventType == XmlPullParser.END_TAG && xpp.getName().equalsIgnoreCase("item")) {
                insideItem = false;
                listaArticoli.add(articoloCorrente);
                articoloCorrente = new Articolo();
            }
            eventType = xpp.next();
        }
        triggerObserver();

    }

    private void triggerObserver() {
        setChanged();
        notifyObservers(listaArticoli);
    }

}

E, ovviamente, nell'Activity principale abbiamo introdotto il metodo update, che si occupa di aggiornare la ListView, e aggiunto l'observer:



public class MyActivity extends ActionBarActivity implements Observer
{

    ConnectionHelper cHelper = null;
    XMLParser xmlParser = null;
    ArrayList listaArticoli = null;
    ListView listViewArticoli;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        listViewArticoli = (ListView) findViewById(R.id.listViewArticoli);
        cHelper = ConnectionHelper.getInstance();
        loadFeed();
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.    
                                                                                                                        
getMenuInflater().inflate(R.menu.my, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } public void addArticolo(Articolo articolo){ listaArticoli.add(articolo); } public void loadFeed() { xmlParser = XMLParser.getInstance(); xmlParser.addObserver(this); cHelper.get("feed",null,new AsyncHttpResponseHandler(){ @Override public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { Log.i("statusCode", statusCode+""); String xml = new String(responseBody); try { xmlParser.parseXML(xml); } catch (XmlPullParserException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } @Override public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { Log.e("error",statusCode+""); } }); } @Override public void update(Observable observable, Object data) { listaArticoli = (ArrayList) data; ArticoloAdapter mArticoloAdapter = new ArticoloAdapter(this,listaArticoli); listViewArticoli.setAdapter(mArticoloAdapter); } }

Il risultato finale, che potete scaricare sempre dall'apposita repository su GitHub, è ancora molto scarno ma, come potete vedere da voi, inizia a funzionare.

Per continuare a sviluppare il vostro personalissimo Feed Reader non vi rimane che continuare a seguire gli appuntamenti con il DevCorner!

Commenta