Показываем список приложений. Отображение списков в RecyclerView.

Урок #12

Урок 12 — Показываем список приложений. Отображение списков в RecyclerView.

В прошлом уроке мы научились получать список установленных приложений. Теперь нужно их как-то показать пользователю.

Давайте подумаем, как это сделать. Отображать простые данные, такие, как текст, мы уже научились. Тут же у нас есть массив (список) данных. Отображение списков работает несколько иначе.

RecyclerView

В любой ОС есть компонент, предназначенный для отображения списков. В iOS это TableView, в Android — RecyclerView (раньше был ListView, но он уже давно в прошлом).

Современные приложения в 99% случаев содержат списки в том или ином виде. Лента ВКонтакте или Facebook — список. Каталог приложений в Google Play — список. Списки бывают различной сложности и разного вида, но они есть почти везде.

Отображение списков — сложная задача для ОС. Почему?

Давайте разберемся, как устроен список. Представьте интерфейс приложения со списком. Он выглядит примерно так:

Список в Android
Список в Android

Список состоит из множества элементов, строк/ячеек:

Одна ячейка в списке
Одна ячейка в списке

Каждая ячейка — это View с некоторым количеством (в нашем случае их четыре) дочерних View.

Представьте, что у нас 10 элементов в списке. Получается, нужно создать 10 ячеек, или 40 View суммарно. Вроде не страшно?

А теперь представьте, что их не 10, а 1000. Получается, нужно создать 1000 ячеек, или 4000 View. А если 100000? Каждый View сам по себе занимает не особо много памяти, но 4000 View, да ещё и со сложной структурой займет очень много памяти.

Плюс создание View — достаточно "дорогая" операция. Когда надо создать пару десятков View, это несущественно, однако, если их количество измеряется тысячами или десятками тысяч, то создание такого количества View займет очень много места (и, скорее всего, не хватит памяти).

Как же выйти из этой ситуации?

Первое, что приходит в голову — создать столько ячеек, сколько влезает в экран, и создавать новые ячейки по мере появления их на экране, а старые, соответственно, уничтожать. Таким образом мы решаем проблему с памятью — ведь, получается, в памяти будет храниться всего 10 (или сколько там влезет в экран?) ячеек, что несущественно, и создать несколько десятков View будет не очень долго, так?

К сожалению, не так. С памятью-то проблему мы частично решили, но нужно учитывать несколько нюансов. Во-первых, постоянное создание и уничтожение объектов, особенно при быстром листании списка, будет подкидывать много работы сборщику мусора (ведь нужно освободить память от тех ячеек, которые нам больше не нужны).

Сборщик мусора, конечно, работает относительно быстро, но если он будет вызываться постоянно, интерфейс начнет подлагивать, плюс это создаст дополнительную нагрузку на CPU, что плохо скажется на потреблении заряда аккумулятора.

Но это еще полбеды. Вы же помните, я упомянул выше, что создание View — достаточно дорогая операция? Создание несколько десятков View — это не особо "тяжело" для системы, но не в том случае, когда у нас создаются десятки View каждую секунду. В общем, проблема все еще есть, и существенная.

Так как же её решить? Выход достаточно прост: мы все так же создаем столько ячеек, сколько требуется для отображения на экране, но те ячейки, которые скрылись из вида мы не уничтожаем, а переиспользуем! Отсюда, кстати, и название компонента, который отвечает за списки — RecyclerView.

Таким образом, у нас создается, скажем, 10 ячеек (количество варьируется в зависимости от того, сколько влезает в экран), и больше новые ячейки не создаются, а используются старые.

Ровно такой же алгоритм используется почти везде: в Android, iOS, Windows Phone и т.д.

Выглядит сложно? Не пугайтесь — на самом деле, все просто. Все, что требуется от нас — сообщить RecyclerView, сколько элементов в нашем списке, сказать ему, как создавать списки, и показать, как привязать данные к конкретной ячейке. Всё!

