
С Firebase создание социальных приложений в реальном времени — это прогулка по парку. И самое главное: вам не нужно писать ни одной строчки кода на стороне сервера.
В этом уроке я покажу вам, как использовать пользовательский интерфейс Firebase для создания приложения для чата, которым вы можете поделиться со своими друзьями. Это будет очень простое приложение с одной чат-комнатой, которая открыта для всех пользователей.
Как вы уже догадались, приложение будет зависеть от Firebase Auth для управления регистрацией пользователей и входа в систему. Оно также будет использовать базу данных Firebase в реальном времени для хранения сообщений группового чата.
Предпосылки
Чтобы следовать этому пошаговому руководству, вам потребуется следующее:
- Последняя версия Android Studio
- Аккаунт Firebase
Инструкции по настройке учетной записи Firebase и подготовке к разработке Firebase в Android Studio см. В моем учебном руководстве Начало работы с Firebase для Android здесь, на Envato Tuts +.
1. Создайте проект Android Studio
Запустите Android Studio и создайте новый проект с пустым действием MainActivity .

Чтобы настроить проект для использования платформы Firebase, откройте окно Помощника Firebase, щелкнув Инструменты> Firebase .
При использовании платформы Firebase обычно хорошей идеей является добавление Firebase Analytics в проект. Поэтому в окне Firebase Assistant перейдите в раздел « Аналитика » и нажмите «Записать событие аналитики» .

Затем нажмите кнопку « Подключиться к Firebase» и убедитесь, что выбрана опция « Создать новый проект Firebase» . Как только соединение установлено, нажмите кнопку « Добавить аналитику в ваше приложение» .

На данный момент проект Android Studio не только интегрирован с Firebase Analytics, но и готов использовать все другие сервисы Firebase.
2. Добавить зависимости
В этом проекте мы будем использовать две библиотеки: пользовательский интерфейс Firebase и библиотеку поддержки дизайна Android. Поэтому откройте файл build.gradle модуля app и добавьте в него следующие зависимости compile :
|
1
2
|
compile ‘com.android.support:design:23.4.0’
compile ‘com.firebaseui:firebase-ui:0.6.0’
|
Нажмите кнопку « Синхронизировать сейчас» , чтобы обновить проект.
3. Определите макеты
Файл MainActivity , который уже связан с MainActivity , определяет содержимое главного экрана приложения. Другими словами, он будет представлять чат.
Как и большинство других приложений группового чата, доступных сегодня, наше приложение будет иметь следующие элементы пользовательского интерфейса:
- Список, отображающий все сообщения группового чата в хронологическом порядке.
- Поле ввода, в котором пользователь может ввести новое сообщение
- Кнопка, которую пользователь может нажать, чтобы опубликовать сообщение
Следовательно, activity_main.xml должен иметь ListView , EditText и FloatingActionButton . Поместив их все в виджет RelativeLayout , ваш макет XML должен выглядеть следующим образом:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
<?xml version=»1.0″ encoding=»utf-8″?>
<RelativeLayout xmlns:android=»https://schemas.android.com/apk/res/android»
xmlns:app=»http://schemas.android.com/apk/res-auto»
xmlns:tools=»http://schemas.android.com/tools»
android:id=»@+id/activity_main»
android:layout_width=»match_parent»
android:layout_height=»match_parent»
android:paddingBottom=»@dimen/activity_vertical_margin»
android:paddingLeft=»@dimen/activity_horizontal_margin»
android:paddingRight=»@dimen/activity_horizontal_margin»
android:paddingTop=»@dimen/activity_vertical_margin»
tools:context=»com.tutsplus.mychatapp.MainActivity»>
<android.support.design.widget.FloatingActionButton
android:layout_width=»wrap_content»
android:layout_height=»wrap_content»
android:clickable=»true»
android:src=»@drawable/ic_send_black_24dp»
android:id=»@+id/fab»
android:tint=»@android:color/white»
android:layout_alignParentBottom=»true»
android:layout_alignParentEnd=»true»
app:fabSize=»mini» />
<android.support.design.widget.TextInputLayout
android:layout_width=»match_parent»
android:layout_height=»wrap_content»
android:layout_toLeftOf=»@id/fab»
android:layout_alignParentBottom=»true»
android:layout_alignParentStart=»true»>
<EditText
android:layout_width=»match_parent»
android:layout_height=»wrap_content»
android:hint=»Input»
android:id=»@+id/input»
/>
</android.support.design.widget.TextInputLayout>
<ListView
android:layout_width=»match_parent»
android:layout_height=»match_parent»
android:layout_alignParentTop=»true»
android:layout_alignParentStart=»true»
android:layout_above=»@id/fab»
android:dividerHeight=»16dp»
android:divider=»@android:color/transparent»
android:id=»@+id/list_of_messages»
android:layout_marginBottom=»16dp»/>
</RelativeLayout>
|
Обратите внимание, что я поместил виджет EditText внутри виджета TextInputLayout . Это добавляет плавающую метку в EditText , что важно, если вы хотите придерживаться принципов дизайна материалов.
Теперь, когда макет домашнего экрана готов, мы можем перейти к созданию макета для сообщений чата, которые будут элементами внутри ListView . Начните с создания нового XML-файла макета с именем message.xml , корневым элементом которого является RelativeLayout .
Макет должен иметь виджеты TextView для отображения текста сообщения чата, времени его отправки и его автора. Вы можете разместить их в любом порядке. Вот макет, который я буду использовать:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
<RelativeLayout xmlns:android=»http://schemas.android.com/apk/res/android»
android:layout_width=»match_parent» android:layout_height=»match_parent»>
<TextView
android:layout_width=»wrap_content»
android:layout_height=»wrap_content»
android:layout_alignParentTop=»true»
android:layout_alignParentStart=»true»
android:id=»@+id/message_user»
android:textStyle=»normal|bold» />
<TextView
android:layout_width=»wrap_content»
android:layout_height=»wrap_content»
android:layout_alignBottom=»@+id/message_user»
android:layout_alignParentEnd=»true»
android:id=»@+id/message_time» />
<TextView
android:layout_width=»wrap_content»
android:layout_height=»wrap_content»
android:layout_below=»@+id/message_user»
android:layout_alignParentStart=»true»
android:layout_marginTop=»5dp»
android:id=»@+id/message_text»
android:textAppearance=»@style/TextAppearance.AppCompat.Body1″
android:textSize=»18sp» />
</RelativeLayout>
|
4. Обработайте аутентификацию пользователя
Разрешить пользователям анонимно публиковать сообщения в чате было бы очень плохой идеей. Это может привести к спаму, проблемам с безопасностью и не совсем идеальному взаимодействию пользователей в чате. Поэтому давайте теперь настроим наше приложение так, чтобы только зарегистрированные пользователи могли читать и отправлять сообщения.
Начните с перехода в раздел Auth консоли Firebase и включения электронной почты / пароля в качестве поставщика входа.

