Building a chat application with FirebaseUI for Android
In this code lab you'll build a chat application for Android using Firebase and Android Studio.
What you'll learn:
- Interacting with Firebase from an Android application
The steps:
- Register with Firebase
- Create a project in Android Studio
- Connect the Android app to Firebase
- Send a message
- Show the messages
- Enable login
What you'll need
- Android Studio version 1.3 or up
- A test device or emulator with Android 2.3.3 or up
- The device must have internet access to the Firebase servers
- While we'll show you what to do in Android Studio, this code lab does not explain how Android works
Register with Firebase
The first step is to create a Firebase application. This will be the server-side component that our Android application talks to.
- Go to the Firebase web site
Login or sign up
Manage the app that was automatically created for you
This app is on Firebase's free hacker plan. This plan is great for when you're developing your app on Firebase.
Any data that our Android application writes, will be visible in the Data tab
The custom Firebase backend for our application is now ready for use. Let's set up our app in Android Studio.
Create a project in Android Studio
In this step we'll create a project in Android Studio.
Start Android Studio and Start a new Android Studio project
You can name the project anything you want. But in the code below, we've named it Nanochat
Set the minimum SDK to 10 or higher.
We've left it on 10 (Gingerbread) here, since that is the lowest API level Firebase supports.
Start with a Empty Activity
We'll leave all the defaults for this activity
If the project outline is not visible on the left, click the 1:Project label
Open up the main activity, which can be found in
app/res/layout/activity_main.xml
and switch from its Design to its Text tab if needed. In this file the root element will be aRelativeLayout
and in there will be aTextView
. We won't be using theTextView
, so delete it (or leave it and put a welcome message in it).We now have a blank project in Android Studio. Let's wire our app up to Firebase!
Connect the Android app to Firebase
Before we can start writing code that interacts with our Firebase database, we'll need to make Android Studio aware that we'll be using Firebase. We need to do this in a few places: in the gradle.build
script for our app and in its AndroidManifest.xml
.
First, open Gradle Scripts > build.gradle (Module: app)
This file contains the steps that Android Studio uses to build our app. We'll add a reference to Firebase to it, so we can start using it.
Then add the following lines to the dependencies object at the bottom:
compile 'com.firebase:firebase-client-android:2.5.0'
compile 'com.firebaseui:firebase-ui:0.3.1'
This tells Gradle to include the Firebase SDK and the FirebaseUI library.
Add the following inside the android
object:
packagingOptions {
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE-FIREBASE.txt'
exclude 'META-INF/NOTICE'
}
This tells Gradle to exclude some files that otherwise create conflicts during the build.
At this stage you'll need to synchronize the project with the gradle files again. Either click the Sync Now link in the notification bar or the corresponding button in the toolbar: Sync Project with Gradle Files.
![Sync Project with Gradle Files button in toolbar](images/3_2.png)
Android Studio will parse the gradle files and pick up our changes.
Since Firebase is a hosted service, our app will need to be able to access the internet. Open app > manifests > AndroidManifest.xml then add this line inside the manifest
element:
<uses-permission android:name="android.permission.INTERNET" />
Import Firebase at the top of your MainActivity by adding the following line:
import com.firebase.client.Firebase;
Now we can get to the Java code. The first step there is to set up initial connection between our code and its Firebase backend.
open MainActivity.java
and add this code to the end of the onCreate
method:
Firebase.setAndroidContext(this);
This code allows the Firebase client to keep its context.
If Android Studio is having trouble finding the Firebase class, be sure that you've added dependencies and have synchronized the build file with the project.
We also want to create a connection to our database. We'll keep this connection in a member field:
private Firebase mFirebaseRef;
that we initialize in onCreate:
mFirebaseRef = new Firebase("https://<your-app>.firebaseio.com");
Be sure to replace <your-app>
with the name of the Firebase app you created in the first section.
That's all the setup that is required. Next up we'll allow the user to enter a message in our app and send the message to Firebase.
Send a message
Next we'll send data to Firebase! In this step we'll allow the user to enter a message in a text box. When they then click the Send button, we will send the message to Firebase.
We'll first add the necessary views to activity_main.xml:
<LinearLayout
android:id="@+id/footer"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<EditText
android:id="@+id/text_edit"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:singleLine="true"
android:inputType="textShortMessage" />
<Button
android:id="@+id/send_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Send" />
</LinearLayout>
This layout puts a horizontal bar at the bottom that contains an EditText
, where the user can enter their chat message, and a Button
that they can click to send the message.
In our MainActivity.java
we'll now add variables for the EditText
and Button
at the end of the onCreate method:
final EditText textEdit = (EditText) this.findViewById(R.id.text_edit);
Button sendButton = (Button) this.findViewById(R.id.send_button);
Next, we'll add a method that grabs the text from the input and send it to our Firebase database:
sendButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String text = textEdit.getText().toString();
Map<String,Object> values = new HashMap<>();
values.put("name", "Android User");
values.put("text", text);
mFirebaseRef.push().setValue(values);
textEdit.setText("");
}
});
You will have to import the packages for some of these classes. Android Studio will tell you where to import them from.
Here we grab the message from the EditText, add it to a Map, and send it off to Firebase. We'll look at a way to replace that Map with something more type-safe in the next section, but for now this will work.
We hard-coded our user name for the moment. We'll use Firebase Authentication to make this dynamic in the last section of this code lab.
If you now run the application in the emulator, you will see an input field with a Send button that sends the message to Firebase. Open the URL of your Firebase database, and you'll see it light up green as you add new messages.
Open the Data tab in the Firebase Dashboard of your app. You'll see it light up green as you add new messages. Admit it, this is pretty cool!
Now that we can send messages to Firebase, it is time for the next step: making the messages show up in our Android app in realtime.
Show the (existing and new) messages
A chat app that doesn’t show existing messages is not very useful. So in this step we’ll add a list of the existing messages to our Android app. And since we're using Firebase, new chat messages will be added to this list automatically. At the end of this section we’ll have a fully functional chat app.
Let's take this in chunks: first we'll create a Java class to represent each message, then we'll create an Adapter that gets each of the messages from Firebase and puts them into a ListView.
As you can see in the screenshot, each chat message has the same layout. Instead of creating a custom layout, we'll use one of the built-in layouts of Android: android.R.layout.two_line_list_item
. We'll show the user name on the first line (in bold) and the message text on the second line.
Create a class ChatMessage.java
that wraps the username and text message:
public class ChatMessage {
private String name;
private String text;
public ChatMessage() {
// necessary for Firebase's deserializer
}
public ChatMessage(String name, String text) {
this.name = name;
this.text = text;
}
public String getName() {
return name;
}
public String getText() {
return text;
}
}
As you can see, this is plain-old Java object. But it’s a POJO with some special traits. First ChatMessage
follows a JavaBean pattern for its property names. The getName
method is a getter for a name
property, while getText()
is a getter for a text
property. And second, those property names correspond to the ones we’ve been using when we sent messages to Firebase in our OnClickListener
.
Warning: if you end up making this ChatMessage
an inner class of another class, you must make it static: public static class ChatMessage
.
With the layout for the message specified and their structure defined in a class, we need to make a space for them in the main_activity.xml
Add a ListView with android:id="@android:id/list"
above the LinearLayout:
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/footer"/>
This is the container that all messages will be added to: one message_layout for each ChatMessage.
The id
value is very important here, since we'll use it to look up this list before we populate it with items.
We're ready to start on our ListAdapter, which we'll base on the FirebaseListAdapter
from the firebase-ui project we imported. The FirebaseListAdapter
class adapts a Firebase collection so that it becomes usable in an Android ListView
. First we'll add a member to our MainActivity
:
public class MainActivity extends AppCompatActivity {
private Firebase mFirebaseRef;
FirebaseListAdapter<ChatMessage> mListAdapter;
To make everything come together, we add this to the onCreate method of our MainActivity:
final ListView listView = (ListView) this.findViewById(android.R.id.list);
mListAdapter = new FirebaseListAdapter<ChatMessage>(this, ChatMessage.class,
android.R.layout.two_line_list_item, mFirebaseRef) {
@Override
protected void populateView(View v, ChatMessage model, int position) {
((TextView)v.findViewById(android.R.id.text1)).setText(model.getName());
((TextView)v.findViewById(android.R.id.text2)).setText(model.getText());
}
};
listView.setAdapter(mListAdapter);
The FirebaseListAdapter maps the data from your Firebase database into the ListView that you added to the layout. It creates a new instance of your two_line_list_item
for each ChatMessage
and calls the populateView
method. We override this method and put the name and text in the correct subviews.
Don't worry, the hardest part is behind us now. All that is left in this step is some clean-up. But before that, run your app and see that it shows all existing messages. And if you send a new message, it shows up in the emulator and in your Firebase dashboard.
The cleanup is minor, but it's important to keep our code as readable as possible at all times. Remember that onSendButtonClick method that we wrote in step 5? That use of a Map looked a bit messy. Now that we have a ChatMessage class, we can make it much more readable:
sendButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String text = textEdit.getText().toString();
ChatMessage message = new ChatMessage("Android User", text);
mFirebaseRef.push().setValue(message);
textEdit.setText("");
}
});
Finally, we also need to clean up our list adapter when the activity is destroyed. This will close the connection to the Firebase server, when the activity is not showing.
@Override
protected void onDestroy() {
super.onDestroy();
mListAdapter.cleanup();
}
In this section we made our app show the chat messages. It was a lot of work, but in the end you can see that the Java code for our main activity still fits in a single screenshot.
Enable e-mail+password login
As a final step, we're going to allow the users of our app to log in using email and password.
In the Login & Auth tab of your Firebase dashboard, enable Email & Password authentication
First add a button to the top right of activity_main.xml
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Login"
android:id="@+id/login"
android:layout_alignTop="@android:id/list"
android:layout_alignRight="@android:id/list"
android:layout_alignEnd="@android:id/list" />
We'll change our MainActivity
definition to extend FirebaseLoginBaseActivity
. This allows us to make use of FirebaseUIs headful auth in the easiest way.
public class MainActivity extends FirebaseLoginBaseActivity {
Then we need to update our usage of FirebaseListAdapter.
final ListView listView = (ListView) this.findViewById(android.R.id.list);
mListAdapter = new FirebaseListAdapter<ChatMessage>(this, ChatMessage.class,
android.R.layout.two_line_list_item, mFirebaseRef) {
@Override
protected void populateView(View v, ChatMessage model, int position) {
((TextView)v.findViewById(android.R.id.text1)).setText(model.getName());
((TextView)v.findViewById(android.R.id.text2)).setText(model.getText());
}
};
listView.setAdapter(mListAdapter);
We'll need to add a few event handlers onto MainActivity
so we can react to login events.
@Override
protected Firebase getFirebaseRef() {
return mFirebaseRef;
}
@Override
protected void onFirebaseLoginProviderError(FirebaseLoginError firebaseLoginError) {
}
@Override
protected void onFirebaseLoginUserError(FirebaseLoginError firebaseLoginError) {
}
Then we can enable an auth provider. In this example we'll just use PASSWORD
but social providers can be enabled here, too.
@Override
protected void onStart() {
super.onStart();
setEnabledAuthProvider(AuthProviderType.PASSWORD);
}
We want our users to be able to click a button to be prompted to log in, so we'll wire up the button we added a moment ago to call showFirebaseLoginPrompt()
.
Button loginButton = (Button) this.findViewById(R.id.login);
loginButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showFirebaseLoginPrompt();
}
});
Now go into your Firebase Dashboard and go to the Auth tab and select "Email/Password". You'll see an "Add User" button. Create a user to test logging in with.
This is also where you can configure the password reset emails that you can send to your users, in case they forgot their password.
Now run your app and click the Login button and you'll see the FirebaseUI dialog. When a user logs in the event handlers we added on our activity will be called and you can interact with their authentication data however you want.
Wrap-up
Wrap-up
Congratulations! You've just built a fully functional multi-user chat application that uses Firebase to store the data and authentication users.
As a reward for finishing the codelab you’ve earned a promo code! When you’re ready to put your Firebase app in production, you can use the promo code androidcodelab49
for $49 off your first month of a paid Firebase plan. Just enter the code when you upgrade your Firebase.
What we've covered
- Interacting with a Firebase Database from an Android application.
- Using Firebase Authentication in an Android application to authenticate users.
Next Steps
- Add a log-out button to the app
- Add a password-reset button to the login dialog
- Use a RecyclerView (and
FirebaseRecyclerViewAdapter
) to ensure the activity also performs well when there are lots of messages - Allow the user to specify a nickname or use one of the Firebase's social authentication providers to look up their first name.
- Get your app on the Play Store!
Learn More
- Learn all about using Firebase with Android by following the Firebase for Android development guide.
- Study a more advanced sample application: AndroidDrawing.
- Learn about GeoFire for Java, which allows you to add realtime location queries to your Android application