TIM简单的即时通信以及仿QQ聊天页面布局

南宫俊逸
2023-12-01

最近帮朋友弄im即时通信,简单记录下整个过程,以便以后用到:
一、Timsdk的集成
直接上腾讯云官网看文档就可以集成了
https://www.qcloud.com/document/product/269/9227

二、初始化
1、登录TimSdk(登录前就要注册消息回调的接口):

public class Tecent_LogIn_Utils {
private String tag = "---->Tecent_LogIn_Utils";
private Context context;
private String identifier;
private String userSig;
private String groupId;
private int sdkAppId = 1400030792;
private TIMConversation conversation;
private int type;
private Message message;
private MyHandler myHandler;
private LogInImSdkCallBack resultCallBack;

public  void logInImSdk(final Context context, String groupId, LogInImSdkCallBack resultCallBack, int type) {
    this.type=type;
    this.groupId=groupId;
    this.context = context;
    this.resultCallBack=resultCallBack;
    this.userSig = SharedUtils.getSharedUtils().getData(context, "usersig");
    this.identifier = SharedUtils.getSharedUtils().getData(context, "uid");
    init();
    logIn();
}

private void init() {
    //初始化SDK基本配置
    TIMSdkConfig config = new TIMSdkConfig(sdkAppId)
            .enableCrashReport(false)
            .enableLogPrint(true)
            .setLogLevel(TIMLogLevel.DEBUG)
            .setLogPath(Environment.getExternalStorageDirectory().getPath() + "/justfortest/");
    //初始化SDK
    TIMManager.getInstance().init(context, config);
    TIMUserConfig userConfig = new TIMUserConfig()
            .setUserStatusListener(new TIMUserStatusListener() {
                @Override
                public void onForceOffline() {
                    //被其他终端踢下线
                    Log.i(tag, "onForceOffline");
                }

                @Override
                public void onUserSigExpired() {
                    //用户签名过期了,需要刷新userSig重新登录SDK
                    Log.i(tag, "onUserSigExpired");
                }
            })
            //设置连接状态事件监听器
            .setConnectionListener(new TIMConnListener() {
                @Override
                public void onConnected() {
                    Log.i(tag, "onConnected");
                }

                @Override
                public void onDisconnected(int code, String desc) {
                    Log.i(tag, "onDisconnected");
                }

                @Override
                public void onWifiNeedAuth(String name) {
                    Log.i(tag, "onWifiNeedAuth");
                }
            })
            //设置群组事件监听器
            .setGroupEventListener(new TIMGroupEventListener() {
                @Override
                public void onGroupTipsEvent(TIMGroupTipsElem elem) {
                    Log.i(tag, "onGroupTipsEvent, type: " + elem.getTipsType());
                }
            })
            //设置会话刷新监听器
            .setRefreshListener(new TIMRefreshListener() {
                @Override
                public void onRefresh() {
                    Log.i(tag, "onRefresh");
                }

                @Override
                public void onRefreshConversation(List<TIMConversation> conversations) {
                    Log.e(tag, "onRefreshConversation, Send_RecMsg_Utils size: " + conversations.size());
                }
            });
    //设置消息监听器,收到新消息时,通过此监听器回调
    TIMManager.getInstance().addMessageListener(new TIMMessageListener() {
        @Override
        public boolean onNewMessages(List<TIMMessage> list) {
            resultCallBack.onNewMessages(list,type);//新消息的回调,做了简单的实现;
            return false;
        }//消息监听器
    });

    TIMManager.getInstance().setUserConfig(userConfig);
}

private void logIn() {
    message=new Message();
    myHandler=new MyHandler(context,resultCallBack);
    // identifier为用户名,userSig 为用户登录凭证
    TIMManager.getInstance().login(identifier, userSig, new TIMCallBack() {
        @Override
        public void onError(int code, String desc) {
            //错误码code和错误描述desc,可用于定位请求失败原因
            Log.e(tag, "login failed. code: " + code + " errmsg: " + desc);
            message.what=2;
            message.obj = null;
            message.arg1=Tecent_LogIn_Utils.this.type;
            myHandler.sendMessage(message);
        }

        @Override
        public void onSuccess() {
            //获取会话
            conversation=getGroupConversation(groupId);
            message.what=1;
            message.obj = conversation;
            message.arg1=Tecent_LogIn_Utils.this.type;
            myHandler.sendMessage(message);
        }
    });
}
    ```

三、获取会话,该会话是用来发送消息的:

 public  TIMConversation getSingleConversation(String peer) {
        return TIMManager.getInstance().getConversation(TIMConversationType.C2C, peer);
    }
    /*//获取群聊会话
    *  groupId 群组的id
    * */
    public  TIMConversation getGroupConversation(String groupId) {
        return TIMManager.getInstance().getConversation(TIMConversationType.Group, groupId);
    }
}

四、发送消息

public static boolean sendMsg(TIMConversation conversation, String message) {
        //构造一条消息
        TIMMessage msg = new TIMMessage();
        //添加文本内容
        TIMTextElem elem = new TIMTextElem();
        elem.setText(message);
        //将elem添加到消息
        if (msg.addElement(elem) != 0) {
            Log.d(tag, "addElement failed");
            return false;
        }
        //发送消息
        conversation.sendMessage(msg, new TIMValueCallBack<TIMMessage>() {//发送消息回调
            @Override
            public void onError(int code, String desc) {//发送消息失败
                //错误码code和错误描述desc,可用于定位请求失败原因
                Log.e(tag, "send message failed. code: " + code + " errmsg: " + desc);
                isSend = false;
            }

            @Override
            public void onSuccess(TIMMessage msg) {//发送消息成功
                Log.e(tag, "send message ok ");
                isSend = true;
            }
        });
        return isSend;
    }

一个基本的流程就是这样了 ,另外需要注意的是:发送消息必须在拿到会话实例之后,本文用handler做了异步的处理;


下面贴一下聊天页面的布局:

一、适配器

public class Chat_ListView_Adapter extends BaseAdapter {
    private String url_me;
    private Activity context;
    private List<RecMsgBean> list_rec;
    private LayoutInflater mInflater;

    public static final int MESSAGE_LEFT = 0;
    public static final int MESSAGE_RIGHT = 1;
    private static final int RETURN_TYPE_COUNT = 2;

    private Map<Integer, TextView> map_text_me, map_text_other;

    public Chat_ListView_Adapter(Activity context,List<RecMsgBean> list) {
        this.context = context;
        this.list_rec = list;
        map_text_me = new HashMap<>();
        map_text_other = new HashMap<>();
        this.mInflater = LayoutInflater.from(context);
        url_me = SharedUtils.getSharedUtils().getData(context, "headimg");
    }

    public void setList(List<RecMsgBean> list_rec) {
        this.list_rec = list_rec;
        url_me = SharedUtils.getSharedUtils().getData(context, "headimg");
    }

    @Override
    public int getCount() {
        return (list_rec != null) ? (list_rec.size()) : (0);
    }
    @Override
    public int getViewTypeCount() {
        return RETURN_TYPE_COUNT;
    }
    @Override
    public int getItemViewType(int position) {
        return list_rec.get(position).getType();
    }

    @Override
    public Object getItem(int position) {
        return position;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolderLeft viewHolderLeft = null;
        ViewHolderRight viewHolderRight = null;
        if (convertView == null) {
            // 根据获得的type类型确定选择哪个layout
            switch (getItemViewType(position)) {
                case MESSAGE_LEFT:
                    viewHolderLeft = new ViewHolderLeft();
                    convertView = mInflater.inflate(R.layout.family_chat_list_item_rec, null);
                    viewHolderLeft.textView_other = (TextView) convertView.findViewById(R.id.chat_item_text_other);
                    viewHolderLeft.imageView_other = (RoundImagViewUtil) convertView.findViewById(R.id.chat_item_img_other);
                    convertView.setTag(viewHolderLeft);
                    break;
                case MESSAGE_RIGHT:
                    viewHolderRight = new ViewHolderRight();
                    convertView = mInflater.inflate(R.layout.family_chat_list_item_me, null);
                    viewHolderRight.textView_me = (TextView) convertView.findViewById(R.id.chat_item_text_me);
                    viewHolderRight.imageView_me = (RoundImagViewUtil) convertView.findViewById(R.id.chat_item_img_me);
                    convertView.setTag(viewHolderRight);
                    break;
                default:
                    break;
            }
        }else {
            switch (getItemViewType(position)) {
                case MESSAGE_LEFT:
                    viewHolderLeft= (ViewHolderLeft) convertView.getTag();
                    break;
                case MESSAGE_RIGHT:
                    viewHolderRight= (ViewHolderRight) convertView.getTag();
                    break;
            }
        }
        switch (getItemViewType(position)) {
            case MESSAGE_LEFT:
                viewHolderLeft.textView_other.setText(list_rec.get(position).getMsg());
                viewHolderLeft.textView_other.setBackgroundResource(R.drawable.other_qipao);
                BaseActivity.loadingImageLoader(context, list_rec.get(position).getHeadurl(), viewHolderLeft.imageView_other);
                break;
            case MESSAGE_RIGHT:
                viewHolderRight.textView_me.setText(list_rec.get(position).getMsg());
                viewHolderRight.textView_me.setBackgroundResource(R.drawable.wo_qipao);
                BaseActivity.loadingImageLoader(context, url_me, viewHolderRight.imageView_me);
                break;
            default:
                break;
        }
        return convertView;
}

    private class ViewHolderLeft{
        TextView textView_other;
        RoundImagViewUtil imageView_other;
    }
    private class ViewHolderRight{
        TextView textView_me;
        RoundImagViewUtil imageView_me;
    }
}

二、xml布局:主布局使用listview或者RecyclerView就好了 ,item布局需要两个:

别人发消息的布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp">
        <LinearLayout
            android:id="@+id/chat_linear_other"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <com.buji.shuzhekan.view.RoundImagViewUtil
                android:layout_width="35dp"
                android:layout_height="35dp"
                android:id="@+id/chat_item_img_other"
                android:layout_gravity="center_vertical"/>
            <TextView
                android:paddingTop="8dp"
                android:paddingBottom="8dp"
                android:paddingLeft="10dp"
                android:paddingRight="8dp"
                android:textColor="@color/brite"
                android:layout_marginLeft="8dp"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/chat_item_text_other"/>
        </LinearLayout>
    </RelativeLayout>
</LinearLayout>

自己发消息的布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp">
        <LinearLayout
            android:id="@+id/chat_linear_me"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:layout_alignParentRight="true"
            android:layout_below="@+id/chat_linear_other">
            <TextView
                android:paddingTop="8dp"
                android:paddingLeft="8dp"
                android:paddingBottom="8dp"
                android:paddingRight="10dp"
                android:layout_weight="1"
                android:textColor="@color/brite"
                android:layout_marginRight="8dp"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/chat_item_text_me"/>
            <com.buji.shuzhekan.view.RoundImagViewUtil
                android:layout_width="35dp"
                android:layout_height="35dp"
                android:id="@+id/chat_item_img_me"/>
        </LinearLayout>
    </RelativeLayout>
</LinearLayout>

这样一个简单的聊天功能就能够实现了 ,更多强大的功能也只需要看文档一步一步来就好了。

 类似资料: