# Start a Basic Chat

## Build the basic layouts

Before we start handling data, we need a UI to show the outgoing/incoming data. Get started by adding some layouts for your chat bubbles and the chat `RecyclerView`.

To speed up this tutorial, just copy and paste the following pieces of code to your project. This is very basic Android stuff and we’ll not be diving deep into this part.

{% code title="back\_blue\_rounded.xml" %}

```markup
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <corners android:radius="50dp" />
    <solid android:color="@color/colorPrimary" />

</shape>
```

{% endcode %}

{% code title="back\_gray\_rounded.xml" %}

```markup
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <corners android:radius="50dp" />
    <solid android:color="#EEEEEE" />

</shape>
```

{% endcode %}

{% code title="item\_message\_self.xml" %}

```markup
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.v7.widget.AppCompatTextView
        android:id="@+id/selfMessageText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:background="@drawable/back_blue_rounded"
        android:paddingBottom="10dp"
        android:paddingEnd="20dp"
        android:paddingStart="20dp"
        android:paddingTop="10dp"
        android:textColor="@android:color/white"
        android:textSize="16sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="Hi, there!" />

</android.support.constraint.ConstraintLayout>
```

{% endcode %}

{% code title="item\_message\_other.xml" %}

```markup
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.v7.widget.AppCompatTextView
        android:id="@+id/otherMessageText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:background="@drawable/back_gray_rounded"
        android:padding="10dp"
        android:paddingBottom="10dp"
        android:paddingEnd="20dp"
        android:paddingStart="20dp"
        android:paddingTop="10dp"
        android:textColor="@android:color/black"
        android:textSize="16sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="Hello!" />

</android.support.constraint.ConstraintLayout>
```

{% endcode %}

So, you’ve added some basic layouts for rendering the chat bubbles. Now, let’s style the chat window. Open up your `activity_main.xml` layout file and add the following code:

{% code title="activity\_main.xml" %}

```markup
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    tools:context=".MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/chatRecyclerView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginBottom="10dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintBottom_toTopOf="@id/inputMessage"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="#EEEEEE"
        app:layout_constraintTop_toBottomOf="@id/chatRecyclerView" />

    <Button
        android:id="@+id/sendButton"
        style="@style/Base.Widget.AppCompat.Button.Borderless"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="5dp"
        android:text="Send"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

    <android.support.v7.widget.AppCompatEditText
        android:id="@+id/inputMessage"
        android:layout_width="0dp"
        android:layout_height="40dp"
        android:layout_marginBottom="10dp"
        android:layout_marginEnd="10dp"
        android:layout_marginStart="20dp"
        android:background="@android:color/white"
        android:hint="Type your message"
        android:inputType="textCapSentences"
        android:textSize="16sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@id/sendButton"
        app:layout_constraintStart_toStartOf="parent" />

</android.support.constraint.ConstraintLayout>
```

{% endcode %}

## Prepare the adapter

Now that your layouts are in place, get started by adding an adapter for your `RecyclerView`.

Assuming you’ve named your adapter `ChatRecyclerViewAdapter`, your class should look something like this:

{% tabs %}
{% tab title="Kotlin" %}
{% code title="ChatRecyclerViewAdapter.kt" %}

```kotlin
class ChatRecyclerViewAdapter(
    private val messageList: List<Message>,
    private val currentUserId: String
) : RecyclerView.Adapter<ChatRecyclerViewAdapter.ViewHolder>() {
    private val MESSAGE_SELF_VIEW = 0
    private val MESSAGE_OTHER_VIEW = 1

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val layoutId = if (viewType == MESSAGE_SELF_VIEW) R.layout.item_message_self else R.layout.item_message_other
        val itemView = LayoutInflater.from(parent.context).inflate(layoutId, parent, false)
        return ViewHolder(itemView)
    }

    override fun getItemCount(): Int = messageList.size

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bindMessage(messageList[position])
    }

    override fun getItemViewType(position: Int) = if (messageList[position].senderId.domainId() == currentUserId)
        MESSAGE_SELF_VIEW else MESSAGE_OTHER_VIEW

    inner class ViewHolder(itemView: View?) : RecyclerView.ViewHolder(itemView) {
        fun bindMessage(message: Message) {
            with(message) {
                if (senderId.domainId() == currentUserId) {
                    itemView?.selfMessageText?.text = textPayload
                } else {
                    itemView?.otherMessageText?.text = textPayload
                }
            }
        }
    }
}
```

