> 文档中心 > 安卓集成腾讯即时通信IM完成聊天室功能

安卓集成腾讯即时通信IM完成聊天室功能

安卓集成腾讯即时通信IM完成聊天室功能

    • 没有效果图的文章都是扯淡
    • 请将下面的MainActivity的代码复制到源码里面,替换掉源码的MainActivity.class
    • 话不多说,下来上代码:
    • 以上就是所有的代码
    • 附上demo源码。
    • 源码:[源码请点这里](https://download.csdn.net/download/qq_35840038/12729429)
    • 如果有什么问题,欢迎大家指导。并相互联系,希望能够通过文章互相学习。

没有效果图的文章都是扯淡

延续我们的优良传统,先上效果图
效果图如下:
在这里插入图片描述
注意:需继承AppCompatActivity

请将下面的MainActivity的代码复制到源码里面,替换掉源码的MainActivity.class

这里我用了两个手机做测试,同样对照activity里面有两个userid和usersig。注意两个手机不能安装同一个userid的APP,否则会被挤下线

近期,由于项目需要,研究了一下腾讯的即时通信IM,完成了一个类似直播间聊天的功能。具体需求为当进入一个直播间时,可以发送并接收当前直播间的所有聊天消息,从而完成直播间聊天功能。

首先了解一下腾讯的即时通信IM(地址为:https://cloud.tencent.com/document/product/269)
在这里插入图片描述
注:我用的是无UI库的,聊天室用RecyclerView显示即可。

//这里列出即时通信IM的概要;
1.开发者后台注册拿到APPID和appkey(参考官方文档)
2.初始化并完成登录;
3.登录完成后修改个人资料(这一步是我在测试中发现的,如果不修改对方收到你发的消息后,昵称为null)
4.登录完成后加入一个直播间(需要直播间id和直播间名称–这是服务端返回的)
5.加入后监听接收消息回调并调用发送消息方法;
6.退出时先退出直播间,然后注销SDK初始化和SDK登录。

配置请参考demo

话不多说,下来上代码:

先看主界面xml:

                                      
注:这里的自定义CustomLinearLayout是为了解决点击输入框浮在键盘上顶部出现空白的问题

这个是recyclerview的item布局:

  
注:布局就这么一丢丢

下来给出自定义的布局和消息存储的实体类

package com.edu.im_demo;import android.content.Context;import android.graphics.Rect;import android.os.Build;import android.util.AttributeSet;import android.view.WindowInsets;import android.widget.LinearLayout;import androidx.annotation.RequiresApi;public class CustomLinearLayout extends LinearLayout {    public CustomLinearLayout(Context context) { super(context);    }    public CustomLinearLayout(Context context, AttributeSet attrs) { super(context, attrs);    }    public CustomLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr);    }    public CustomLinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes);    }    @Override    protected boolean fitSystemWindows(Rect insets) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {     insets.left = 0;     insets.top = 0;     insets.right = 0; } return super.fitSystemWindows(insets);    }    @RequiresApi(api = Build.VERSION_CODES.KITKAT_WATCH)    @Override    public WindowInsets onApplyWindowInsets(WindowInsets insets) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {     return super.onApplyWindowInsets(insets.replaceSystemWindowInsets(0, 0, 0, insets.getSystemWindowInsetBottom())); } else {     return insets; }    }}
注:主界面布局中使用

实体类

package com.edu.im_demo;public class ChatMsgBean {    private String nickname;    private String content;    public ChatMsgBean(){}    public ChatMsgBean(String nickname, String content) { this.nickname = nickname; this.content = content;    }    public String getNickname() { return nickname;    }    public void setNickname(String nickname) { this.nickname = nickname;    }    public String getContent() { return content;    }    public void setContent(String content) { this.content = content;    }}
注:接收消息发出的类

下来给出适配器

package com.edu.im_demo;import android.app.Activity;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.TextView;import androidx.recyclerview.widget.RecyclerView;import com.orz.nb.plus.emojiview.EmojiUtils;import java.util.List;/ * 聊天室 */public class ChatMsgAdapter extends RecyclerView.Adapter {    / 上下文 */    Activity context;    / 数据源 */    List data;    / 控件 */    LayoutInflater inflater;    /     * 这里的data作为数据源从activity传入     * @param activity     * @param datas     */    public ChatMsgAdapter(Activity activity, List datas){ this.context = activity; this.data = datas; //获取布局 inflater = LayoutInflater.from(activity);    }    /     * 加载布局,相当于activity的onCreate方法     * @param parent     * @param viewType     * @return     */    @Override    public ChatMsgAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.chit_item, parent, false); return new ChatMsgAdapter.ViewHolder(view);    }    /     * 绑定数据     * @param viewHolder     * @param position     */    @Override    public void onBindViewHolder(final ChatMsgAdapter.ViewHolder viewHolder, int position) { viewHolder.chat_item_nickname.setText(data.get(position).getNickname() + ":");// viewHolder.chat_item_content.setText(data.get(position).getContent()); EmojiUtils.showEmoji(viewHolder.chat_item_content, data.get(position).getContent());    }    /     * 数据源的内容大小     * @return     */    @Override    public int getItemCount() { return data.size();    }    public void refresh() { notifyDataSetChanged();    }    /     * //自定义的ViewHolder,持有每个Item的的所有界面元素     */    public class ViewHolder extends RecyclerView.ViewHolder { private TextView chat_item_nickname, chat_item_content; public ViewHolder(View rootView) {     super(rootView);     chat_item_nickname = rootView.findViewById(R.id.chat_item_nickname);     chat_item_content = rootView.findViewById(R.id.chat_item_content); }    }}

我自己写的IM管理类

package com.edu.im_demo;import android.content.Context;import android.text.TextUtils;import androidx.annotation.NonNull;import com.tencent.imsdk.v2.V2TIMCallback;import com.tencent.imsdk.v2.V2TIMManager;import com.tencent.imsdk.v2.V2TIMMessage;import com.tencent.imsdk.v2.V2TIMSDKConfig;import com.tencent.imsdk.v2.V2TIMSDKListener;import com.tencent.imsdk.v2.V2TIMSimpleMsgListener;import com.tencent.imsdk.v2.V2TIMValueCallback;/ * 这是我整合的IM的管理类 */public class IMManager {    /     * 是否已经登录到 im 服务器     *     * 用户已经处于已登录和登录中状态,则认为用户已经登录,无需在进行登录     */    public static boolean isLoginIMService(){ int loginStatus = V2TIMManager.getInstance().getLoginStatus(); return loginStatus == V2TIMManager.V2TIM_STATUS_LOGINED ||  loginStatus == V2TIMManager.V2TIM_STATUS_LOGINING;    }    /     * 用户登录到IM服务器     *     * @param userID    用户编号     * @param userSig   用户签名     * @param callback  登录成功与否回调     */    public static void login(String userID, String userSig, V2TIMCallback callback) { if (isLoginIMService()) {     callback.onSuccess();     return; } V2TIMManager.getInstance().login(userID, userSig, callback);    }    /     * 初始化 IM 连接腾讯服务器     *     * @param context 上下文对象     * @param imSDKConfig    imSdk配置     * @param listener连接腾讯服务器回调     */    public static void initConnectTXService(     Context context,     int imSdkAppId,     V2TIMSDKConfig imSDKConfig,     V2TIMSDKListener listener    ) { V2TIMManager.getInstance()  .initSDK(context, imSdkAppId, imSDKConfig, listener);    }    /     * 创建一个直播聊天室     *     * @param groupType  群类型(V2TIMManager.GROUP_TYPE_AVCHATROOM)     * 

* "Work" :工作群 * "Public" :公开群 * "Meeting" :会议群 * "AVChatRoom" :直播群 *

* * @param groupId 聊天室 id * @param groupName 聊天室名称 * @param callback 创建状态回调 */ public static void createLiveRoom( String groupType, String groupId, @NonNull String groupName, V2TIMValueCallback callback ) { V2TIMManager.getInstance().createGroup(groupType, groupId, groupName, callback); } / * 加入到某一个直播间 IM * * @param groupId 聊天室 id * @param listener 是否成功接入回调 */ public static void joinToLiveRoom(String groupId, String msg, V2TIMCallback listener) { V2TIMManager.getInstance().joinGroup(groupId, msg, listener); } / * 退出直播直播间 * * @param groupId 聊天室 id */ public static void exitLiveRoom(String groupId) { V2TIMManager.getInstance().quitGroup(groupId, null); } / * 发送纯文本消息到聊天群组 * @param msg 发送的聊天内容 * @param groupId 聊天室 ID * @param priority 发送消息的优先级 (V2TIMMessage.V2TIM_PRIORITY_NORMAL) *

* V2TIMMessage.V2TIM_PRIORITY_HIGH:云端会优先传输,适用于在群里发送重要消息,比如主播发送的文本消息等。 * V2TIMMessage.V2TIM_PRIORITY_NORMAL:云端按默认优先级传输,适用于在群里发送非重要消息,比如观众发送的弹幕消息等。 *

* @param callback 发送状态回调 */ public static void sendTextMsg( String msg, String groupId, int priority, V2TIMValueCallback callback ) { V2TIMManager.getInstance().sendGroupTextMessage( msg, groupId, priority, callback ); } / * 发送单聊普通文本消息 */ public static void sendC2CTextMsg(String msg, String userID, V2TIMValueCallback callback) { V2TIMManager.getInstance().sendC2CTextMessage(msg, userID, callback); } / * 接受消息 */ public static void receiveMsg(V2TIMSimpleMsgListener callback) { V2TIMManager.getInstance().addSimpleMsgListener(callback); } / * 解散聊天室 */ public static void dismissGroup(String groupId) { if (TextUtils.isEmpty(groupId)) { V2TIMManager.getInstance().dismissGroup(groupId, null); } } / * 用户退出 im 登录 */ public static void userLogout() { V2TIMManager.getInstance().logout(null); } / * 登出账号并注销 im sdk */ public static void unInitIMSDk() { userLogout(); V2TIMManager.getInstance().unInitSDK(); }}

重中之重主界面MainActivity来啦

package com.edu.im_demo;import android.app.Activity;import android.content.Context;import android.os.Bundle;import android.util.Log;import android.view.KeyEvent;import android.view.View;import android.view.inputmethod.EditorInfo;import android.view.inputmethod.InputMethodManager;import android.widget.EditText;import android.widget.ImageView;import android.widget.TextView;import android.widget.Toast;import androidx.appcompat.app.AppCompatActivity;import androidx.recyclerview.widget.LinearLayoutManager;import androidx.recyclerview.widget.RecyclerView;import com.orz.nb.plus.emojiview.EmojiView;import com.tencent.imsdk.v2.V2TIMCallback;import com.tencent.imsdk.v2.V2TIMGroupMemberInfo;import com.tencent.imsdk.v2.V2TIMManager;import com.tencent.imsdk.v2.V2TIMMessage;import com.tencent.imsdk.v2.V2TIMSDKConfig;import com.tencent.imsdk.v2.V2TIMSDKListener;import com.tencent.imsdk.v2.V2TIMSimpleMsgListener;import com.tencent.imsdk.v2.V2TIMUserFullInfo;import com.tencent.imsdk.v2.V2TIMValueCallback;import java.util.ArrayList;import java.util.List;/ * 腾讯IM完成聊天室 * 直接运行即可 */public class MainActivity extends AppCompatActivity {    private Activity mActivity = MainActivity.this;    //IM测试的账号数据    private int IMSDKAPPID = 1400415921;    private String ROOMID = "@TGS#aDGNB5UG3";    private String ROOMNAME = "测试";    //控件    RecyclerView chat_rv;    EditText send_msg;    ImageView chat_img_emojy;    EmojiView emoji_view;    List lists;    ChatMsgAdapter chatMsgAdapter;    /     * 隐藏键盘     */    private void hintKbOne() { InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); View v = getWindow().peekDecorView(); if (null != v) {     imm.hideSoftInputFromWindow(v.getWindowToken(), 0); }    }    @Override    protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); chat_rv = findViewById(R.id.chat_rv); chat_img_emojy = findViewById(R.id.chat_img_emojy); send_msg = findViewById(R.id.send_msg); emoji_view = findViewById(R.id.emoji_view); //绑定表情 emoji_view.setTarget(send_msg); chat_img_emojy.setOnClickListener(new View.OnClickListener() {     @Override     public void onClick(View v) {  emoji_view.setVisibility(View.VISIBLE);  hintKbOne();  send_msg.clearFocus();     } }); send_msg.setOnFocusChangeListener(new android.view.View.  OnFocusChangeListener() {     @Override     public void onFocusChange(View v, boolean hasFocus) {  if (hasFocus) {      emoji_view.setVisibility(View.GONE);  }else{  }     } }); //初始化rv initRecyclerView(); //发送消息 send_msg.setOnEditorActionListener(new TextView.OnEditorActionListener() {     @Override     public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {  if (actionId == EditorInfo.IME_ACTION_SEND) {      if(send_msg.getText().toString().trim().length() == 0){   Toast.makeText(mActivity, "说点什么吧", Toast.LENGTH_SHORT).show();   return true;      }      hintKbOne();      sendMessage(send_msg.getText().toString());      //清空      send_msg.setText("");      return true;  }  return false;     } }); //腾讯IM实现初始化 init(); //接收消息 getMessage();    }    /     * 接收消息     */    private void getMessage() { //接收消息 IMManager.receiveMsg(new V2TIMSimpleMsgListener() {     @Override     public void onRecvGroupTextMessage(String msgID, String groupID, V2TIMGroupMemberInfo sender, String text) {  super.onRecvGroupTextMessage(msgID, groupID, sender, text);  Log.i("腾讯云即时通信IM", "接收成功" + sender.toString());  addMessage(sender.getNickName(), text);     } });    }    /     * IM初始化     */    private void init() { //腾讯云IM V2TIMSDKConfig config = new V2TIMSDKConfig(); // 3. 指定 log 输出级别,详情请参考 SDKConfig。 config.setLogLevel(V2TIMSDKConfig.V2TIM_LOG_INFO); // 4. 初始化 SDK 并设置 V2TIMSDKListener 的监听对象。 IMManager.initConnectTXService(mActivity, IMSDKAPPID, config, new V2TIMSDKListener() {     @Override     public void onConnecting() {  super.onConnecting();  Log.i("腾讯云即时通信IM", "正在连接腾讯云服务器");     }     @Override     public void onConnectSuccess() {  super.onConnectSuccess();  Log.i("腾讯云即时通信IM", "连接腾讯云服务器成功");  if(IMManager.isLoginIMService()){      joinRoom();  }else{      IMManager.userLogout();      login();  }     }     @Override     public void onConnectFailed(int code, String error) {  super.onConnectFailed(code, error);  Log.i("腾讯云即时通信IM", "连接腾讯云服务器失败");     }     @Override     public void onKickedOffline() {  super.onKickedOffline();  Log.i("腾讯云即时通信IM", "当前用户被踢下线");  login();     }     @Override     public void onUserSigExpired() {  super.onUserSigExpired();  Log.i("腾讯云即时通信IM", "登录票据已经过期");  login();     } });    }    /     * 实例化RecyclerView     */    public void initRecyclerView() { lists = new ArrayList(); chatMsgAdapter = new ChatMsgAdapter(mActivity, lists); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(mActivity); linearLayoutManager.setStackFromEnd(true); linearLayoutManager.scrollToPositionWithOffset(chatMsgAdapter.getItemCount() - 1, Integer.MIN_VALUE); chat_rv.setLayoutManager(linearLayoutManager); chat_rv.setAdapter(chatMsgAdapter);    }//    final String UserID = "23";//    final String UserSig = "eJyrVgrxCdYrSy1SslIy0jNQ0gHzM1NS80oy0zIhwsZQ0eKU7MSCgswUJStDEwMDE0NTSyNDiExqRUFmUSpQ3NTU1MjAwAAiWpKZCxazNLcwNjYyMIWakpkONNTPzyTcLCzdsDLC0zTbMrHMPy870NXJUdvI3NwrMt20vMKl0q3KzNy1IKPYVqkWABdFLy0_";    final String UserID = "6";    final String UserSig = "eJwtzMEKgkAUheF3mXXIvZNjjdAigowINw5ES80xL6bdJikhevdkdHm*A-9XmFMWvK0TsZABiIXfVNqup4o8RzO*yiZnplLEGAKEqLTE6bEDk7OjK6UkAEzaU*tNr9YaQhXNFbqNzaLmrm6eW5a7xKTn9oL35IBH-Wh56VLcZ6bI2djhip*N*P0BGg4wBA__";    /     * 登录这里的id和sig分别为userid和用userID加密后生成的sign(服务端提供)     * 这里的userid可以替换为自己的userid     * usersign可以使用开发者后台提供的生成工具生成测试(生成工具地址:https://console.cloud.tencent.com/im-detail/tool-usersig)     * 具体正式usersign需要服务端生成后返回     */    public void login() { Log.i("腾讯云即时通信IM", "登录的账号为:" + 23); Log.i("腾讯云即时通信IM", "登录的密码为:" + "eJyrVgrxCdYrSy1SslIy0jNQ0gHzM1NS80oy0zIhwsZQ0eKU7MSCgswUJStDEwMDE0NTSyNDiExqRUFmUSpQ3NTU1MjAwAAiWpKZCxazNLcwNjYyMIWakpkONNTPzyTcLCzdsDLC0zTbMrHMPy870NXJUdvI3NwrMt20vMKl0q3KzNy1IKPYVqkWABdFLy0_"); Log.i("腾讯云即时通信IM", "登录的账号为:" + 6); Log.i("腾讯云即时通信IM", "登录的密码为:" + "eJwtzMEKgkAUheF3mXXIvZNjjdAigowINw5ES80xL6bdJikhevdkdHm*A-9XmFMWvK0TsZABiIXfVNqup4o8RzO*yiZnplLEGAKEqLTE6bEDk7OjK6UkAEzaU*tNr9YaQhXNFbqNzaLmrm6eW5a7xKTn9oL35IBH-Wh56VLcZ6bI2djhip*N*P0BGg4wBA__"); IMManager.login(UserID, UserSig, new V2TIMCallback() {      @Override      public void onError(int i, String s) {   Log.i("腾讯云即时通信IM", "登录失败,错误码为" + i + ",原因为:" + s);      }      @Override      public void onSuccess() {   Log.i("腾讯云即时通信IM", "登录成功,即將加入房间");   V2TIMUserFullInfo v2TIMUserFullInfo = new V2TIMUserFullInfo();   v2TIMUserFullInfo.setNickname(UserID.equals("23") ? "独孤求败" : "宇宙中的飞猪");   V2TIMManager.getInstance().setSelfInfo(v2TIMUserFullInfo, new V2TIMCallback(){@Overridepublic void onError(int i, String s) {    //修改失败    Log.i("腾讯云即时通信IM", "修改失败");}@Overridepublic void onSuccess() {    //修改成功    Log.i("腾讯云即时通信IM", "修改成功");}   });   joinRoom();      }  });    }    /     * 加入一个房间     */    private void joinRoom() { Log.i("腾讯云即时通信IM", "你即将加入的房间号为:" + ROOMID); IMManager.joinToLiveRoom(ROOMID, ROOMNAME, new V2TIMCallback() {     @Override     public void onError(int i, String s) {  Log.i("腾讯云即时通信IM", "加入房间失败。错误码为:" + i + ",错误信息为:" + s);     }     @Override     public void onSuccess() {  Log.i("腾讯云即时通信IM", "加入房间成功");     } });    }    /     * 发送一个消息     * @param msg     */    private void sendMessage(final String msg) { IMManager.sendTextMsg(msg, ROOMID, V2TIMMessage.V2TIM_PRIORITY_NORMAL, new V2TIMValueCallback() {     @Override     public void onError(int i, String s) {  Log.i("腾讯云即时通信IM", "发送失败");     }     @Override     public void onSuccess(V2TIMMessage v2TIMMessage) {  Log.i("腾讯云即时通信IM", "发送成功");  addMessage(UserID.equals("23") ? "独孤求败" : "宇宙中的飞猪", msg);     } });    }    /     * 添加消息进rv并刷新数据显示     * @param nickName     * @param msg     */    public void addMessage(String nickName, String msg) { lists.add(new ChatMsgBean(nickName, msg)); //让最后一个消息顶上来 chat_rv.scrollToPosition(chatMsgAdapter.getItemCount() - 1); chatMsgAdapter.notifyDataSetChanged();    }    @Override    public void onPause() { super.onPause(); //退出房间号 IMManager.exitLiveRoom(ROOMID); //销毁SDK IMManager.unInitIMSDk();    }}
注:自此功能完成。

其实整个功能不难,个人觉得开发者后台的文档有点乱,所以导致有时候理不清楚,故记录一下,顺便帮助一下需要使用的大佬,如果问题还请指出。

以上就是所有的代码

附上demo源码。

源码:源码请点这里


q:486789970
email:mr.cai_cai@foxmail.com

如果有什么问题,欢迎大家指导。并相互联系,希望能够通过文章互相学习。

   ---财财亲笔