How to Create an Android Chat App Using Firebase
2021-04-16 00:13:19 Author: code.tutsplus.com(查看原文) 阅读量:154 收藏

With Firebase, creating real-time social applications is a walk in the park. And the best thing about it: you don't have to write a single line of server-side code.

In this tutorial, I'll show you how to leverage Firebase UI to create a group chat app you can share with your friends. It's going to be a very simple app with just one chat room, which is open to all users.

As you might have guessed, the app will depend on Firebase Auth to manage user registration and sign in. It will also use Firebase's real-time database to store the group chat messages.

Prerequisites

To be able to follow this step-by-step tutorial, you'll need the following:

For instructions on how to set up a Firebase account and get ready for Firebase development in Android Studio, see my tutorial Get Started With Firebase for Android here on Envato Tuts+.

1. Create an Android Studio Project

Fire up Android Studio and create a new project with an empty activity called MainActivity.

Add empty activity

To configure the project to use the Firebase platform, open the Firebase Assistant window by clicking on Tools > Firebase.

While using the Firebase platform, it's usually a good idea to add Firebase Analytics to the project. Therefore, inside the Firebase Assistant window, go to the Analytics section and press Log an Analytics event.

Firebase Assistant

Next, press the Connect to Firebase button and make sure that the Create new Firebase project option is selected. Once the connection is established, press the Add Analytics to your app button.

Press Add analytics to your app

At this point, the Android Studio project is not only integrated with Firebase Analytics, it is also ready to use all other Firebase services.

2. Add Dependencies

We'll be using two libraries in this project: Firebase UI, and the Android design support library. Therefore, open the build.gradle file of the app module and add the following compile dependencies to it:

compile 'com.android.support:design:23.4.0'
compile 'com.firebaseui:firebase-ui:0.6.0'

Press the Sync Now button to update the project.

3. Define Layouts

The activity_main.xml file, which is already bound to MainActivity, defines the contents of the home screen of the app. In other words, it will represent the chat room.

Like most other group chat apps available today, our app will have the following UI elements:

  • A list that displays all the group chat messages in a chronological order
  • An input field where the user can type in a new message
  • A button the user can press to post the message

Therefore, activity_main.xml must have a ListView, an EditText, and a FloatingActionButton. After placing them all inside a RelativeLayout widget, your layout XML should look like this:

<?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>

Note that I've placed the EditText widget inside a TextInputLayout widget. Doing so adds a floating label to the EditText, which is important if you want to adhere to the guidelines of material design.

Now that the layout of the home screen is ready, we can move on to creating a layout for the chat messages, which will be items inside the ListView. Start by creating a new layout XML file called message.xml, whose root element is RelativeLayout.

The layout must have TextView widgets to display the chat message's text, the time it was sent, and its author. You are free to place them in any order. Here's the layout I'll be using:

<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. Handle User Authentication

Allowing users to anonymously post messages to the chat room would be a very bad idea. It could lead to spam, security issues, and a less than ideal chatting experience for the users. Therefore, let us now configure our app such that only registered users can read and post messages.

Start by going to the Auth section of the Firebase Console and enabling Email/Password as a sign-in provider.

Feel free to enable OAuth 2.0 sign-in providers as well. However, FirebaseUI v0.6.0 seamlessly supports only Google Sign-In and Facebook Login.

Step 1: Handle User Sign-In

As soon as the app starts, it must check if the user is signed in. If so, the app should go ahead and display the contents of the chat room. Otherwise, it must redirect the user to either a sign-in screen, or a sign-up screen. With FirebaseUI, creating those screens takes a lot less code than you might imagine.

Inside the onCreate() method of MainActivity, check if the user is already signed in by checking if the current FirebaseUser object is not null. If it is null, you must create and configure an Intent object that opens a sign-in activity. To do so, use the SignInIntentBuilder class. Once the intent is ready, you must launch the sign-in activity using the startActivityForResult() method.

Note that the sign-in activity also allows new users to sign up. Therefore, you don't have write any extra code to handle user registration.

Add the following code to the onCreate() method:

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();
}

As you can see in the above code, if the user is already signed in, we first display a Toast welcoming the user, and then call a method named displayChatMessages. For now, just create a stub for it. We'll be adding code to it later.

private void displayChatMessages() {

}