Не стесняйтесь также включать провайдеров входа OAuth 2.0. Тем не менее, FirebaseUI v0.6.0 без проблем поддерживает только Google Sign-In и Facebook Login.
Шаг 1. Обработка входа пользователя
Как только приложение запускается, оно должно проверить, вошел ли пользователь в систему. Если это так, приложение должно продолжить работу и отобразить содержимое чата. В противном случае он должен перенаправить пользователя либо на экран входа, либо на экран регистрации. С FirebaseUI создание этих экранов занимает гораздо меньше кода, чем вы можете себе представить.
Внутри onCreate() метода MainActivity проверьте, MainActivity ли пользователь в систему, проверив, является ли текущий объект FirebaseUser не null . Если значение равно null , необходимо создать и настроить объект Intent который открывает действие входа. Для этого используйте класс SignInIntentBuilder . Как только намерение будет готово, вы должны запустить startActivityForResult() используя метод startActivityForResult() .
Обратите внимание, что вход в систему также позволяет новым пользователям зарегистрироваться. Следовательно, вам не нужно писать дополнительный код для регистрации пользователя.
Добавьте следующий код в метод onCreate() :
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
if(FirebaseAuth.getInstance().getCurrentUser() == null) {
// Start sign in/sign up activity
startActivityForResult(
AuthUI.getInstance()
.createSignInIntentBuilder()
.build(),
SIGN_IN_REQUEST_CODE
);
} else {
// User is already signed in. Therefore, display
// a welcome Toast
Toast.makeText(this,
«Welcome » + FirebaseAuth.getInstance()
.getCurrentUser()
.getDisplayName(),
Toast.LENGTH_LONG)
.show();
// Load chat room contents
displayChatMessages();
}
|
Как видно из приведенного выше кода, если пользователь уже вошел в систему, мы сначала отображаем Toast приветствующий пользователя, а затем вызываем метод с именем displayChatMessages . А пока просто создайте заглушку для него. Мы будем добавлять код к нему позже.
|
1
2
3
|
private void displayChatMessages() {
}
|
Как только пользователь MainActivity в систему, MainActivity получит результат в форме Intent . Чтобы справиться с этим, вы должны переопределить метод onActivityResult() .
Если код результата RESULT_OK , это означает, что пользователь успешно RESULT_OK в систему. Если это так, вы должны снова вызвать метод displayChatMessages() . В противном случае вызовите finish() чтобы закрыть приложение.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == SIGN_IN_REQUEST_CODE) {
if(resultCode == RESULT_OK) {
Toast.makeText(this,
«Successfully signed in. Welcome!»,
Toast.LENGTH_LONG)
.show();
displayChatMessages();
} else {
Toast.makeText(this,
«We couldn’t sign you in. Please try again later.»,
Toast.LENGTH_LONG)
.show();
// Close the app
finish();
}
}
}
|
На этом этапе вы можете запустить приложение и взглянуть на экраны входа и регистрации.

