Se você quer criar um aplicativo Android que use listas para exibir muitos dados, o Android têm dois componentes para facilitar sua vida, RecyclerView e CardView.
Usando esses componentes, é muito fácil dar ao seu aplicativo uma aparência que esteja em conformidade com as diretrizes mencionadas na especificação do Material Design do Google.
Além disso, também os benefícios da reciclagem de Views para o sistema operacional funcionar com mais eficiência.
Neste artgo, você experimentará o poder do RecyclerView em ação.
Por que você precisa do RecyclerView?
Imagine que você esteja criando um ListView onde os itens personalizados que você deseja mostrar são bastante complicados. Você pode criar um layout para esses itens e usar esse layout dentro do seu Adapter.
Dentro do método getView(), você infla o layout do novo item. Em seguida, você faz referência a todas as Views usando os IDs fornecidos em seu XML para personalizar e adicionar alguma lógica de visualização.
Uma vez terminado, você passa essa View para o ListView para ser desenhado na tela.
A verdade é que ListViews e GridViews fazem apenas metade do trabalho de conseguir uma verdadeira eficiência de memória. Eles reciclam o layout do item, mas não mantêm referências aos filhos do layout, forçando-o a chamar findViewById() para cada filho do layout do item toda vez que você chamar getView().
Todas essas chamadas podem se tornar muito intensivas no processador, especialmente para layouts complicados. Além disso, a situação pode fazer com que sua rolagem do ListView se torne irregular ou não responsiva, pois tenta freneticamente capturar referências às Views necessárias.
Inicialmente, os engenheiros Android do Google forneceram uma solução para esse problema de rolagem suave, por meio do padrão View Holder.
Ao usar esse padrão, você cria uma classe que se torna uma referência na memória para todas as Views necessárias para preencher seu layout. O benefício é você definir as referências uma vez e reutilizá-las, trabalhando efetivamente em torno do resultado de desempenho que vem repetidamente chamando findViewById().
O problema é que é um padrão opcional para um ListView ou GridView. Se você não tem conhecimento desse detalhe, pode se perguntar por que seus preciosos ListViews e GridViews são tão lentos.
RecyclerView e Layouts
A chegada do RecyclerView mudou tudo. Ele ainda usa um Adapter para atuar como uma fonte de dados. No entanto, você precisa criar ViewHolders para manter referências na memória.
Quando você precisa de uma nova View, ela cria um novo objeto ViewHolder para inflar o layout e manter essas referências ou reciclar uma da pilha existente.
Agora você sabe por que é chamado de RecyclerView!
Outra vantagem de usar o RecyclerView é que eles vêm com animações padrão que você não precisa criar do zero, elas simplesmente funcionam.
Graças à exigência de um ViewHolder, o RecyclerView sabe exatamente qual animação aplicar a qual item. O melhor de tudo, apenas faz conforme necessário. Você pode até criar suas próprias animações e aplicá-las conforme necessário.
O último e mais interessante componente de um RecyclerView é o seu LayoutManager. Este objeto posiciona os itens do RecyclerView e informa quando reciclar itens que foram transferidos para fora da tela.
Os gerenciadores de layout vêm em três tipos padrão:
- LinearLayoutManager: Posiciona seus itens para se parecerem com um ListView padrão.
- GridLayoutManager: Posiciona seus itens em um formato de grade semelhante a um GridView.
- StaggeredGridLayoutManager: Posiciona seus itens em um formato de grade escalonado.
Você também pode criar seus próprios LayoutManagers para usar com um RecyclerView se quiser um pouco mais de personalização.
Criando a CardView
Primeiramente, vamos configurar as bibliotecas de compatibilidade dos componentes dentro do arquivo build.gradle.
compile 'com.android.support:cardview-v7:21.0.+' compile 'com.android.support:recyclerview-v7:21.0.+'
Um CardView é um ViewGroup. Como qualquer outro ViewGroup, ele pode ser adicionado à sua Activity ou Fragment usando um arquivo XML de layout.
Para criar um CardView vazio, você teria que adicionar o seguinte código ao XML de layout, conforme mostrado a seguir:
<android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content"> </android.support.v7.widget.CardView>
Como um exemplo mais realista, vamos agora criar um LinearLayout e colocar um CardView dentro dele. O CardView poderia representar, por exemplo, uma pessoa e conter o seguinte:
- um TextView para exibir o nome da pessoa
- um TextView para exibir a idade da pessoa
- um ImageView para exibir a foto da pessoa
É assim que o XML seria:
<?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:padding="16dp" > <android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/cv" > <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/person_photo" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:layout_marginRight="16dp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/person_name" android:layout_toRightOf="@+id/person_photo" android:layout_alignParentTop="true" android:textSize="30sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/person_age" android:layout_toRightOf="@+id/person_photo" android:layout_below="@+id/person_name" /> </RelativeLayout> </android.support.v7.widget.CardView> </LinearLayout>
Criando a RecyclerView
Usar uma instância do RecyclerView é um pouco mais complicado. No entanto, defini-lo em um arquivo XML de layout é bem simples. Você pode defini-lo em um layout da seguinte maneira:
<android.support.v7.widget.RecyclerView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/rv" />
Para recuperar o objeto em sua Activity, use o seguinte:
RecyclerView rv = (RecyclerView)findViewById(R.id.rv);
Se tiver certeza de que o tamanho da RecyclerView não será alterado, você poderá adicionar o seguinte para melhorar o desempenho:
rv.setHasFixedSize(true);
Usando o LayoutManager
Ao contrário de um ListView, um RecyclerView precisa de um LayoutManager para gerenciar o posicionamento de seus itens. Você pode definir seu próprio LayoutManager, estendendo a classe RecyclerView.LayoutManager. No entanto, na maioria dos casos, você poderia simplesmente usar uma das subclasses de LayoutManager predefinidas:
Neste artigo, vou usar um LinearLayoutManager. Esta subclasse do LayoutManager, por padrão, fará com que seu RecyclerView se pareça com um ListView.
LinearLayoutManager llm = new LinearLayoutManager(context); rv.setLayoutManager(llm);
Definindo os dados
Assim como um ListView, um RecyclerView precisa de um Adapter para acessar seus dados. Mas antes de criarmos um Adapter, vamos criar dados com os quais possamos trabalhar.
Crie uma classe simples para representar uma pessoa e, em seguida, escreva um método para inicializar um objeto List<Person>:
class Person { String name; String age; int photoId; Person(String name, String age, int photoId) { this.name = name; this.age = age; this.photoId = photoId; } } private List<Person> persons; private void initializeData(){ persons = new ArrayList<>(); persons.add(new Person("Fillipe Cordeiro", "31 anos", R.drawable.fillipe)); persons.add(new Person("Joao da Silva", "25 anos", R.drawable.joao)); persons.add(new Person("Maria Dolores", "35 anos", R.drawable.maria)); }
Criando um Adapter
Para criar um Adapter que um RecyclerView possa usar, você deve estender o RecyclerView.Adapter.
Esse Adapter segue o padrão ViewHolder, o que significa que você define uma classe personalizada que estende RecyclerView.ViewHolder. Esse padrão minimiza o número de chamadas para o método findViewById.
Nós já definimos o layout XML para um CardView que representa uma pessoa. Vamos reutilizar esse layout agora. Dentro do construtor do nosso ViewHolder personalizado, inicialize as Views que pertencem aos itens do nosso RecyclerView.
public class RVAdapter extends RecyclerView.Adapter<RVAdapter.PersonViewHolder>{ public static class PersonViewHolder extends RecyclerView.ViewHolder { CardView cv; TextView personName; TextView personAge; ImageView personPhoto; PersonViewHolder(View itemView) { super(itemView); cv = (CardView)itemView.findViewById(R.id.cv); personName = (TextView)itemView.findViewById(R.id.person_name); personAge = (TextView)itemView.findViewById(R.id.person_age); personPhoto = (ImageView)itemView.findViewById(R.id.person_photo); } } }
Em seguida, adicione um construtor ao Adapter personalizado para que ele tenha um identificador para os dados que o RecyclerView exibe. Como nossos dados estão na forma de um objeto List, use o seguinte código:
List<Person> persons; RVAdapter(List<Person> persons){ this.persons = persons; }
RecyclerView.Adapter tem três métodos abstratos que devemos substituir. Vamos começar com o método getItemCount. Isso deve retornar o número de itens presente nos dados. Como nossos dados estão na forma de uma lista, só precisamos chamar o método size() no objeto List:
@Override public int getItemCount() { return persons.size(); }
Em seguida, substitua o método onCreateViewHolder. Como o próprio nome sugere, esse método é chamado quando o ViewHolder personalizado precisa ser inicializado. Nós especificamos o layout que cada item do RecyclerView deve usar. Isso é feito inflando o layout usando LayoutInflater, passando a saída para o construtor do ViewHolder personalizado.
@Override public PersonViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item, viewGroup, false); PersonViewHolder pvh = new PersonViewHolder(v); return pvh; }
Sobrescreva o onBindViewHolder para especificar o conteúdo de cada item do RecyclerView. Esse método é muito semelhante ao método getView de um Adapter de ListView. Em nosso exemplo, aqui é onde você deve definir os valores dos campos nome, idade e foto do CardView.
@Override public void onBindViewHolder(PersonViewHolder personViewHolder, int i) { personViewHolder.personName.setText(persons.get(i).name); personViewHolder.personAge.setText(persons.get(i).age); personViewHolder.personPhoto.setImageResource(persons.get(i).photoId); }
Finalmente, você precisa substituir o método onAttachedToRecyclerView. Por enquanto, podemos simplesmente usar a implementação da superclasse deste método como mostrado abaixo.
@Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); }
Usando o Adapter
Agora que o Adapter está pronto, inclua o seguinte código em sua Activity para inicializar e usar o Adapter chamando o construtor do e o método setAdapter() do RecyclerView:
RVAdapter adapter = new RVAdapter(persons); rv.setAdapter(adapter);
Conclusão
Você criou um RecyclerView, CardView e todos os componentes necessários, como um LayoutManager, um Adapter e um ViewHolder.
Acima de tudo, você percebeu como a separação de componentes, um atributo importante do RecyclerViews, oferece tanta funcionalidade com tanta facilidade.
Se você tiver listagens muito grande e layouts complexos, então sempre utilize o RecyclerView.
Observe que, embora um RecyclerView possa fazer quase tudo que um ListView, para conjuntos de dados pequenos e layouts simples, ainda é preferível usar um ListView, pois ele exige menos linhas de código.