{% endcode %}
{% endtab %}

{% tab title="Java" %}
{% code title="ChatRecyclerViewAdapter.java" %}

```java
public class ChatRecyclerViewAdapter extends RecyclerView.Adapter<ChatRecyclerViewAdapter.ViewHolder> {
    private List<Message> messageList;
    private String currentUserId;

    private int MESSAGE_SELF_VIEW = 0;
    private int MESSAGE_OTHER_VIEW = 1;

    public ChatRecyclerViewAdapter(
        List<Message> messageList,
        String currentUserId
    ) {
        this.messageList = messageList;
        this.currentUserId = currentUserId;
    }

    @NonNull
    @Override
    public ChatRecyclerViewAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        int layoutId;

        if (viewType == MESSAGE_SELF_VIEW) {
            layoutId = R.layout.item_message_self;
        } else {
            layoutId = R.layout.item_message_other;
        }

        View itemView = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
        return new ViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(@NonNull ChatRecyclerViewAdapter.ViewHolder holder, int position) {
        Message message = messageList.get(position);

        if (message.getSenderId().domainId().equals(currentUserId)) {
            holder.selfMessageText.setText(message.getTextPayload());
        } else {
            holder.otherMessageText.setText(message.getTextPayload());
        }
    }

    @Override
    public int getItemCount() {
        return messageList != null ? messageList.size() : 0;
    }

    @Override
    public int getItemViewType(int position) {
        if (messageList.get(position).getSenderId().domainId().equals(currentUserId)) {
            return MESSAGE_SELF_VIEW;
        } else {
            return MESSAGE_OTHER_VIEW;
        }
    }

    class ViewHolder extends RecyclerView.ViewHolder {
        private TextView selfMessageText;
        private TextView otherMessageText;

        public ViewHolder(View itemView) {
            super(itemView);

            selfMessageText = (TextView) itemView.findViewById(R.id.selfMessageText);
            otherMessageText = (TextView) itemView.findViewById(R.id.otherMessageText);
        }
    }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

Here, we receive a list of `Message` objects to display the chat items, and compare the `senderId` field to the `currentUserId` field to decide whether the bubble should render on the right or on the left.

## Render messages in the window

The final step to rendering the messages in a channel to the screen is to wire up the `ChatRecyclerViewAdapter` that you created to the `RecyclerView` that you had already added to your layout.

Get started by initialising an empty list for holding the incoming `Message` objects and setting a layout manager for your `RecyclerView`.

{% tabs %}
{% tab title="Kotlin" %}
{% code title="MainActivity.kt" %}

```kotlin
class MainActivity : AppCompatActivity() {

    private lateinit var mitter: Mitter
    private val channelId: String = "6dedfac5-8060-4ad3-8d69-20a72fb86899"

    private val messageList = mutableListOf<Message>()
    private lateinit var chatRecyclerViewAdapter: ChatRecyclerViewAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        mitter = (application as MyApp).mitter

        val users = mitter.Users()
        val channels = mitter.Channels()
        val messaging = mitter.Messaging()

        chatRecyclerView.layoutManager = LinearLayoutManager(this)
    }
}
```

{% endcode %}
{% endtab %}

{% tab title="Java" %}
{% code title="MainActivity.java" %}

```java
public class MainActivity extends AppCompatActivity {
    private Mitter mitter;
    private String channelId = "6dedfac5-8060-4ad3-8d69-20a72fb86899";

    private RecyclerView chatRecyclerView;
    private List<Message> messageList = new ArrayList<>();
    private ChatRecyclerViewAdapter chatRecyclerViewAdapter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mitter = ((MyApp) getApplication()).mitter;

        Mitter.Users users = mitter.new Users();
        Mitter.Channels channels = mitter.new Channels();
        Mitter.Messaging messaging = mitter.new Messaging();

        chatRecyclerView = (RecyclerView) findViewById(R.id.chatRecyclerView);
        chatRecyclerView.setLayoutManager(new LinearLayoutManager(this));
    }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

Now, you need to make a call to fetch messages in the channel that you had already created.

If you’ve noticed, in the previous code snippet, the channel ID is already defined in the class. Replace the channel ID string with your actual channel ID over there.

Once that’s done, just make a call to the `getMessagesInChannel()` method on the `Messaging` object to get a list of messages in the channel:

{% tabs %}
{% tab title="Kotlin" %}
{% code title="MainActivity.kt" %}

