С выходом новой версии Android и привнесением в мир нового течения Material Design-а, появились и обновлённые, более современные версии старых вьюшек. Одно из таких обновлений затронуло и привычны вид отображения списка — ListView, на замену которого пришёл более быстрый и многофункциональный RecyclerView.
Главным отличием RecyclerView является создания всех элементов списка единожды, в отличии от ListView, где каждая View в списке создавалась отдельно для каждого из элементов списка, что в свою очередь приводило к огромному использованию памяти при создании достаточно больших списков.
Как начать работать с RecyclerView.
Для начала необходимо подключить библиотеку RecyclerView. Сделать это можно либо прописав зависимости в Gradle файл, либо же нажав кнопку F4 на нашем проекте и перейдя в вкладку «Dependencies». Так же подключим библиотеку CardView, так как элементы списка будем отображать в виде карточек и библиотеку Picasso, с помощью которой подгрузим изображения.
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:21.0.3'
compile 'com.android.support:cardview-v7:21.0.3'
compile 'com.android.support:recyclerview-v7:21.0.3'
compile 'com.squareup.picasso:picasso:2.3.2'
}
Теперь создадим отображение нашего списка, поместив в layout активности наш RecyclerView.
activity_main.xml
public String getUniverse(){return universe;}
public String getImage() {return image;}
}
Создавать элементы списка нам будет наш кастомный адаптер, который будет создавать представление элементов для всего списка сразу, а не для для каждого по отдельности и работа с которым не отличается от работы с кастомными адаптерами при использовании ListView.
HeroAdapter.java
package com.awesomedevelop.recyclerview;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.squareup.picasso.Picasso;
import java.util.ArrayList;
/**
* Created by Taras on 30.01.2015.
*/
public class HeroAdapter extends RecyclerView.Adapter{
private ArrayListheroDataSet;
public Context mContext;
private int lastPosition = -1;
public static class MyViewHolder extends RecyclerView.ViewHolder {
TextView textName;
TextView textUniverse;
ImageView imageHero;
public MyViewHolder(View itemView){
super (itemView);
this.imageHero = (ImageView)itemView.findViewById(R.id.image);
this.textName = (TextView)itemView.findViewById(R.id.hero_name);
this.textUniverse = (TextView)itemView.findViewById(R.id.hero_universe);
}
}
public HeroAdapter(Context context, ArrayListheroes){
this.heroDataSet= heroes;
mContext=context;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.hero_card, parent, false);
MyViewHolder myViewHolder = new MyViewHolder(view);
return myViewHolder;
}
@Override
public void onBindViewHolder(final MyViewHolder holder, final int listPosition) {
final TextView textViewName = holder.textName;
final TextView textViewUniverse = holder.textUniverse;
ImageView imageViewHero = holder.imageHero;
textViewName.setText(heroDataSet.get(listPosition).getName());
textViewUniverse.setText(heroDataSet.get(listPosition).getUniverse());
String src = heroDataSet.get(listPosition).getImage();
Picasso.with(mContext)
.load("file:///android_asset/images/"+src+".jpg")
.resize(300, 300)
.into(imageViewHero);
}
@Override
public int getItemCount() {
return heroDataSet.size();
}
}
В данном примере используются изображения, хранящиеся в папке асетов, но использовать можно (по необходимости) любое расположение. Например если используя библиотеку Picasso вы укажете путь к онлайновому расположению изображений, они будут подгружаться только для тех элементов списка, которые будут отображены на экране в данный момент, а не для всего списка сразу при его построении.
Теперь нам осталось только заполнить наш массив данных и передать его адаптеру. Выполняем это в активности, которая будет отображать список, в данном случае MainActivity.java
package com.awesomedevelop.recyclerview;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.Menu;
import android.view.MenuItem;
import java.util.ArrayList;
public class MainActivity extends ActionBarActivity {
private static ArrayListheroes;
private static RecyclerView recyclerView;
private RecyclerView.LayoutManager layoutManager;
private static RecyclerView.Adapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView)findViewById(R.id.my_recycler_view);
recyclerView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
fetchHeroes(); //Заполняем массив
adapter = new HeroAdapter(MainActivity.this,heroes); //Инициализируем наш адаптер
recyclerView.setAdapter(adapter); // Устанавливаем адаптер
}
//Заполняем массив
public void fetchHeroes(){
heroes = new ArrayList();
heroes.add(new HeroData("Зелёный Фонарь","DC comics","greenlantern"));
heroes.add(new HeroData("Джокер","DC comics","joker"));
heroes.add(new HeroData("Джона Хекс","DC comics","jonah-hex"));
heroes.add(new HeroData("Папа Миднайт","DC comics","glav"));
heroes.add(new HeroData("Ворона","DC comics","raven"));
heroes.add(new HeroData("Чёрная Вдова","Marvel","glavnaya"));
heroes.add(new HeroData("Капитан Америка","Marvel","cap_america"));
heroes.add(new HeroData("Космический Халк","Marvel","cosmic_hulk"));
heroes.add(new HeroData("Призрачный Гонщик","Marvel","ghost_rider"));
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, 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();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
Использование RecyclerView значительно улучшает работу со списками, помимо оптимизации использования памяти его использование позволяет создавать более сложные элементы списка, которые могут быть абсолютно любыми, вплоть до создания полноценных экранов в виде элементов списка.
Проект на github.
Автор: Taras Neduiev