腾讯云IM接入案列(二)

作者: return_toLife | 来源:发表于2018-03-23 17:52 被阅读201次

    合集

    腾讯云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:若有不理解或者有错误的地方欢迎留言评论)

    相关文章

      网友评论

      • kyriej2:大佬能否在此基础上继续写个群组聊天室demo
        return_toLife:@kyriej2 我不是什么大佬啊:joy: ,咱们技术交流下就好,别这样称呼。聊天室我有空看看吧,我准备毕业挺多事情要弄的

      本文标题:腾讯云IM接入案列(二)

      本文链接:https://www.haomeiwen.com/subject/gzztcftx.html