腾讯云IM接入案列(二)

合集

腾讯云IM接入案列(一)
腾讯云IM接入案列(二)
腾讯云IM接入案列(三)
腾讯云IM接入案列(四)

前言

上面实现了项目的基本导入,其实很多坑的,特别是还导入了其他腾讯sdk,会有很多冲突,玩玩解决就好

本篇内容

本篇来分析下腾讯demo里面的一些代码,由于腾讯demo使用的是mvp框架,如果不熟悉的,推荐先去学习一下,不过你不会跟着步骤做一样能实现头像显示的
ps:由于是做代码分析,可能会比较枯燥,往坚持.

会话列表显示分析

  1. ConversationFragement
    我们按着正常步骤来分析一下,首先界面显示最重要的是会话列表,然后我们可以从会话列表中进入聊天界面,那我们看看收到最新消息之后做了什么处理

关键代码

 /**
     * 更新最新消息显示
     *
     * @param message 最后一条消息
     */
    @Override
    public void updateMessage(TIMMessage message) {
   
        if (message == null){
            adapter.notifyDataSetChanged();
            return;
        }
        //1.系统消息,他把系统消息也作为一个组
        if (message.getConversation().getType() == TIMConversationType.System){
            groupManagerPresenter.getGroupManageLastMessage();
            return;
        }
        //2.这里很关键,如果后面用CustomMessage作为自定义消息扩展的话,这里要做一些处理,不做处理的话会话列表是不会有任何更新
        if (MessageFactory.getMessage(message) instanceof CustomMessage) return;
        //3. 会话信息实体
        NomalConversation conversation = new NomalConversation(message.getConversation());
        Iterator<Conversation> iterator =conversationList.iterator();
        while (iterator.hasNext()){
            Conversation c = iterator.next();
            if (conversation.equals(c)){
                conversation = (NomalConversation) c;
                iterator.remove();
                break;
            }
        }
        conversation.setLastMessage(MessageFactory.getMessage(message));
        conversationList.add(conversation);
        Collections.sort(conversationList);
        refresh();
    }

    /**
     * 刷新
     */
    @Override
    public void refresh() {
        Collections.sort(conversationList);
        adapter.notifyDataSetChanged();
//        if (getActivity() instanceof MainActivity)
//            ((HomeActivity) getActivity()).setMsgUnread(getTotalUnreadNum() == 0);
    }

我在代码上做了一些注解,这里我们主要留意第2点,后面会做进一步讲解
通过上面代码可以看出,收到新消息通过adapter.notifyDataSetChanged();进行更新,那我们接着进入adapter类观看

  1. ConversationAdapter
    相信经常用的adapter大家都比较熟悉了,代码很简单,关键点是
 final Conversation data = getItem(position);

而Conversation是一个抽象类,里面封装了一些会话的基本信息,后面扩展一些消息可以在这基础上增加

    //会话对象id
    protected String identify;

    //会话类型
    protected TIMConversationType type;

    //会话对象名称
    protected String name;
    ...............略

而这里的实体类对象就是ConversationFragement中的第三点NomalConversation

  1. NomalConversation
    这个类实现了conversation定义的抽象方法,很明显可以看出,就是返回了会话列表中的头像,用户名,消息摘要等一系列的信息,聪明的小伙伴们一定想到,后面我们做会话列表的显示,就是在这做修改并且结合ConversationAdapter里来实现不同的会话列表界面
    这里写个例子
 //Conversation
     abstract public UserInfo getUserInfo();

 //NomalConversation
   UserInfo getUserInfo(){
    return UserInfo;
 }
//ConversationAdapter
 final Conversation data = getItem(position);
 UserInfo userInfo=data.getUserInfo();

上面的只是个例子,可以有很多种写法,具体看个人习惯

相信通过上面的例子,大家应该知道怎么做自定义会话列表的内容显示了,下面来看看聊天界面吧

聊天界面分析

首先在ConversationFragment中找到入口,不难发现入口代码

/**
     * 跳转到聊天界面或会话详情
     *
     * @param context 跳转上下文
     */
    @Override
    public void navToDetail(Context context) {
        ChatActivity.navToChat(context,identify,type);
    }
  1. chatActivity
    由于使用的是mvp模式,所以我们可以通过ChatView来快速查看它所了哪些事情

