用环信实现基本的聊天功能:
1、先到官网下载官方的demo:http://www.easemob.com/download/im
2、新建一个工程,然后将下面几个文件加到libs 里面,没有这个文件的可以在app下新建一个。
3、配置信息
在清单文件 AndroidManifest.xml 里加入以下权限,以及写上你注册的 AppKey。
新建一个MyApplication文件并继承application 然后配置信息初始化
public class MyApplication extends Application {
// 上下文菜单
private Context mContext;
// 记录是否已经初始化
private boolean isInit = false;
@Override
public void onCreate() {
super.onCreate();
mContext = this;
initEasemob();
}
private void initEasemob() {
// 获取当前进程 id 并取得进程名
int pid = android.os.Process.myPid();
String processAppName = getAppName(pid);
/**
* 如果app启用了远程的service,此application:onCreate会被调用2次
* 为了防止环信SDK被初始化2次,加此判断会保证SDK被初始化1次
* 默认的app会在以包名为默认的process name下运行,如果查到的process name不是app的process name就立即返回
*/
if (processAppName == null || !processAppName.equalsIgnoreCase(mContext.getPackageName())) {
// 则此application的onCreate 是被service 调用的,直接返回
return;
}
if (isInit) {
return;
}
// 调用初始化方法初始化sdk
EMClient.getInstance().init(mContext, initOptions());
// 设置开启debug模式
EMClient.getInstance().setDebugMode(true);
// 设置初始化已经完成
isInit = true;
}
/**
* SDK初始化的一些配置
* 关于 EMOptions 可以参考官方的 API 文档
* http://www.easemob.com/apidoc/android/chat3.0/classcom_1_1hyphenate_1_1chat_1_1_e_m_options.html
*/
private EMOptions initOptions() {
EMOptions options = new EMOptions();
// 设置Appkey,如果配置文件已经配置,这里可以不用设置
// options.setAppKey("lzan13#hxsdkdemo");
// 设置自动登录
/**
* 自动登录在以下几种情况下会被取消:
用户调用了 SDK 的登出动作;
用户在别的设备上更改了密码,导致此设备上自动登录失败;
用户的账号被从服务器端删除;
用户从另一个设备登录,把当前设备上登录的用户踢出。
*/
options.setAutoLogin(true);
// 设置是否需要发送已读回执
options.setRequireAck(true);
// 设置是否需要发送回执,
options.setRequireDeliveryAck(true);
// 设置是否需要服务器收到消息确认
options.setRequireServerAck(true);
// 设置是否根据服务器时间排序,默认是true
options.setSortMessageByServerTime(false);
// 收到好友申请是否自动同意,如果是自动同意就不会收到好友请求的回调,因为sdk会自动处理,默认为true
options.setAcceptInvitationAlways(false);
// 设置是否自动接收加群邀请,如果设置了当收到群邀请会自动同意加入
options.setAutoAcceptGroupInvitation(false);
// 设置(主动或被动)退出群组时,是否删除群聊聊天记录
options.setDeleteMessagesAsExitGroup(false);
// 设置是否允许聊天室的Owner 离开并删除聊天室的会话
options.allowChatroomOwnerLeave(true);
// 设置google GCM推送id,国内可以不用设置
// options.setGCMNumber(MLConstants.ML_GCM_NUMBER);
// 设置集成小米推送的appid和appkey
// options.setMipushConfig(MLConstants.ML_MI_APP_ID, MLConstants.ML_MI_APP_KEY);
return options;
}
/**
* 根据Pid获取当前进程的名字,一般就是当前app的包名
*
* @param pid 进程的id
* @return 返回进程的名字
*/
private String getAppName(int pid) {
String processName = null;
ActivityManager activityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
List list = activityManager.getRunningAppProcesses();
Iterator i = list.iterator();
while (i.hasNext()) {
ActivityManager.RunningAppProcessInfo info = (ActivityManager.RunningAppProcessInfo) (i.next());
try {
if (info.pid == pid) {
// 根据进程的信息获取当前进程的名字
processName = info.processName;
// 返回当前进程名
return processName;
}
} catch (Exception e) {
e.printStackTrace();
}
}
// 没有匹配的项,返回为null
return null;
}
}
4、实现注册
注册模式分两种,开放注册和授权注册。可以登录环信管理后台,在“应用概况”页,切换注册模式。
注册用户名会自动转为小写字母,所以建议用户名均以小写注册(强烈建议开发者通过后台调用 REST API 去注册环信 ID,客户端注册方法不提倡使用)。
new Thread(new Runnable() {
public void run() {
try {
// 调用sdk注册方法
EMChatManager.getInstance().createAccountOnServer(username, pwd);
} catch (final EaseMobException e) {
//注册失败
int errorCode=e.getErrorCode();
if(errorCode==EMError.NONETWORK_ERROR){
Toast.makeText(getApplicationContext(), "网络异常,请检查网络!", Toast.LENGTH_SHORT).show();
}else if(errorCode==EMError.USER_ALREADY_EXISTS){
Toast.makeText(getApplicationContext(), "用户已存在!", Toast.LENGTH_SHORT).show();
}else if(errorCode==EMError.UNAUTHORIZED){
Toast.makeText(getApplicationContext(), "注册失败,无权限!", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(getApplicationContext(), "注册失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}).start();
5、登陆实现
登录成功后需要调用 EMGroupManager.getInstance().loadAllGroups();
和 EMChatManager.getInstance().loadAllConversations();
。
以上两个方法是为了保证进入主页面后本地会话和群组都 load 完毕。
另外如果登录过,APP 长期在后台再进的时候也可能会导致加载到内存的群组和会话为空,可以在主页面的 oncreate 里也加上这两句代码,当然,更好的办法应该是放在程序的开屏页
EMChatManager.getInstance().login(userName,password,new EMCallBack() {//回调
@Override
public void onSuccess() {
runOnUiThread(new Runnable() {
public void run() {
EMGroupManager.getInstance().loadAllGroups();
EMChatManager.getInstance().loadAllConversations();
Log.d("main", "登录聊天服务器成功!");
}
});
}
@Override
public void onProgress(int progress, String status) {
}
@Override
public void onError(int code, String message) {
Log.d("main", "登录聊天服务器失败!");
}
});
完整代码:布局主要就是加两个输入框和两个按钮,并详细了错误的信息,具体错误可以到下面网址查看:http://www.easemob.com/apidoc/android/chat3.0/classcom_1_1hyphenate_1_1_e_m_error.html#a09893124e1fbcd100a9583a4293957af
public class Login extends AppCompatActivity {
// 弹出框
private ProgressDialog mDialog;
// username 输入框
private EditText mUsernameEdit;
// 密码输入框
private EditText mPasswordEdit;
// 注册按钮
private Button mSignUpBtn;
// 登录按钮
private Button mSignInBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
initView();
}
/**
* 初始化界面控件
*/
private void initView() {
mUsernameEdit = (EditText) findViewById(R.id.ec_edit_username);
mPasswordEdit = (EditText) findViewById(R.id.ec_edit_password);
mSignUpBtn = (Button) findViewById(R.id.ec_btn_sign_up);
mSignUpBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
signUp();//注册
}
});
mSignInBtn = (Button) findViewById(R.id.ec_btn_sign_in);
mSignInBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
signIn();//登陆
}
});
}
/**
* 注册方法
*/
private void signUp() {
// 注册是耗时过程,所以要显示一个dialog来提示下用户
mDialog = new ProgressDialog(this);
mDialog.setMessage("注册中,请稍后...");
mDialog.show();
new Thread(new Runnable() {
@Override
public void run() {
try {
String username = mUsernameEdit.getText().toString().trim();
String password = mPasswordEdit.getText().toString().trim();
EMClient.getInstance().createAccount(username, password);
runOnUiThread(new Runnable() {
@Override
public void run() {
if (!Login.this.isFinishing()) {
mDialog.dismiss();
}
Toast.makeText(Login.this, "注册成功", Toast.LENGTH_LONG).show();
}
});
} catch (final HyphenateException e) {
e.printStackTrace();
runOnUiThread(new Runnable() {
@Override
public void run() {
if (!Login.this.isFinishing()) {
mDialog.dismiss();
}
/**
* 关于错误码可以参考官方api详细说明
* http://www.easemob.com/apidoc/android/chat3.0/classcom_1_1hyphenate_1_1_e_m_error.html
*/
int errorCode = e.getErrorCode();
String message = e.getMessage();
Log.d("lzan13", String.format("sign up - errorCode:%d, errorMsg:%s", errorCode, e.getMessage()));
switch (errorCode) {
// 网络错误
case EMError.NETWORK_ERROR:
Toast.makeText(Login.this, "网络错误 code: " + errorCode + ", message:" + message, Toast.LENGTH_LONG).show();
break;
// 用户已存在
case EMError.USER_ALREADY_EXIST:
Toast.makeText(Login.this, "用户已存在 code: " + errorCode + ", message:" + message, Toast.LENGTH_LONG).show();
break;
// 参数不合法,一般情况是username 使用了uuid导致,不能使用uuid注册
case EMError.USER_ILLEGAL_ARGUMENT:
Toast.makeText(Login.this, "参数不合法,一般情况是username 使用了uuid导致,不能使用uuid注册 code: " + errorCode + ", message:" + message, Toast.LENGTH_LONG).show();
break;
// 服务器未知错误
case EMError.SERVER_UNKNOWN_ERROR:
Toast.makeText(Login.this, "服务器未知错误 code: " + errorCode + ", message:" + message, Toast.LENGTH_LONG).show();
break;
case EMError.USER_REG_FAILED:
Toast.makeText(Login.this, "账户注册失败 code: " + errorCode + ", message:" + message, Toast.LENGTH_LONG).show();
break;
default:
Toast.makeText(Login.this, "ml_sign_up_failed code: " + errorCode + ", message:" + message, Toast.LENGTH_LONG).show();
break;
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
/**
* 登录方法
*/
private void signIn() {
mDialog = new ProgressDialog(this);
mDialog.setMessage("正在登陆,请稍后...");
mDialog.show();
String username = mUsernameEdit.getText().toString().trim();
String password = mPasswordEdit.getText().toString().trim();
if (TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) {
Toast.makeText(Login.this, "用户名和密码不能为空", Toast.LENGTH_LONG).show();
return;
}
// Intent intent = new Intent(Login.this, MainActivity.class);
// startActivity(intent);
// finish();
EMClient.getInstance().login(username, password, new EMCallBack() {
/**
* 登陆成功的回调
*/
@Override
public void onSuccess() {
runOnUiThread(new Runnable() {
@Override
public void run() {
mDialog.dismiss();
// 加载所有会话到内存
EMClient.getInstance().chatManager().loadAllConversations();
// 加载所有群组到内存,如果使用了群组的话
// EMClient.getInstance().groupManager().loadAllGroups();
// 登录成功跳转界面
Intent intent = new Intent(Login.this, MainActivity.class);
startActivity(intent);
finish();
}
});
}
/**
* 登陆错误的回调
* @param i
* @param s
*/
@Override
public void onError(final int i, final String s) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mDialog.dismiss();
Log.d("lzan13", "登录失败 Error code:" + i + ", message:" + s);
/**
* 关于错误码可以参考官方api详细说明
* http://www.easemob.com/apidoc/android/chat3.0/classcom_1_1hyphenate_1_1_e_m_error.html
*/
switch (i) {
// 网络异常 2
case EMError.NETWORK_ERROR:
Toast.makeText(Login.this, "网络错误 code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
break;
// 无效的用户名 101
case EMError.INVALID_USER_NAME:
Toast.makeText(Login.this, "无效的用户名 code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
break;
// 无效的密码 102
case EMError.INVALID_PASSWORD:
Toast.makeText(Login.this, "无效的密码 code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
break;
// 用户认证失败,用户名或密码错误 202
case EMError.USER_AUTHENTICATION_FAILED:
Toast.makeText(Login.this, "用户认证失败,用户名或密码错误 code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
break;
// 用户不存在 204
case EMError.USER_NOT_FOUND:
Toast.makeText(Login.this, "用户不存在 code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
break;
// 无法访问到服务器 300
case EMError.SERVER_NOT_REACHABLE:
Toast.makeText(Login.this, "无法访问到服务器 code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
break;
// 等待服务器响应超时 301
case EMError.SERVER_TIMEOUT:
Toast.makeText(Login.this, "等待服务器响应超时 code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
break;
// 服务器繁忙 302
case EMError.SERVER_BUSY:
Toast.makeText(Login.this, "服务器繁忙 code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
break;
// 未知 Server 异常 303 一般断网会出现这个错误
case EMError.SERVER_UNKNOWN_ERROR:
Toast.makeText(Login.this, "未知的服务器异常 code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
break;
default:
Toast.makeText(Login.this, "ml_sign_in_failed code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
break;
}
}
});
}
@Override
public void onProgress(int i, String s) {
}
});
}
6、自动登陆
即首次登录成功后,不需要再次调用登录方法,在下次 APP 启动时,SDK 会自动为您登录。并且如果您自动登录失败,也可以读取到之前的会话信息(以上情况是在未调用登出的情况下实现的)。
SDK 中自动登录属性默认是 true 打开的,如果不需要自动登录,在初始化 SDK 之前,调用 EMChat.getInstance().setAutoLogin(false);
设置为 false 关闭。
自动登录在以下几种情况下会被取消:
重连实现: 当掉线时,Android SDK 会自动重连,无需进行任何操作。
//注册一个监听连接状态的listener
EMChatManager.getInstance().addConnectionListener(new MyConnectionListener());
//实现ConnectionListener接口
private class MyConnectionListener implements EMConnectionListener {
@Override
public void onConnected() {
//已连接到服务器
}
@Override
public void onDisconnected(final int error) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if(error == EMError.USER_REMOVED){
// 显示帐号已经被移除
}else if (error == EMError.CONNECTION_CONFLICT) {
// 显示帐号在其他设备登录
} else {
if (NetUtils.hasNetwork(MainActivity.this))
//连接不到聊天服务器
else
//当前网络不可用,请检查网络设置
}
}
});
}
}
退出登录实现
/**
* 退出登陆
*/
private void setLogout(){
// EMClient.getInstance().logout(true);//同步方法
//异步方法
// 调用sdk的退出登录方法,第一个参数表示是否解绑推送的token,没有使用推送或者被踢都要传false
EMClient.getInstance().logout(false, new EMCallBack() {
@Override
public void onSuccess() {
Log.e("lzan13", "logout success");
// 调用退出成功,结束app
finish();
}
@Override
public void onError(int i, String s) {
Log.e("lzan13", "logout error " + i + " - " + s);
}
@Override
public void onProgress(int i, String s) {
}
});
}
完整代码:
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Button button;
private Button logout;
private EditText userName;
private final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 判断sdk是否登录成功过,并没有退出和被踢,否则跳转到登陆界面
if (!EMClient.getInstance().isLoggedInBefore()) {
Intent intent = new Intent(MainActivity.this, Login.class);
startActivity(intent);
finish();
return;
}
initView();
}
private void initView() {
button = (Button)findViewById(R.id.btn);
button.setOnClickListener(this);
logout = (Button)findViewById(R.id.logout);
logout.setOnClickListener(this);
userName = (EditText)findViewById(R.id.userName);
//注册一个监听连接状态的listener
EMClient.getInstance().addConnectionListener(new MyConnectionListener());
}
//实现ConnectionListener接口
private class MyConnectionListener implements EMConnectionListener {
@Override
public void onConnected() {
}
@Override
public void onDisconnected(final int error) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if(error == EMError.USER_REMOVED){
// 显示帐号已经被移除
}else if (error == EMError.USER_LOGIN_ANOTHER_DEVICE) {
// 显示帐号在其他设备登录
} else {
if (NetUtils.hasNetwork(MainActivity.this)){
Toast.makeText(getApplication(),"连接不到聊天服务器",Toast.LENGTH_SHORT).show();
Log.e(TAG,"连接不到聊天服务器");
//连接不到聊天服务器
} else{
Toast.makeText(getApplication(),"当前网络不可用,请检查网络设置",Toast.LENGTH_SHORT).show();
Log.e(TAG,"当前网络不可用,请检查网络设置");
//当前网络不可用,请检查网络设置
}
}
}
});
}
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.logout:
setLogout();
break;
case R.id.btn:
if (!userName.getText().toString().equals("")) {
Intent intent = new Intent(this, Chat.class);
intent.putExtra("userName", userName.getText().toString());
startActivity(intent);
}else {
Toast.makeText(getApplication(),"用户名不能为空!",Toast.LENGTH_SHORT).show();
}
break;
}
}
/**
* 退出登陆
*/
private void setLogout(){
// EMClient.getInstance().logout(true);//同步方法
//异步方法
// 调用sdk的退出登录方法,第一个参数表示是否解绑推送的token,没有使用推送或者被踢都要传false
EMClient.getInstance().logout(false, new EMCallBack() {
@Override
public void onSuccess() {
Log.e("lzan13", "logout success");
// 调用退出成功,结束app
finish();
}
@Override
public void onError(int i, String s) {
Log.e("lzan13", "logout error " + i + " - " + s);
}
@Override
public void onProgress(int i, String s) {
}
});
}
}
7、实现基本的聊天功能
布局代码
首先获取到从上一界面传递过来的用户id
Intent intent = getIntent();
userName = intent.getStringExtra("userName");
mMessageListener = this;
实现发送消息功能
private void sendMessage(){
String content = input_text.getText().toString();
//创建一条文本消息,content为消息文字内容,toChatUsername为对方用户或者群聊的id,后文皆是如此
EMMessage message = EMMessage.createTxtSendMessage(content, userName);
// text_content.setText(content);
text_content.setText(text_content.getText() + "\n"+ mConversation.getAllMessages().get(0).getFrom()+":"+ content + " - time: " + message.getMsgTime());
//如果是群聊,设置chattype,默认是单聊
// if (chatType == CHATTYPE_GROUP)
//message.setChatType(EMMessage.ChatType.GroupChat);
//发送消息
EMClient.getInstance().chatManager().sendMessage(message);
// 为消息设置回调
message.setMessageStatusCallback(new EMCallBack() {
@Override
public void onSuccess() {
// 消息发送成功,打印下日志,正常操作应该去刷新ui
Log.e(TAG, "send message on success");
}
@Override
public void onError(int i, String s) {
// 消息发送失败,打印下失败的信息,正常操作应该去刷新ui
Log.e(TAG, "send message on error " + i + " - " + s);
}
@Override
public void onProgress(int i, String s) {
// 消息发送进度,一般只有在发送图片和文件等消息才会有回调,txt不回调
}
});
}
接收消息,主要通过一个线程来接收并显示
/**
* 收到新消息
* @param messages
*/
@Override
public void onMessageReceived(List messages) {
//收到消息
// 循环遍历当前收到的消息
for (EMMessage message : messages) {
if (message.getFrom().equals(userName)) {
// 设置消息为已读
mConversation.markMessageAsRead(message.getMsgId());
// 因为消息监听回调这里是非ui线程,所以要用handler去更新ui
Message msg = mHandler.obtainMessage();
msg.what = 0;
msg.obj = message;
mHandler.sendMessage(msg);
} else {
// 如果消息不是当前会话的消息发送通知栏通知
}
}
}
/**
* 自定义实现Handler,主要用于刷新UI操作
*/
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
EMMessage message = (EMMessage) msg.obj;
// 这里只是简单的demo,也只是测试文字消息的收发,所以直接将body转为EMTextMessageBody去获取内容
EMTextMessageBody body = (EMTextMessageBody) message.getBody();
// 将新的消息内容和时间加入到下边
Log.e("nsc", body.getMessage());
//text_content.setText(body.getMessage());
text_content.setText(text_content.getText() + "\n"+mConversation.getAllMessages().get(0).getTo()+":" + body.getMessage() + " - time: " + message.getMsgTime());
break;
}
}
};
数据格式,即返回的数据格式
{
"callId":"",//每个回调的ID都不一样
"eventType":"chat_offline",//用于以后的扩展,现在只推送聊天消息(离线和所有),以后会加入更多,比如用户加入了某个群组
"timestamp":0,//环信接收到此消息的时间
"chat_type":"groupchat", // 群聊,如果是单聊则为"chat"
"group_id":'',//群聊时才有此参数
"from":"",//消息的发送方
"to":"",//消息的接收方
"msg_id":"",// 消息ID
"payload":{//消息,与通过REST API发送过来的一致
},
"securityVersion":"",//安全校验版本,目前为1.0.0。忽略此参数,以后会改成Console后台做设置
"security":""//签名。格式如下: MD5(callId+约定的key+timestamp),约定的key为123456,以后会改成Console后台做设置
}
完整代码
public class Chat extends AppCompatActivity implements View.OnClickListener,EMMessageListener{
private EditText input_text;
private Button send;
private TextView text_content;
private String userName;// 当前聊天的 ID
// 当前会话对象
private EMConversation mConversation;
// 消息监听器
private EMMessageListener mMessageListener;
private final String TAG = "Chat";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
Intent intent = getIntent();
userName = intent.getStringExtra("userName");
mMessageListener = this;
initView();
initConversation();
}
private void initView() {
input_text = (EditText)findViewById(R.id.input_text);
send = (Button)findViewById(R.id.send);
send.setOnClickListener(this);
text_content = (TextView)findViewById(R.id.text_content);
// 设置textview可滚动,需配合xml布局设置
text_content.setMovementMethod(new ScrollingMovementMethod());
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.send:
sendMessage();
break;
default:
break;
}
}
/**
* 初始化会话对象,并且根据需要加载更多消息
*/
private void initConversation() {
/**
* 初始化会话对象,这里有三个参数么,
* 第一个表示会话的当前聊天的 useranme 或者 groupid
* 第二个是绘画类型可以为空
* 第三个表示如果会话不存在是否创建
*/
mConversation = EMClient.getInstance().chatManager().getConversation(userName, null, true);
for (int i = 0; i 0) {
EMMessage messge = mConversation.getLastMessage();
// EMTextMessageBody body = (EMTextMessageBody) messge.getBody();
// 将消息内容和时间显示出来
//text_content.setText("聊天记录:" + body.getMessage() + " - time: " + mConversation.getLastMessage().getMsgTime());
}
}
/**
* 自定义实现Handler,主要用于刷新UI操作
*/
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
EMMessage message = (EMMessage) msg.obj;
// 这里只是简单的demo,也只是测试文字消息的收发,所以直接将body转为EMTextMessageBody去获取内容
EMTextMessageBody body = (EMTextMessageBody) message.getBody();
// 将新的消息内容和时间加入到下边
Log.e("nsc", body.getMessage());
//text_content.setText(body.getMessage());
text_content.setText(text_content.getText() + "\n"+mConversation.getAllMessages().get(0).getTo()+":" + body.getMessage() + " - time: " + message.getMsgTime());
break;
}
}
};
private void sendMessage(){
String content = input_text.getText().toString();
//创建一条文本消息,content为消息文字内容,toChatUsername为对方用户或者群聊的id,后文皆是如此
EMMessage message = EMMessage.createTxtSendMessage(content, userName);
// text_content.setText(content);
text_content.setText(text_content.getText() + "\n"+ mConversation.getAllMessages().get(0).getFrom()+":"+ content + " - time: " + message.getMsgTime());
//如果是群聊,设置chattype,默认是单聊
// if (chatType == CHATTYPE_GROUP)
//message.setChatType(EMMessage.ChatType.GroupChat);
//发送消息
EMClient.getInstance().chatManager().sendMessage(message);
// 为消息设置回调
message.setMessageStatusCallback(new EMCallBack() {
@Override
public void onSuccess() {
// 消息发送成功,打印下日志,正常操作应该去刷新ui
Log.e(TAG, "send message on success");
}
@Override
public void onError(int i, String s) {
// 消息发送失败,打印下失败的信息,正常操作应该去刷新ui
Log.e(TAG, "send message on error " + i + " - " + s);
}
@Override
public void onProgress(int i, String s) {
// 消息发送进度,一般只有在发送图片和文件等消息才会有回调,txt不回调
}
});
}
@Override
protected void onResume() {
super.onResume();
// 添加消息监听
EMClient.getInstance().chatManager().addMessageListener(mMessageListener);
}
@Override
protected void onStop() {
super.onStop();
// 移除消息监听
EMClient.getInstance().chatManager().removeMessageListener(mMessageListener);
}
/**
* 收到新消息
* @param messages
*/
@Override
public void onMessageReceived(List messages) {
//收到消息
// 循环遍历当前收到的消息
for (EMMessage message : messages) {
if (message.getFrom().equals(userName)) {
// 设置消息为已读
mConversation.markMessageAsRead(message.getMsgId());
// 因为消息监听回调这里是非ui线程,所以要用handler去更新ui
Message msg = mHandler.obtainMessage();
msg.what = 0;
msg.obj = message;
mHandler.sendMessage(msg);
} else {
// 如果消息不是当前会话的消息发送通知栏通知
}
}
}
/**
* 收到新的 CMD 消息
* @param list
*/
@Override
public void onCmdMessageReceived(List list) {
for (int i = 0; i < list.size(); i++) {
// 透传消息
EMMessage cmdMessage = list.get(i);
EMCmdMessageBody body = (EMCmdMessageBody) cmdMessage.getBody();
Log.e("nsc", body.action());
}
}
/**
* 收到新的已读回执
* @param list
*/
@Override
public void onMessageReadAckReceived(List list) {
}
/**
* 收到新的发送回执
* @param list
*/
@Override
public void onMessageDeliveryAckReceived(List list) {
}
/**
* 消息的状态改变
* @param emMessage
* @param o
*/
@Override
public void onMessageChanged(EMMessage emMessage, Object o) {
}
到此就可以实现基本的聊天了。代码下载地址: 点击打开链接