合集
腾讯云IM接入案列(一)
腾讯云IM接入案列(二)
腾讯云IM接入案列(三)
腾讯云IM接入案列(四)
前言
上面实现了项目的基本导入,其实很多坑的,特别是还导入了其他腾讯sdk,会有很多冲突,玩玩解决就好
本篇内容
本篇来分析下腾讯demo里面的一些代码,由于腾讯demo使用的是mvp框架,如果不熟悉的,推荐先去学习一下,不过你不会跟着步骤做一样能实现头像显示的
ps:由于是做代码分析,可能会比较枯燥,往坚持.
会话列表显示分析
- 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类观看
- ConversationAdapter
相信经常用的adapter大家都比较熟悉了,代码很简单,关键点是
final Conversation data = getItem(position);
而Conversation是一个抽象类,里面封装了一些会话的基本信息,后面扩展一些消息可以在这基础上增加
//会话对象id
protected String identify;
//会话类型
protected TIMConversationType type;
//会话对象名称
protected String name;
...............略
而这里的实体类对象就是ConversationFragement中的第三点NomalConversation
- 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);
}
- 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具体如何显示
- 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:若有不理解或者有错误的地方欢迎留言评论)