```kotlin
messaging.getMessagesInChannel(
    channelId = channelId,
    onValueAvailableCallback = object : Mitter.OnValueAvailableCallback<List<Message>> {
        override fun onError(apiError: ApiError) {
            Log.d("MSA", "Error in getting messages")
        }

        override fun onValueAvailable(value: List<Message>) {
            messageList.addAll(value)
            chatRecyclerViewAdapter = ChatRecyclerViewAdapter(
                messageList = messageList,
                currentUserId = mitter.getUserId()
            )

            chatRecyclerView?.adapter = chatRecyclerViewAdapter
        }
    }
)
```

{% endcode %}
{% endtab %}

{% tab title="Java" %}
{% code title="MainActivity.java" %}

```java
messaging.getMessagesInChannel(
    channelId,
    new FetchMessageConfig(),
    new Mitter.OnValueAvailableCallback<List<Message>>() {
        @Override
        public void onValueAvailable(List<Message> messages) {
            messageList.addAll(messages);
            chatRecyclerViewAdapter = new ChatRecyclerViewAdapter(
                messageList,
                mitter.getUserId()
            );

            chatRecyclerView.setAdapter(chatRecyclerViewAdapter);
        }

        @Override
        public void onError(ApiError apiError) {
            Log.d("MSA", "Error in getting messages");
        }
    }
);
```

{% endcode %}
{% endtab %}
{% endtabs %}

Here, we add the total incoming message list to our already defined empty message list. Next, we hook up that list with our `ChatRecyclerViewAdapter` and also retrieve the currently logged-in user ID and pass it to the adapter for the bubble alignment that we discussed previously.

The final step is to assign our `ChatRecyclerViewAdapter` object as the `RecyclerView` adapter to render the elements on the screen.

If you open up your app right now, it’ll display a blank screen because you haven’t sent any messages yet.

![Basic chat window layout](/files/-LN1bpnlo2zdcqecEgkd)

Let’s do that now.

## Send a basic text message

We’ve already added a basic `EditText` and a `Button` to our app while defining the layouts. Let’s connect them in the activity to send the typed text on the press of the **Send** button.

{% tabs %}
{% tab title="Kotlin" %}
{% code title="MainActivity.kt" %}

```kotlin
sendButton.setOnClickListener {
    messaging.sendTextMessage(
        channelId = channelId,
        message = inputMessage?.text.toString(),
        onValueUpdatedCallback = object : Mitter.OnValueUpdatedCallback {
            override fun onError(apiError: ApiError) {}

            override fun onSuccess() {
                inputMessage?.text?.clear()
            }
        }
    )
}
```

{% endcode %}
{% endtab %}

{% tab title="Java" %}
{% code title="MainActivity.java" %}

```java
sendButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        messaging.sendTextMessage(
            channelId,
            inputMessage.getText().toString(),
            new AppliedAclList(
                new ArrayList<AppliedAcl>(),
                new ArrayList<AppliedAcl>()
            ),
            new Mitter.OnValueUpdatedCallback() {
                @Override
                public void onSuccess() {
                    inputMessage.getText().clear();
                }

                @Override
                public void onError(ApiError apiError) { }
            }
        );
    }
});
```

{% endcode %}
{% endtab %}
{% endtabs %}

Here, we’re listening to the click events on the **Send** button and sending a message by calling the `sendTextMessage()` method on the `Messaging` object. We pass the typed text to the method as the message text.

After the message has been sent successfully, we clear the input area. You can also show a progress bar while sending the message by utilising this callback.

That’s all wired in. You can test if this works by typing something in the input field and hitting **Send**.

Do note that you won’t see the message appear on the screen even after it’s sent successfully. This is because we haven’t hooked our push message listener with the UI.

We’ll do this in the next section. For now, after sending a message, just close and reopen the app to see the message populated on the screen.

![Messages in the channel being populated in the chat window](/files/-LN1d_wo4b3ljmR-3ov6)

## Hook push messages with the UI

You can choose any way you want to pass around data from your `Application` class to your `MainActivity`. For this tutorial, we’ll stick to an event bus to do our job.