Once the user has signed in, MainActivity will receive a result in the form of an Intent. To handle it, you must override the onActivityResult() method.

If the result's code is RESULT_OK, it means the user has signed in successfully. If so, you must call the displayChatMessages() method again. Otherwise, call finish() to close the app.

@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();
        }
    }

}

At this point, you can run the app and take a look at the sign-in and sign-up screens.

Sign up screen for new users

Step 2: Handle User Sign-Out

By default, FirebaseUI uses Smart Lock for Passwords. Therefore, once the users sign in, they'll stay signed in even if the app is restarted. To allow the users to sign out, we'll now add a sign-out option to the overflow menu of MainActivity.

Create a new menu resource file called main_menu.xml and add a single item to it, whose title attribute is set to Sign out. The contents of the file should look like this:

<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>

To instantiate the menu resource inside MainActivity, override the onCreateOptionsMenu() method and call the inflate() method of the MenuInflater object.

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.main_menu, menu);
    return true;
}

Next, override the onOptionsItemSelected() method to handle click events on the menu item. Inside the method, you can call the signOut() method of the AuthUI class to sign the user out. Because the sign-out operation is executed asynchronously, we'll also add an OnCompleteListener to it.

@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;
}

Once the user has signed out, the app should close automatically. That's the reason why you see a call to the finish() method in the code above.

5. Create a Model

In order to store the chat messages in the Firebase real-time database, you must create a model for them. The layout of the chat message, which we created earlier in this tutorial, has three views. To be able to populate those views, the model too must have at least three fields.

Create a new Java class called ChatMessage.java and add three member variables to it: messageText, messageUser, and messageTime. Also add a constructor to initialize those variables.

To make the model compatible with FirebaseUI, you must also add a default constructor to it, along with getters and setters for all the member variables.

At this point, the ChatMessage class should look like this:

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. Post a Chat Message

Now that the model is ready, we can easily add new chat messages to the Firebase real-time database.

To post a new message, the user will press the FloatingActionButton. Therefore, you must add an OnClickListener to it.

Inside the listener, you must first get a DatabaseReference object using the getReference() method of the FirebaseDatabase class. You can then call the push() and setValue() methods to add new instances of the ChatMessage class to the real-time database.

The ChatMessage instances must, of course, be initialized using the contents of the EditText and the display name of the currently signed in user.

Accordingly, add the following code to the onCreate() method:

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("");
    }
});

Data in the Firebase real-time database is always stored as key-value pairs. However, if you observe the code above, you'll see that we're calling setValue() without specifying any key. That's allowed only because the call to the setValue() method is preceded by a call to the push() method, which automatically generates a new key.

7. Display the Chat Messages

FirebaseUI has a very handy class called FirebaseListAdapter, which dramatically reduces the effort required to populate a ListView using data present in the Firebase real-time database. We'll be using it now to fetch and display all the ChatMessage objects that are present in the database.

Add a FirebaseListAdapter object as a new member variable of the MainActivity class.

private FirebaseListAdapter<ChatMessage> adapter;

Inside the displayChatMessages() method, initialize the adapter using its constructor, which expects the following arguments:

  • A reference to the Activity
  • The class of the object you're interested in
  • The layout of the list items
  • A DatabaseReference object

FirebaseListAdapter is an abstract class and has an abstract populateView() method, which must be overridden.

As its name suggests, populateView() is used to populate the views of each list item. If you are familiar with the ArrayAdapter class, you can think of populateView() as an alternative to the getView() method.

Inside the method, you must first use findViewById() to get references to each TextView that's present in the message.xml layout file. You can then call their setText() methods and populate them using the getters of the ChatMessage class.

At this point, the contents of the displayChatMessages() method should like this:

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);

The group chat app is ready. Run it and a post new messages to see them pop up immediately in the ListView. If you share the app with your friends, you should be able to see their messages too as soon as they post them.

Conclusion

In this tutorial, you learned how to use Firebase and FirebaseUI to create a very simple group chat application. You also saw how easy it is to work with the classes available in FirebaseUI to quickly create new screens and implement complex functionality.

To learn more about Firebase and FirebaseUI, do refer to the official documentation. Or check out some of our other Firebase tutorials here on Envato Tuts+!



文章来源: https://code.tutsplus.com/tutorials/how-to-create-an-android-chat-app-using-firebase--cms-27397
如有侵权请联系:admin#unsafe.sh