Шаг 2. Обработка выхода пользователя
По умолчанию FirebaseUI использует Smart Lock для паролей . Поэтому, как только пользователи войдут в систему, они останутся в системе, даже если приложение будет перезапущено. Чтобы разрешить пользователям выходить из системы, теперь мы добавим параметр выхода в меню переполнения MainActivity .
Создайте новый файл ресурсов меню с именем main_menu.xml и добавьте в него отдельный item , атрибут title которого установлен на Выход . Содержимое файла должно выглядеть так:
|
1
2
3
4
5
6
7
|
<menu xmlns:android=»http://schemas.android.com/apk/res/android»
xmlns:app=»http://schemas.android.com/apk/res-auto»>
<item android:title=»Sign out» app:showAsAction=»never»
android:id=»@+id/menu_sign_out»/>
</menu>
|
Чтобы создать экземпляр ресурса меню внутри MainActivity , переопределите метод onCreateOptionsMenu() и вызовите метод onCreateOptionsMenu() объекта MenuInflater .
|
1
2
3
4
5
|
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
return true;
}
|
Затем переопределите метод onOptionsItemSelected() для обработки событий щелчка в пункте меню. Внутри метода вы можете вызвать метод signOut() класса AuthUI для выхода из системы. Поскольку операция выхода выполняется асинхронно, мы также добавим к ней OnCompleteListener .
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId() == R.id.menu_sign_out) {
AuthUI.getInstance().signOut(this)
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
Toast.makeText(MainActivity.this,
«You have been signed out.»,
Toast.LENGTH_LONG)
.show();
// Close activity
finish();
}
});
}
return true;
}
|
Как только пользователь вышел, приложение должно автоматически закрыться. Вот почему вы видите вызов метода finish() в приведенном выше коде.
5. Создайте модель
Чтобы сохранять сообщения чата в базе данных Firebase в реальном времени, вы должны создать модель для них. Макет сообщения чата, который мы создали ранее в этом уроке, имеет три вида. Чтобы иметь возможность заполнять эти представления, модель также должна иметь как минимум три поля.
Создайте новый класс Java с именем ChatMessage.java и добавьте в него три переменные-члена: messageText , messageUser и messageTime . Также добавьте конструктор для инициализации этих переменных.
Чтобы сделать модель совместимой с FirebaseUI, вы также должны добавить к ней конструктор по умолчанию, а также методы получения и установки для всех переменных-членов.
На этом этапе класс ChatMessage должен выглядеть следующим образом:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
public class ChatMessage {
private String messageText;
private String messageUser;
private long messageTime;
public ChatMessage(String messageText, String messageUser) {
this.messageText = messageText;
this.messageUser = messageUser;
// Initialize to current time
messageTime = new Date().getTime();
}
public ChatMessage(){
}
public String getMessageText() {
return messageText;
}
public void setMessageText(String messageText) {
this.messageText = messageText;
}
public String getMessageUser() {
return messageUser;
}
public void setMessageUser(String messageUser) {
this.messageUser = messageUser;
}
public long getMessageTime() {
return messageTime;
}
public void setMessageTime(long messageTime) {
this.messageTime = messageTime;
}
}
|
6. Опубликовать сообщение чата
Теперь, когда модель готова, мы можем легко добавить новые сообщения чата в базу данных Firebase в реальном времени.
Чтобы опубликовать новое сообщение, пользователь нажмет кнопку FloatingActionButton . Поэтому вы должны добавить к нему OnClickListener .
Внутри слушателя вы должны сначала получить объект DatabaseReference с помощью getReference() класса FirebaseDatabase . Затем вы можете вызвать методы push() и setValue() чтобы добавить новые экземпляры класса ChatMessage в базу данных реального времени.
ChatMessage экземпляры ChatMessage должны быть инициализированы с использованием содержимого EditText и отображаемого имени текущего пользователя, ChatMessage в систему.
Соответственно добавьте следующий код в метод onCreate() :
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
FloatingActionButton fab =
(FloatingActionButton)findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
EditText input = (EditText)findViewById(R.id.input);
// Read the input field and push a new instance
// of ChatMessage to the Firebase database
FirebaseDatabase.getInstance()
.getReference()
.push()
.setValue(new ChatMessage(input.getText().toString(),
FirebaseAuth.getInstance()
.getCurrentUser()
.getDisplayName())
);
// Clear the input
input.setText(«»);
}
});
|
Данные в базе данных реального времени Firebase всегда хранятся в виде пар ключ-значение. Однако, если вы посмотрите на приведенный выше код, вы увидите, что мы вызываем setValue() без указания какого-либо ключа. Это разрешено только потому, что вызову setValue() предшествует вызов метода push() , который автоматически генерирует новый ключ.
7. Показать сообщения чата
FirebaseUI имеет очень удобный класс, называемый FirebaseListAdapter , который значительно сокращает усилия, необходимые для заполнения ListView используя данные, присутствующие в базе данных Firebase в реальном времени. Теперь мы будем использовать его для извлечения и отображения всех объектов ChatMessage , которые присутствуют в базе данных.
Добавьте объект FirebaseListAdapter в качестве новой переменной- MainActivity класса MainActivity .
|
1
|
private FirebaseListAdapter<ChatMessage> adapter;
|
Внутри displayChatMessages() инициализируйте адаптер, используя его конструктор, который ожидает следующие аргументы:
- Ссылка на
Activity -
classинтересующего вас объекта - Расположение элементов списка
- Объект
DatabaseReference
FirebaseListAdapter является абстрактным классом и имеет абстрактный метод populateView() , который необходимо переопределить.
Как следует из его названия, populateView() используется для заполнения представлений каждого элемента списка. Если вы знакомы с классом ArrayAdapter , вы можете думать о ArrayAdapter populateView() как об альтернативе getView() .
Внутри метода вы должны сначала использовать findViewById() чтобы получить ссылки на каждый TextView , присутствующий в файле макета message.xml . Затем вы можете вызвать их методы setText() и заполнить их, используя методы получения класса ChatMessage .
На этом этапе содержимое метода displayChatMessages() должно displayChatMessages() так:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
ListView listOfMessages = (ListView)findViewById(R.id.list_of_messages);
adapter = new FirebaseListAdapter<ChatMessage>(this, ChatMessage.class,
R.layout.message, FirebaseDatabase.getInstance().getReference()) {
@Override
protected void populateView(View v, ChatMessage model, int position) {
// Get references to the views of message.xml
TextView messageText = (TextView)v.findViewById(R.id.message_text);
TextView messageUser = (TextView)v.findViewById(R.id.message_user);
TextView messageTime = (TextView)v.findViewById(R.id.message_time);
// Set their text
messageText.setText(model.getMessageText());
messageUser.setText(model.getMessageUser());
// Format the date before showing it
messageTime.setText(DateFormat.format(«dd-MM-yyyy (HH:mm:ss)»,
model.getMessageTime()));
}
};
listOfMessages.setAdapter(adapter);
|
Приложение группового чата готово. Запустите его и отправьте новые сообщения, чтобы увидеть их сразу же в ListView . Если вы поделитесь приложением с друзьями, вы также сможете увидеть их сообщения, как только они отправят их.
Вывод
Из этого руководства вы узнали, как использовать Firebase и FirebaseUI для создания очень простого приложения для группового чата. Вы также увидели, как легко работать с классами, доступными в FirebaseUI, чтобы быстро создавать новые экраны и реализовывать сложные функции.
Чтобы узнать больше о Firebase и FirebaseUI, обратитесь к официальной документации . Или посмотрите некоторые другие наши учебники по Firebase здесь на Envato Tuts +!


