С 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 +!