AppCompat

И последнее, о чем я обязательно расскажу, прежде чем мы перейдем к практике — это библиотеки AppCompat.

Android очень динамично развивается — постоянно добавляются новые фичи, новые элементы интерфейса и т.д. Когда-то давно для реализации некоторых фич приходилось использовать сторонние библиотеки, например, в старых версиях Android не было ActionBar, и чтобы использовать его на Android вторых версий нужно было использовать ActionBarSherlock.

Это не очень хорошо, потому что это лишняя сторонняя зависимость — за его баги не отвечает команда Android, разработку таких библиотек могут рано или поздно забросить, да и в целом это неудобно.

Или бывало даже такое, что выпускались две версии приложения — для Android 2 и для Android 3+.

Спустя какое-то время команда Android все же поняла, что это плохо сказывается на приложениях, выпускаемых для Android, и решила выпустить библиотеки AppCompat (Application Compatibility — совместимость приложений). Различные компоненты этих библиотек позволяют использовать самые новые фичи (в том числе и интерфейсные) на старых версиях Android, причем совместимость обеспечивается абсолютно прозрачно для разработчика.

Почему я рассказываю об этом прямо сейчас? RecyclerView появился только с релизом Android 5, и в более ранних версиях его не было. До Android 5 все использовали ListView, и если бы RecyclerView не было в AppCompat, нам бы сейчас пришлось либо реализовывать и ListView и RecyclerView, что не очень хорошо, либо использовать старый ListView, либо вообще отказаться от поддержки устройств на базе Android 4 (а на момент написания курса их очень много!).

Но, хвала Гуглу, мы можем просто подключить AppCompat и спокойно использовать RecyclerView :)

Использование RecyclerView

Наконец-то практика!

Для начала, как я и сказал выше, нужно подключить соответствующую библиотеку. Откройте build.gradle, соответствующий нашему приложению (не проекту!). В нем в разделе dependencies вы увидите примерно такие зависимости (версии могут отличаться):

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.0.2'

    testImplementation 'junit:junit:4.12'

    androidTestImplementation('com.android.support.test.espresso:espresso-core:3.0.1', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
}

Как видите, тут уже есть зависимость от "общей" библиотеки AppCompat. Добавьте туда строчку implementation 'com.android.support:recyclerview-v7:26.0.2' (версия может быть иной), чтобы блок dependencies выглядел вот так:

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.0.2'
    implementation 'com.android.support:recyclerview-v7:26.0.2'

    testImplementation 'junit:junit:4.12'

    androidTestImplementation('com.android.support.test.espresso:espresso-core:3.0.1', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
}

После этого синхронизируйте проект, нажав на Sync now в правом верхнем углу.

Теперь откройте файл лэйаута нашей Activity, и добавьте туда RecyclerView:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.test.packages.MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/apps_rv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</FrameLayout>

Теперь "найдём" свежесозданный RecyclerView в Java-коде (как обычно, в методе onCreate()):

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        appManager = new AppManager(this);

        RecyclerView recyclerView = findViewById(R.id.apps_rv);
    }

Так, RecyclerView у нас есть. Теперь нужно создать лэйаут для элементов списка, который мы будем отображать. Нажмите правой кнопкой на директорию res/layout, выберите New, затем Layout resource file.

Создание нового файла лэйаута
Создание нового файла лэйаута

В появившемся окне в качестве имени файла укажите view_item_app и нажмите на кнопку ОК:

Создание нового файла лэйаута
Создание нового файла лэйаута

Как вы помните из схемы, которую я приводил в начале этого урока, нам нужно отобразить иконку приложения, его название и версию.



Продолжение доступно на платных тарифах

А вместе с ним — проверка домашних заданий нашими менторами.

Это совсем недорого — всего от 440 ₽ в месяц!



ВЫБРАТЬ ТАРИФ



Вход

Войдите, чтобы пользоваться всеми преимуществами.
Это займёт всего пару секунд!

или