Для тестирования давайте сделаем новую ActivitySearchUsersActivity стартовой, чтобы мы могли видеть вносимые нами изменения на экране. Для этого в файле AndroidManifest перенесём блок <intent-filter> в новую Activity:
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifestxmlns:android="http://schemas.android.com/apk/res/android"package="colibri.dev.com.colibritweet">
// остальной код выше не изменился
<activityandroid:name=".activity.UserInfoActivity"/>
<activityandroid:name=".activity.SearchUsersActivity">
<intent-filter>
<actionandroid:name="android.intent.action.MAIN"/>
<categoryandroid:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
// остальной код ниже не изменился
</manifest>
Создание UsersAdapter
В предыдущем уроке мы познакомились с элементом RecyclerView и адаптером, при помощи которого можно отобразить элементы списка. В этом уроке предлагаем вам самостоятельно создать адаптер для списка экрана SearchUsersActivity. Наш вариант реализации приведён ниже.
Для тестирования вашего решения предлагаем создать метод getUsers(), возвращающий объекты-заглушки:
SearchUsersActivity.java
publicclassSearchUsersActivityextendsAppCompatActivity {
// остальной код выше не изменилсяprivateCollection<User>getUsers() {
returnArrays.asList(
newUser(
929257819349700608L,
"http://i.imgur.com/DvpvklR.png",
"DevColibri",
"@devcolibri",
"Sample description",
"USA",
42,
42
),
newUser(
44196397L,
"https://pbs.twimg.com/profile_images/782474226020200448/zDo-gAo0_400x400.jpg",
"Elon Musk",
"@elonmusk",
"Hat Salesman",
"Boring",
14,
13
)
);
}
// остальной код ниже не изменился
}
Напоминаем, что мы уже создавали файл user_item_view. Поэтому его и используем в нашем адаптере UsersAdapter.
По аналогии с предыдущим уроком создаём класс UsersAdapter в пакете adapter.
Помним, что элемент user_item_view мы с вами делали в одном из прошлых уроков. Мы делали
его специально для использования в методе onCreateViewHolder нашего адаптера.
Отличная работа. Самое время убедиться, что всё работает. Для этого добавим использование нашего адаптера в Activity. Также давайте добавим в нашу Activity методы searchUsers(), getUsers(), чтобы отобразить в нашем списке тестовые элементы:
SearchUsersActivity.java
publicclassSearchUsersActivityextendsAppCompatActivity {
// остальной код выше не изменилсяprivateUsersAdapter usersAdapter;
@OverrideprotectedvoidonCreate(BundlesavedInstanceState) {
// остальной код выше не изменился
initRecyclerView();
searchUsers();
}
privatevoidinitRecyclerView() {
// остальной код выше не изменился
usersAdapter =newUsersAdapter();
usersRecyclerView.setAdapter(usersAdapter);
}
privatevoidsearchUsers() {
Collection<User> users = getUsers();
usersAdapter.setItems(users);
}
privateCollection<User>getUsers() {
returnArrays.asList(
newUser(
929257819349700608L,
"http://i.imgur.com/DvpvklR.png",
"DevColibri",
"@devcolibri",
"Sample description",
"USA",
42,
42
),
newUser(
44196397L,
"https://pbs.twimg.com/profile_images/782474226020200448/zDo-gAo0_400x400.jpg",
"Elon Musk",
"@elonmusk",
"Hat Salesman",
"Boring",
14,
13
)
);
}
// остальной код ниже не изменился
}
Запустим приложение, посмотрим на результат:
Отлично, идём дальше.
Обработка клика по элементу списка
Но на этом экране список немного отличается от предыдущего: здесь нам надо обработать нажатие на элемент списка и перейти на экран информации о пользователе.
Теперь о реализации. Механизм прост: физически на экране пользователь видит список из множества View-компонентов. Android обо всём позаботился до нас и всё, что необходимо сделать нам – это использовать готовый интерфейс-слушатель View.OnClickListener, который предоставляет единственный метод onClick(View v). Использовать его довольно просто (помимо представленного здесь материала также можно ознакомиться с этим):
ClickListener sample
myView.setOnClickListener(newView.OnClickListener() {
@OverridepublicvoidonClick(Viewv) {
// необходимое действие
}
});
Таким образом, установив такой слушатель на View-компонент, мы можем реагировать на события нажатия на него любым необходимым нам способом. Отлично, момент, в который происходит нажатие на компонент, мы перехватываем.
Но теперь нам нужно получить данные пользователя, которые связаны, с этим компонентом. А мы, конечно же, помним, где осуществляется связь между View-компонентами и данными – в адаптере. Т.е. именно в адаптере мы можем узнать раньше всего, что произошло нажатие по какому-либо элементу и что необходимо связать его с реальными данными.
На этом зона ответственности адаптера заканчивается. За то, что делать с информацией, полученной при нажатии на элемент должна отвечать Activity. Поэтому нам необходим «мост», некий интерфейс адаптера, который бы помог нам реагировать на нажатия по элементу списка на более высоком уровне – оперируя данными.
Помните интерфейс, который предоставляет View? С единственным методом, который сообщает нам, какой элемент был нажат. Нам нужен такой же, только сообщать он нам будет не о нажатом View, а о нажатом пользователе:
UsersAdapter.java
publicclassUsersAdapterextendsRecyclerView.Adapter<UsersAdapter.UserViewHolder> {
// код выше не изменилсяpublicinterfaceOnUserClickListener {
voidonUserClick(Useruser);
}
}
Отлично, теперь наш адаптер предоставляет интерфейс, который должен гарантировать вызов метода onUserClick(User user) при нажатии на элемент списка. Поэтому Activity смело может использовать его для реакции на данное событие.
Т.е. мы используем обычную реализацию паттерна проектирования наблюдатель.
Создание наблюдателя за кликом в SearchUsersActivity
В данном случае нам необходимо создать внутри SearchUsersActivity наблюдателя за кликом по элементу пользователя. Наблюдатель мы реализуем, создавая новый экземпляр интерфейса OnUserClickListener. Но для начала давайте добавим этот интерфейс в наш SearchUsersAdapter, чтобы мы могли передать слушателя из Activity в Adapter:
UsersAdapter.java
publicclassUsersAdapterextendsRecyclerView.Adapter<UsersAdapter.UserViewHolder> {
privateOnUserClickListener onUserClickListener;
publicUsersAdapter(OnUserClickListeneronUserClickListener) {
this.onUserClickListener = onUserClickListener;
}
// остальной код ниже не изменился
}
Пока по клику на элемент будем просто выводить имя пользователя, чтобы проверить, что всё работает правильно.
Уведомление наблюдателя о событии в UsersAdapter
Теперь осталось гарантировать, что метод onUserClick(User user) будет вызываться при каждом нажатии на элемент списка. Поэтому вызывать мы его будем в методе onClick(View v), который срабатывает именно тогда, когда нам и нужно. Отличным местом для добавления слушателя для View-компонента является место его создания в адаптере:
UsersAdapter.java
publicclassUsersAdapterextendsRecyclerView.Adapter<UsersAdapter.UserViewHolder> {
// остальной код выше не изменилсяclassUserViewHolderextendsRecyclerView.ViewHolder {
publicUserViewHolder(ViewitemView) {
// остальной код выше не изменился
itemView.setOnClickListener(newView.OnClickListener() {
@OverridepublicvoidonClick(Viewv) {
User user = userList.get(getLayoutPosition());
onUserClickListener.onUserClick(user);
}
});
}
// остальной код ниже не изменился
}
}
Метод getLayoutPosition() вернёт нам позицию, по которой произошло нажатие, что поможет нам получить по порядковому номеру элемент данных. Эти данные мы и отправляем на уровень выше в методе onUserClick(User user), с которыми уже работает Activity.
Давайте запустим приложение, проверим что при клике на элемент отображается корректное имя:
Видим, что снизу экрана вывелся Toast с именем Elon Musk. Отлично, значит всё работает корректно.
Переход на экран UserInfoActivity
Отличная работа. Но на этом экране список немного отличается от предыдущего: здесь по нажатию на элемент списка необходимо выполнить переход на детальную информацию о пользователе. Проще говоря, по нажатию на элемент списка нам необходимо узнать id пользователя, на которого мы нажали, и использовать его для перехода на детальную информацию о нём. Делать мы это будем при помощи объекта Intent (рус. намерение), при помощи которого мы сообщаем Android системе о том, что мы изъявляем желание попасть на другой экран и передать туда некоторые данные. Подробнее об этом механизме вы можете узнать из наших видеоуроков (этом и этом), а также из официальной документации.
Также давайте создадим константу USER_ID в ActivityUserInfoActivity, чтобы мы могли ссылаться на неё при получении данных на экране:
UserInfoActivity.java
publicclassUserInfoActivityextendsAppCompatActivity {
publicstaticfinalStringUSER_ID="userId";
// остальной код ниже не изменился
}
Таким образом код перехода на экран детальной информации о пользователе выглядит следующим образом:
Мы могли бы просто передать просто «сырую» строку в объекте Intent:
SearchUsersActivity.java
intent.putExtra("userId", userId);
Однако в таком случае при получении объекта Intent следующим экраном придётся снова писать данную строку. Это повышает шанс ошибки или опечатки при написании кода. Создание же константы USER_ID просто избавляет нас от необходимости задумываться о том, что скрывается внутри неё. Android Studio просто не позволит нам ошибиться.
Запустим приложение. Видим, что по клику на элемент списка мы переходим на UserInfoActivity.
Таким образом, в ходе данного урока мы рассмотрели принцип работы со слушателями существующих компонентов системы, а также научились создавать свои собственные.
После того, как вы закончите тестирование, не забудьте в манифесте приложения снова сделать ActivityUserInfoActivity стартовой.
Сайт использует cookie-файлы для того, чтобы вам было удобнее им пользоваться. Для
продолжения работы с сайтом, вам необходимо принять использование cookie-файлов.
Код начала урока:
gitzip
Структура урока:
Создание SearchUsersActivity
Вначале нам надо создать новую
Activity
–SearchUsersActivity
.Мы ещё не создавали пакет
activity
. Давайте создадим его, как мы уже делали в прошлых уроках.Давайте переместим файл
UserInfoActivity
в пакетactivity
. Для этого левой кнопкой нажимаем наUserInfoActivity
и перетягиваем в пакетactivity
.У вас появится диалог подтверждения перемещения файла, изменения его пакета во всех местах использования:
Нажимаем
Refactor
. Видим, что файл переместился. Двигаемся дальше.Давайте в пакете
activity
создадим новыйJava
файл, который назовёмSearchUsersActivity
.После этого давайте создадим
layout
для нашейActivity
. Для этого нажмём правой кнопкой по папкеlayout
и выберемNew -> Layout resource file
.Введём имя
activity_search_users
, корневым элементом выберем контейнерFrameLayout
. Сразу же добавим элементRecyclerView
в него:activity_search_users.xml
Давайте свяжем наш
layout
и нашуActivity
:SearchUsersActivity.java
Также не забываем добавить нашу
Activity
вAndroidManifest
файл:AndroidManifest.xml
Для тестирования давайте сделаем новую
Activity
SearchUsersActivity
стартовой, чтобы мы могли видеть вносимые нами изменения на экране. Для этого в файлеAndroidManifest
перенесём блок<intent-filter>
в новуюActivity
:AndroidManifest.xml
Создание UsersAdapter
В предыдущем уроке мы познакомились с элементом
RecyclerView
и адаптером, при помощи которого можно отобразить элементы списка. В этом уроке предлагаем вам самостоятельно создать адаптер для списка экранаSearchUsersActivity
. Наш вариант реализации приведён ниже.Для тестирования вашего решения предлагаем создать метод
getUsers()
, возвращающий объекты-заглушки:SearchUsersActivity.java
Напоминаем, что мы уже создавали файл
user_item_view
. Поэтому его и используем в нашем адаптереUsersAdapter
.По аналогии с предыдущим уроком создаём класс
UsersAdapter
в пакетеadapter
.Помним, что элемент
user_item_view
мы с вами делали в одном из прошлых уроков. Мы делалиего специально для использования в методе
onCreateViewHolder
нашего адаптера.UsersAdapter.java
Отличная работа. Самое время убедиться, что всё работает. Для этого добавим использование нашего адаптера в
Activity
. Также давайте добавим в нашуActivity
методыsearchUsers()
,getUsers()
, чтобы отобразить в нашем списке тестовые элементы:SearchUsersActivity.java
Запустим приложение, посмотрим на результат:
Отлично, идём дальше.
Обработка клика по элементу списка
Но на этом экране список немного отличается от предыдущего: здесь нам надо обработать нажатие на элемент списка и перейти на экран информации о пользователе.
Теперь о реализации. Механизм прост: физически на экране пользователь видит список из множества
View
-компонентов.Android
обо всём позаботился до нас и всё, что необходимо сделать нам – это использовать готовый интерфейс-слушательView.OnClickListener
, который предоставляет единственный методonClick(View v)
. Использовать его довольно просто (помимо представленного здесь материала также можно ознакомиться с этим):ClickListener sample
Таким образом, установив такой слушатель на
View
-компонент, мы можем реагировать на события нажатия на него любым необходимым нам способом. Отлично, момент, в который происходит нажатие на компонент, мы перехватываем.Но теперь нам нужно получить данные пользователя, которые связаны, с этим компонентом. А мы, конечно же, помним, где осуществляется связь между
View
-компонентами и данными – в адаптере. Т.е. именно в адаптере мы можем узнать раньше всего, что произошло нажатие по какому-либо элементу и что необходимо связать его с реальными данными.На этом зона ответственности адаптера заканчивается. За то, что делать с информацией, полученной при нажатии на элемент должна отвечать
Activity
. Поэтому нам необходим «мост», некий интерфейс адаптера, который бы помог нам реагировать на нажатия по элементу списка на более высоком уровне – оперируя данными.Помните интерфейс, который предоставляет
View
? С единственным методом, который сообщает нам, какой элемент был нажат. Нам нужен такой же, только сообщать он нам будет не о нажатомView
, а о нажатом пользователе:UsersAdapter.java
Отлично, теперь наш адаптер предоставляет интерфейс, который должен гарантировать вызов метода
onUserClick(User user)
при нажатии на элемент списка. ПоэтомуActivity
смело может использовать его для реакции на данное событие.Т.е. мы используем обычную реализацию паттерна проектирования наблюдатель.
Создание наблюдателя за кликом в SearchUsersActivity
В данном случае нам необходимо создать внутри
SearchUsersActivity
наблюдателя за кликом по элементу пользователя. Наблюдатель мы реализуем, создавая новый экземпляр интерфейсаOnUserClickListener
. Но для начала давайте добавим этот интерфейс в нашSearchUsersAdapter
, чтобы мы могли передать слушателя изActivity
вAdapter
:UsersAdapter.java
SearchUsersActivity.java
Пока по клику на элемент будем просто выводить имя пользователя, чтобы проверить, что всё работает правильно.
Уведомление наблюдателя о событии в UsersAdapter
Теперь осталось гарантировать, что метод
onUserClick(User user)
будет вызываться при каждом нажатии на элемент списка. Поэтому вызывать мы его будем в методеonClick(View v)
, который срабатывает именно тогда, когда нам и нужно. Отличным местом для добавления слушателя дляView
-компонента является место его создания в адаптере:UsersAdapter.java
Метод
getLayoutPosition()
вернёт нам позицию, по которой произошло нажатие, что поможет нам получить по порядковому номеру элемент данных. Эти данные мы и отправляем на уровень выше в методеonUserClick(User user)
, с которыми уже работаетActivity
.Давайте запустим приложение, проверим что при клике на элемент отображается корректное имя:
Видим, что снизу экрана вывелся
Toast
с именемElon Musk
. Отлично, значит всё работает корректно.Переход на экран UserInfoActivity
Отличная работа. Но на этом экране список немного отличается от предыдущего: здесь по нажатию на элемент списка необходимо выполнить переход на детальную информацию о пользователе. Проще говоря, по нажатию на элемент списка нам необходимо узнать id пользователя, на которого мы нажали, и использовать его для перехода на детальную информацию о нём. Делать мы это будем при помощи объекта
Intent
(рус. намерение), при помощи которого мы сообщаемAndroid
системе о том, что мы изъявляем желание попасть на другой экран и передать туда некоторые данные. Подробнее об этом механизме вы можете узнать из наших видеоуроков (этом и этом), а также из официальной документации.Также давайте создадим константу
USER_ID
вActivity
UserInfoActivity
, чтобы мы могли ссылаться на неё при получении данных на экране:UserInfoActivity.java
Таким образом код перехода на экран детальной информации о пользователе выглядит следующим образом:
SearchUsersActivity.java
Мы могли бы просто передать просто «сырую» строку в объекте
Intent
:SearchUsersActivity.java
Однако в таком случае при получении объекта
Intent
следующим экраном придётся снова писать данную строку. Это повышает шанс ошибки или опечатки при написании кода. Создание же константыUSER_ID
просто избавляет нас от необходимости задумываться о том, что скрывается внутри неё.Android Studio
просто не позволит нам ошибиться.Полный листинг кода:
SearchUsersActivity.java
UsersAdapter.java
Запустим приложение. Видим, что по клику на элемент списка мы переходим на
UserInfoActivity
.Таким образом, в ходе данного урока мы рассмотрели принцип работы со слушателями существующих компонентов системы, а также научились создавать свои собственные.
После того, как вы закончите тестирование, не забудьте в манифесте приложения снова сделать
Activity
UserInfoActivity
стартовой.Полезные материалы:
Полный листинг изменений кода:
Code diff