segunda-feira, 28 de novembro de 2011

Lendo RSS no Android

Olá povo,

A tecnologia RSS tornou-se uma forma padrão que os sites encontraram para compartilhar suas informações. Com ele, os usuários podem visualizar seu conteúdo de forma padronizada, uma vez que utiliza o formato XML. Sendo assim, vou mostrar nesse post como ler um RSS com Android. Mas o código utilizado aqui pode ser utilizado para qualquer XML.

Vou começar criando a classe que vai representar uma notícia do RSS. Ela tem basicamente um título, um resumo da notícia e um link para notícia completa.

class Noticia {
  String titulo;
  String descricao;
  String link;
 
  public Noticia(String t, String d, String l) {
    titulo = t;
    descricao = d;
    link = l;
  }
 
  @Override
  public String toString() {
    return titulo;
  }
}

Simplifiquei ao máximo a classe aqui, não coloquei nem os GETs nem os SETs. Implementei apenas o método toString() pois o mesmo é utilizado pelo Adapter (que veremos em seguida) para exibir a notícia.

Agora vamos ver o código da Activity.
public class LeitorRSSActivity extends ListActivity {

  List<Noticia> news;
  ArrayAdapter<Noticia> adapter;
 
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    news = new ArrayList<Noticia>();
    adapter = new ArrayAdapter<Noticia>(
    this, android.R.layout.simple_list_item_1, news);
    setListAdapter(adapter);

    // Criando AsyncTask que buscará o RSS da globo
    new RssAsyncTask().execute(
      "http://g1.globo.com/dynamo/rss2.xml");
  }

  // Método que lê o XML do RSS
  private List<Noticia> readXML(InputStream is){
    List<Noticia> noticias =
      new ArrayList<Noticia>();

    try {
      // Criando os objetos que representam o XML
      DocumentBuilderFactory factory =
        DocumentBuilderFactory.newInstance();

      DocumentBuilder builder = 
        factory.newDocumentBuilder();
      Document xmlDocument = builder.parse(is);
   
      // Cada notícia é representada pela tag <item>
      // Aqui obtemos a lista de nós com essa tag
      NodeList posts = 
        xmlDocument.getElementsByTagName("item");

      // Vamos iterar sobre a lista de itens
      String titulo = null, descricao = null, 
        link = null;

      for (int i = 0; i < posts.getLength(); i++) {
        Node post = posts.item(i);

        // Cada nó ITEM tem os filhos:
        // TITLE, DESCRIPTION e LINK
        NodeList postInfo = post.getChildNodes();
        for (int j = 0; j < postInfo.getLength(); j++){
          Node info = postInfo.item(j);

          if ("title".equals(info.getNodeName())){
            titulo = info.getTextContent();

          } else if ("link".equals(
            info.getNodeName())){
            link = info.getTextContent();
      
          } else if ("description".equals(
            info.getNodeName())){
            descricao = info.getTextContent();
          }
        }
        // Com as informações das tags, criamos o
        // objeto notícia e adicionamos na lista
        noticias.add(
          new Noticia(titulo, descricao, link));
      }
    } catch (Throwable e) {
      e.printStackTrace();
    }
    return noticias;
  }

  // A AsyncTask realiza a comunicação em background
  class RssAsyncTask extends
    AsyncTask<String, Void, List<Noticia>>{

    ProgressDialog dialog;
 
    @Override
    protected void onPreExecute() {
      super.onPreExecute();
      // Antes de baixaro XML, mostra o dialog
      dialog = ProgressDialog.show(
        LeitorRSSActivity.this, 
        "Aguarde", "Baixando RSS");
    }
 
    @Override
    protected List<Noticia> doInBackground(
      String... params) {

      List<Noticia> lista = null;
      HttpURLConnection conexao = null;
      InputStream is = null;
   
      try {
        URL url = new URL(params[0]);
        conexao = (HttpURLConnection)
          url.openConnection();
        conexao.connect();
    
        is = conexao.getInputStream();
        lista = readXML(is);

      } catch (Throwable t){
        t.printStackTrace();
      } finally {
        try {
          if (is != null) is.close();
          if (conexao != null) conexao.disconnect();
        } catch (Throwable t){
        }
      }
      return lista;
    }
  
    @Override
    protected void onPostExecute(List<Noticia> result){
      super.onPostExecute(result);
      dialog.dismiss();
      news.addAll(result);
      adapter.notifyDataSetChanged();
    }
  }
}


Quem tiver dúvida sobre AsyncTask, dá uma olhada aqui, ou deixem seus comentários.

4br4ç05,
nglauber

10 comentários:

thiago silva disse...

Muito bom este tutorial glauber. parabéns!

Nelson Glauber disse...

Olá povo,

O método getTextContent() usado nas linhas 53, 57 e 61 não está disponível na versão 2.1 do Android, e pode ser substituído por getFirstChild().getNodeValue().

4br4ç05,
nglauber

Eduardo disse...

Olá Nelson, Boa Tarde, muito obrigado pela matéria, gostaria de saber como seriam feitos os views para exibir na tela do Android a lista de RSS...

[]s,

Nelson Glauber disse...

Oi Eduardo,

O código acima já lista o RSS na tela...

4br4ç05,
nglauber

Anônimo disse...

muito bom, funcionou direitinho.

agora como eu faço para ele pegar uma imagem também do link? e mostrar? tenho q usar adapter? ou tem como ele mostrar sem adapter?
vlw, abraços

Nelson Glauber disse...

Oi Anônimo,

Você terá que alterar o parser para extrair essa informação. Daí alterar o adapter para que essa imagem apareça na lista. Aconselho usar esse componente:
https://github.com/leocadiotine/WebCachedImageView

4br4ç05,
nglauber

Mxcz Piscioneri disse...

Olá.
Muito bom esse post, com ele consigo mostrar 1 item do XML (pelo toString) e jogando no layout (android.R.layout.simple_list_item_1).
Minha dúvida é como mostrar todos os dados dispostos em um layout que eu irei criar.
Pode me ajudar?

Nelson Glauber disse...

Oi Matheus,

É só substituir o ArrayAdapter por um adapter customizado:
http://nglauber.blogspot.com.br/2011/03/adapter-eficiente-no-android.html

4br4ç05,
nglauber

Darkschneider disse...

Excelente post. Blog nota 10.

Como faço para abrir essas notícias em uma WebView?

Nelson Glauber disse...

Oi Darkshneider,

Basicamente você teria que implementar o método onListItemClick e obter o objeto Noticia.
Noticia noticia = (Noticia)getListAdapter().getItem(position);

Depois é só carregar a Url na WebView.
webView.loadUrl(noticia.link);

Dá uma olhada aqui:
http://developer.android.com/reference/android/webkit/WebView.html

4br4ç05,
nglauber