We’ll use [Greenrobot’s EventBus 3](https://github.com/greenrobot/EventBus) for this project. It’s pretty easy to use, while being reliable. Add the library to your project by including this line in your `build.gradle`:

{% code title="build.gradle" %}

```groovy
implementation 'org.greenrobot:eventbus:3.1.1'
```

{% endcode %}

Once that’s done, add a subscribing method in your `MainActivity` to listen to the incoming messages:

{% tabs %}
{% tab title="Kotlin" %}
{% code title="MainActivity.kt" %}

```kotlin
@Subscribe(threadMode = ThreadMode.MAIN)
fun onNewMessage(message: Message) {
    messageList.add(message)
    chatRecyclerViewAdapter.notifyItemInserted(messageList.size - 1)
}
```

{% endcode %}
{% endtab %}

{% tab title="Java" %}
{% code title="MainActivity.java" %}

```java
@Subscribe(threadMode = ThreadMode.MAIN)
public void onNewMessage(Message message) {
    messageList.add(message);
    chatRecyclerViewAdapter.notifyItemInserted(messageList.size() - 1);
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

After that, you need to register your `MainActivity` to listen to any event bus events. Just modify your `onCreate()` to include this code:

{% tabs %}
{% tab title="Kotlin" %}
{% code title="MainActivity.kt" %}

```kotlin
EventBus.getDefault().register(this)
```

{% endcode %}
{% endtab %}

{% tab title="Java" %}
{% code title="MainActivity.java" %}

```java
EventBus.getDefault().register(this);
```

{% endcode %}
{% endtab %}
{% endtabs %}

Then, override the `onDestroy()` method to clean up any registered listeners:

{% tabs %}
{% tab title="Kotlin" %}
{% code title="MainActivity.kt" %}

```kotlin
override fun onDestroy() {
    super.onDestroy()

    if (EventBus.getDefault().isRegistered(this)) {
        EventBus.getDefault().unregister(this)
    }
}
```

{% endcode %}
{% endtab %}

{% tab title="Java" %}
{% code title="MainActivity.java" %}

```java
@Override
protected void onDestroy() {
    super.onDestroy();

    if (EventBus.getDefault().isRegistered(this)) {
        EventBus.getDefault().unregister(this);
    }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

Finally, navigate to your custom `Application` class, locate the previously registered push message listener and modify it to this:

{% tabs %}
{% tab title="Kotlin" %}
{% code title="MyApp.kt" %}

```kotlin
mitter.registerOnPushMessageReceivedListener(object : Mitter.OnPushMessageReceivedCallback {
    override fun onChannelStreamData(
        channelId: String,
        streamId: String,
        streamData: ContextFreeMessage
    ) {}

    override fun onNewChannel(channel: Channel) {}

    override fun onNewChannelTimelineEvent(
        channelId: String,
        timelineEvent: TimelineEvent
    ) {}

    override fun onNewMessage(
        channelId: String,
        message: Message
    ) {
        //Send the incoming message to the registered listener
        EventBus.getDefault().post(message)
    }

    override fun onNewMessageTimelineEvent(
        messageId: String,
        timelineEvent: TimelineEvent
    ) {}

    override fun onParticipationChangedEvent(
        channelId: String,
        participantId: String,
        newStatus: ParticipationStatus,
        oldStatus: ParticipationStatus?
    ) {}
})
```

{% endcode %}
{% endtab %}

{% tab title="Java" %}
{% code title="MyApp.java" %}

```java
mitter.registerOnPushMessageReceivedListener(new Mitter.OnPushMessageReceivedCallback() {
    @Override
    public void onNewMessage(
        String channelId,
        Message message
    ) {
        //Send the incoming message to the registered listener
        EventBus.getDefault().post(message);
    }

    @Override
    public void onNewChannel(Channel channel) { }

    @Override
    public void onNewMessageTimelineEvent(
        String messageId,
        TimelineEvent timelineEvent
    ) { }

    @Override
    public void onNewChannelTimelineEvent(
        String channelId,
        TimelineEvent timelineEvent
    ) { }

    @Override
    public void onParticipationChangedEvent(
        String channelId, String participantId,
        ParticipationStatus participationStatus,
        ParticipationStatus participationStatus1
    ) { }

    @Override
    public void onChannelStreamData(
        String channelId,
        String streamId,
        ContextFreeMessage contextFreeMessage
    ) { }
});
```

{% endcode %}
{% endtab %}
{% endtabs %}

If you open up your app now and send a text message, you should be able to see it added to the list as soon as the message is sent.

![Messages are being transferred in and out the app in real-time](/files/-LN1h74b8UEKWkyJru_v)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.mitter.io/getting-started/build-your-first-android-app/start-a-basic-chat.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
