Chat em tempo real com NodeJs e Android - Parte 2
10 Jan 2016Continuando a criação do chat em tempo real, vamos ver como utilizar a biblioteca Socket.io no Android.
Implementando no Android
Como na primeira parte, já configuramos o servidor (em NodeJs) para receber as conexões dos sockets, vamos apenas implementar a parte do Android.
Se você não viu a primeira parte, clique aqui para ver. Lembrando que estarei assumindo que você já leu a primeira parte.
Preparando a Activity
Crie um novo projeto no Android Studio, com uma Activity em branco. Eu dei o nome de MainActivity no meu caso.
No layout, vamos colocar uma ListView para as mensagens, um EditText para digitar o texto e um Button para enviar os dados para o servidor. Então temos o seguinte XML:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
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=".MainActivity">
<ListView
android:id="@+id/lista_mensagens"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/layout_baixo"
android:layout_alignParentTop="true" />
<LinearLayout
android:id="@+id/layout_baixo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="horizontal">
<EditText
android:id="@+id/input_mensagem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.9" />
<Button
android:id="@+id/btn_enviar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.1"
android:text="Enviar" />
</LinearLayout>
</RelativeLayout>
Agora voltando para o código da Activity, vamos criar os objetos para cada controle:
package com.joaoretamero.socketiochat;
import android.support.v7.app.AppCompatActivity;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
public class MainActivity extends AppCompatActivity {
private EditText mInputMensagem;
private Button mBtnEnviar;
private ListView mListaMensagens;
private ArrayAdapter<String> mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mInputMensagem = (EditText) findViewById(R.id.input_mensagem);
mBtnEnviar = (Button) findViewById(R.id.btn_enviar);
mListaMensagens = (ListView) findViewById(R.id.lista_mensagens);
mAdapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1);
mListaMensagens.setAdapter(mAdapter);
mBtnEnviar.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// código para enviar os dados
}
});
}
}
O que fizemos até agora foi: obter todos os controles da Activity, criar um Adapter para nossa ListView e prepara o evento onClick do botão "Enviar".
Usando o Socket.io
Felizmente, o pessoal do Socket.io também fizeram uma versão para o Android, então podemos configurar o Gradle do projeto para resolver esta dependência. No seu arquivo build.gradle, adicione a seguinte linha no grupo "dependencies":
compile 'io.socket:socket.io-client:0.6.2'
O Android Studio irá solicitar para fazer a sincronização do Gradle, faça isto e aguarde um pouco.
Para que o Socket.io funcione corretamente, adicione no seu AndroidManifest.xml, a permissão para usar a internet:
<uses-permission android:name="android.permission.INTERNET" />
Antes de colocarmos o código na Activity, vamos ver como usar o Socket.io:
Socket socket = IO.socket("http://localhost:81");
// No método .on, definimos qualquer evento que desejarmos
// e vinculamos a um Emitter.Listener que será executado
// toda vez que recebermos um dado neste evento
socket.on("mensagem_cliente", new Emitter.Listener() {
@Override
public void call(final Object... args) {
// Código para tratar o dado recebido
// Apenas exemplo para enviar uma mensagem ao servidor
socket.emit("mensagem_servidor", "Olá servidor");
}
});
socket.connect();
Agora vamos colocá-lo na MainActivity, lembrando do evento onDestroy para desconectarmos o socket de forma segura.
package com.joaoretamero.socketiochat;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import java.net.URISyntaxException;
import io.socket.client.IO;
import io.socket.client.Socket;
import io.socket.emitter.Emitter;
public class MainActivity extends AppCompatActivity {
private EditText mInputMensagem;
private Button mBtnEnviar;
private ListView mListaMensagens;
private ArrayAdapter<String> mAdapter;
private Socket mSocket;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mInputMensagem = (EditText) findViewById(R.id.input_mensagem);
mBtnEnviar = (Button) findViewById(R.id.btn_enviar);
mListaMensagens = (ListView) findViewById(R.id.lista_mensagens);
mAdapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1);
mListaMensagens.setAdapter(mAdapter);
mBtnEnviar.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!mInputMensagem.getText().toString().equals("")) {
mSocket.emit("mensagem_servidor", mInputMensagem.getText());
mInputMensagem.setText("");
}
}
});
try {
mSocket = IO.socket("http://localhost:81");
} catch (URISyntaxException e) {
this.finish();
return;
}
mSocket.on("mensagem_cliente", new Emitter.Listener() {
@Override
public void call(final Object... args) {
if (args.length > 0) {
// Note a necessidade de usar o método runOnUiThread pois este código é
// executado numa thread separada, então precisamos rodar o código da UI
// na thread adequada
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
mAdapter.add((String) args[0]);
mAdapter.notifyDataSetChanged();
// Apenas faz um scroll para o novo item da lista
mListaMensagens.smoothScrollToPosition(mAdapter.getCount() - 1);
}
});
}
}
});
mSocket.connect();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mSocket != null)
mSocket.disconnect();
}
}
Feito isto, já pode executar o app (com o NodeJs já em execução) e brincar com o chat.
Você pode ver o projeto completo no repositório do GitHub.
Até mais.