/**
 * 聊天界面的接口
 */
public interface ChatView extends MvpView {

    /**
     * 显示消息
     */
    void showMessage(TIMMessage message);

    /**
     * 显示消息
     */
    void showMessage(List<TIMMessage> messages);

   ····
   ····
   ····

(ps:个人很喜欢MVP,虽然也有缺点,但是利大于弊,代码结构一目了然,而且扩展很容易)
发送消息就不多说了,看下代码都理解,这里我们主要看看显示消息

/**
     * 显示消息
     *
     * @param message
     */
    @Override
    public void showMessage(TIMMessage message) {
        if (message == null) {
            adapter.notifyDataSetChanged();
        } else {
            Message mMessage = MessageFactory.getMessage(message);
            if (mMessage != null) {
                if (mMessage instanceof CustomMessage){
                    CustomMessage.Type messageType = ((CustomMessage) mMessage).getType();
                    switch (messageType){
                        case TYPING:
                            TemplateTitle title = (TemplateTitle) findViewById(R.id.chat_title);
                            title.setTitleText(getString(R.string.chat_typing));
                            handler.removeCallbacks(resetTitle);
                            handler.postDelayed(resetTitle,3000);
                            break;
                        default:
                            break;
                    }
                }else{
                    if (messageList.size()==0){
                        mMessage.setHasTime(null);
                    }else{
                        mMessage.setHasTime(messageList.get(messageList.size()-1).getMessage());
                    }
                    messageList.add(mMessage);
                    adapter.notifyDataSetChanged();
                    listView.setSelection(adapter.getCount()-1);
                }

            }
        }

    }

这里有个关键,就是CustomMessage,结合之前ConversationFragment里让大家留意的关键点可以得出,CustomMessage类主要是用来显示某一些状态,并且不会更新会话列表的信息,所以CustomMessage类不适合用来做自定义扩展消息.当然也不是不可以,在两个地方同时做一些判断也是可以实现,我尝试过,比较麻烦,而且我觉得这可能不是写demo的人的初衷。

同样的,聊天界面的具体显示在chatAdapter里面,进去查看,关键点

      if (position < getCount()){
            final Message data = getItem(position);
            data.showMessage(viewHolder, getContext());
        }

Message也是一个抽象类,所以,具体真正做界面显示的是在各种Message的子类。
这里大家要注意,由于adapter里的item布局已经写死为item_message,而每种消息显示的界面需求是很多样化的,我们点进其中一种Message的子类去查看他的showMessage具体如何显示

  1. TextMessage
 /**
     * 在聊天界面显示消息
     *
     * @param viewHolder 界面样式
     * @param context 显示消息的上下文
     */
    @Override
    public void showMessage(ChatAdapter.ViewHolder viewHolder, Context context) {
        clearView(viewHolder);
        if (checkRevoke(viewHolder)) return;
        boolean hasText = false;
        TextView tv = new TextView(MyApplication.getContext());
        tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);
        tv.setTextColor(MyApplication.getContext().getResources().getColor(isSelf() ? R.color.white : R.color.black));
        List<TIMElem> elems = new ArrayList<>();
        for (int i = 0; i < message.getElementCount(); ++i){
            elems.add(message.getElement(i));
            if (message.getElement(i).getType() == TIMElemType.Text){
                hasText = true;
            }
        }
        SpannableStringBuilder stringBuilder = getString(elems, context);
        if (!hasText){
            stringBuilder.insert(0," ");
        }
        tv.setText(stringBuilder);
        getBubbleView(viewHolder).addView(tv);
        showStatus(viewHolder);
    }

可以看出,他的控件是通过动态添加来实现的,而且他还有一个bubbleview的父布局,这里我觉得相比于环信,环信的自定义布局会比较容易绘制和操控。

总结

其实这里主要讲解了一些比较浅显的代码逻辑梳理,为了方便后面讲解具体实现界面显示做准备,下篇就会开始真正动手实现我们想要的界面显示。

项目地址

你们最关注的来了
https://github.com/DongDian455/TIMDemo

下篇

腾讯云IM接入案列(三)
(ps:若有不理解或者有错误的地方欢迎留言评论)

    原文作者:return_toLife
    原文地址: https://www.jianshu.com/p/38658b7adca0
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