Как использовать список в Android с помощью RecyclerView?

Если Вы начали изучение программирование под платформу Android, очень скоро от «Hello World!» Вы приступите к созданию более разумных приложений. Почти что в каждом приложении под Android Вы будете встречаться с использованием списков, их реализация не такая уж и тривиальная, как это можно себе представить на первых порах, особенно для новичков! Очень важно сразу разобраться в концепции и набить руку, иначе после придётся часто возвращаться к старым наработкам для выдёргивания кусков рабочего кода.RecyclerView
Я расскажу как реализован список с помощью виджета RecyclerView, любезно предоставленного нам корпорацией Google. Виджет развивается и есть смысл хорошенько познакомится с его реализацией и предоставляемым API. На скришоте пример того, как должен выглядеть в итоге наш список.

Наше приложение будет состоять из фабрики клонов, которая будет генерировать 100 объектов, и одного активити, внутри которого опишем необходимые классы, для работы с RecyclerView.

Также нам будет необходимо создать 2 файла-макета. Один activity_main.xml для RecycleView, в нём будет описан только сам виджет. Второй list_item_person.xml для представления отдельного элемента списка.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView
    android:id="@+id/recyclerView"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/colorPrimary"
    android:scrollbars="vertical"
    />

list_item_person.xml

<?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="wrap_content"
              android:layout_marginBottom="2dp"
              android:orientation="vertical"
              android:padding="4dp"
              android:background="#FFFFFF"
    >
    
    <TextView
        android:id="@+id/personNameView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#FFFFFF"/>

    <TextView
        android:id="@+id/personAdressView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"

        android:background="#FFFFFF"/>
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:background="#FFFFFF"
        >

        <TextView
            android:id="@+id/personSexView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginRight="10dp"
            android:layout_weight="1"
            android:background="#FFFFFF"/>

        <TextView
            android:id="@+id/personAgeView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="#FFFFFF"/>

    </LinearLayout>


</LinearLayout>

 

Для начала необходимо выполнить разрешение зависимостей. Нажимаем в AndroidStudio «Ctrl+Alt+Shift+S«, жмём (1) добавить зависимость, набираем recyclerview (2), жмём поиск (3), выбираем нужную версию (4), ок (5).Choose Library Dependency

 

Наш будущий лист необходимо будет чем то заполнить. Я создал «фабрику клонов», которая создаёт 100 объектов с некими данными и с помощью метода getCloneList любезно возвращает лист, полный объектов.

import java.util.ArrayList;
import java.util.List;

public class CloneFactory {
    private static CloneFactory sCloneFactory;
    private static List<Person> mPersonList;


    public class Person {
        private String name;
        private int age;
        private String adress;
        private boolean sex;

        public Person() {
        }

        public Person(String name, int age, String adress, boolean sex) {
            this.name = name;
            this.age = age;
            this.adress = adress;
            this.sex = sex;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        public String getAdress() {
            return adress;
        }

        public void setAdress(String adress) {
            this.adress = adress;
        }

        public boolean isSex() {
            return sex;
        }

        public void setSex(boolean sex) {
            this.sex = sex;
        }
    }

    private CloneFactory() {
        mPersonList = new ArrayList<>(100);
        for (int i = 0; i < 100; i++) {
            if(i % 2 == 0){
                mPersonList.add(new Person("Иванов Иван клон#"+i, 25, "Москва", true));
            }else{
                mPersonList.add(new Person("Петрова Мария клон#"+i, 33, "Санкт-Петербург", false));
            }
        }

    }
    public static List<Person> getCloneList() {
        if(sCloneFactory == null){
            sCloneFactory = new CloneFactory();
        }
        return mPersonList;
    }
}

Всё остальное происходит в MainActivity. Для того что бы RecycleView завёлся, необходимо запастись некоторыми классами. Ему необходим адаптер — класс, наследующийся от абстрактного класса RecyclerView.Adapter.

private class PersonAdapter extends RecyclerView.Adapter<PersonHolder>{
    ...
}

     Этот адаптер выполняет связывание объектов нашей модели (В нашем случае персон-клонов) с представлениями, которые будут отображаться в списке(во вьюхе RecyclerView). Связывает он их не напрямую, а через второй класс. А второй чудо-класс —  это наследник от RecyclerView.ViewHolder, реализующий паттерн холдер. 

private class PersonHolder extends RecyclerView.ViewHolder{
    ...
}

По нему параметризуется адаптер, его роль сперва, при первом создании, запомнить все ссылки на виджеты той вьюшки, которую ему передадут в аргументе конструктора, а после, просто, по просьбе адаптера наполнять эти виджеты данными из объекта модели, которого передаёт ему в метод public void bindCrime(Person person) адаптер. Перечитайте ещё разок предыдущее предложение, оно является одним из ключевых в статье. Если плохо понятно, я постараюсь в приведённом ниже коде донести мысль в комментах. С помощью того, что он не ищет каждый раз ссылки на виджеты, а постоянно хранит их на готове, достигается скорость отработки UI RecyclerView.

import android.app.Activity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;
import info.javaway.maks.testapp.CloneFactory.*;

/*Класс-активити, в котором происходит вся кухня. Нет смысла распыляться на
фрагменты в данном случае, наша задача максимально понять как работает RecyclerView*/
public class MainActivity extends Activity {

    //ссылка на адаптер, класс который знает всё о модели и дёргает методы холдера
    private PersonAdapter mAdapter;
    //ссылка на вьюшку из представления
    private RecyclerView mRecyclerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //Заполняем лайаут Activity контейнером с единственным виджетом RecyclerView
        setContentView(R.layout.activity_main);
        //Находим ссылку на контейнер - виджет
        mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
        //LinearLayoutManager занимается размещением объектов на экране и прокруткой
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        //Подготавливаем армию клонов
        List<CloneFactory.Person> personList = CloneFactory.getCloneList();
        //Создаём экземпляр адаптера и передаём ему под командование наших клонов. Далее руководит ими он
        mAdapter = new PersonAdapter(personList);
        //Назначаем вьюхе адаптером наш экземпляр PersonAdapter
        mRecyclerView.setAdapter(mAdapter);
    }

    /*Класс PersonHolder занят тем, что держит на готове ссылки на элементы виджетов,
    которые он с радостью наполнит данными из объекта модели в методе bindCrimе.
    Этот класс используется только адаптером в коде ниже, адаптер дёргает его и поручает
    грязную работу по заполнению виджетов*/
    private class PersonHolder extends RecyclerView.ViewHolder{

        private TextView mPersonNameTextView;
        private TextView mPersonAdressTextView;
        private TextView mPersonSexTextView;
        private TextView mPersonAgeTextView;
        private CloneFactory.Person mPerson;


        public PersonHolder(View itemView) {
            super(itemView);
            mPersonNameTextView = (TextView) itemView.findViewById(R.id.personNameView);
            mPersonAdressTextView = (TextView) itemView.findViewById(R.id.personAdressView);
            mPersonSexTextView = (TextView) itemView.findViewById(R.id.personSexView);
            mPersonAgeTextView = (TextView) itemView.findViewById(R.id.personAgeView);
        }
        //Метод, связывающий ранее добытые в конструкторе ссылки с данными модели
        public void bindCrime(Person person) {
            mPerson = person;
            mPersonNameTextView.setText(mPerson.getName());
            mPersonAdressTextView.setText(mPerson.getAdress());
            mPersonAgeTextView.setText(""+mPerson.getAge());
            if(mPerson.isSex()){
                mPersonSexTextView.setText("Мужчина");
            }else {
                mPersonSexTextView.setText("Женщина");
            }

        }

    }

    //Наш адаптер, мост между фабрикой клонов и выводом их на экран.
    //Его методы будет дёргать LinearLayoutManager, назныченный вьюшке
    //RecyclerView в методе onCreate нашей активити
    private class PersonAdapter extends RecyclerView.Adapter<PersonHolder> {

        private List<CloneFactory.Person> mPersons;
        public PersonAdapter(List<CloneFactory.Person> persons) {
            mPersons = persons;
        }

        //Создаёт пустую вьюшку,оборачивает её в PersonHolder.
        //Дальше забота по наполнению этой вьюшки ложиться именно на объект PersonHolder'а
        @Override
        public PersonHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            LayoutInflater li = getLayoutInflater();
            View view = li.inflate(R.layout.list_item_person, parent, false);
            return new PersonHolder(view);

        }
        
        //Дёргает метод холдера при выводе нового элемента списка на экран,
        //передавая ему актуальный объект модели для разбора и представления
        @Override
        public void onBindViewHolder(PersonHolder holder, int position) {
            CloneFactory.Person person = mPersons.get(position);
            holder.bindCrime(person);

        }
        
        //Возвращает размер хранилища моделей
        @Override
        public int getItemCount() {
            return mPersons.size();
        }
    }
}

Вы должны были заметить, что в методе onCreate, как только мы создали виджет RecyclerView, сразу же присваеваем ему другой объект LinearLayouManagerДело в том что виджет RecyclerView очень ленивый и любит всю работу поручать другим. В том числе размещение элементов на экране и прокрутку списка он поручает именно LinearLayouManager‘у. Если не выполнить это присвоение, получим ошибку. Также на плечи бедного LinearLayouManager‘а ложиться работа по дёрганию методов onCreateViewHolder(), onBindViewHolder() и getItemCount() нашего адаптера.

В принципе это всё, что необходимо для понимания как работать со списком. Для более глубокого понимания есть описание API на сайте разработчиков, а также статья на Хабре. Надеюсь что Вы смогли понять как использовать список в приложении на андроид! 

 

 

 

Понравилась статья? Поделиться с друзьями:

Комментарии:

Комментарии: 4
  1. Evgeny

    Булевое поле sex — это шовинизм : ))))
    Да и метод isSex() выглядит странновато.

    1. sexolog

      Sex по английски сначит не только секс но и пол человека. Вогт так вот.

  2. Марина

    Спасибо за урок! Подскажите пожалуйста как теперь сделать избранное для пользователя и возможность добавлять в избранное из этого списка, нажав на сердечко или звездочку…

Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: