环信UI开源Demo情景分析七、会话界面

5分钟集成即时通讯功能——环信Android版 下载环信demo (Android) 什么是环信demo 环信demo展示了怎样使用环信SDK快速创建一个完整的类微信聊天APP。展示的功能包括:环信SDK初始化,登录,登出,注册消息接收listener, 发送消息。 环信demo源代码已在github上开源供开发者下载,以帮助开发者更好的学习了解环信SDK。 下载环信sdk及demo 到环信官网下载 阅读详情

在会话界面中,主要是对会话记录的操作。就跟QQ上面的一样,最左边的一个Tab。管理会话历史,并动态显示消息数量。

因为整个会话界面是由Fragment所组成,所以没有清单文件。接下来咱们先来看看布局文件的构成。

<?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:background="@color/common_bg"
    android:orientation="vertical" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="@dimen/height_top_bar"
        android:background="@color/top_bar_normal_bg"
        android:gravity="center_vertical" >

        <TextView
            android:id="@+id/message_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="@string/session"
            android:textColor="#fff"
            android:textSize="18sp" />
    </RelativeLayout>

    <include layout="@layout/search_bar" />

    <include
        android:id="@+id/rl_error_item"
        layout="@layout/chat_neterror_item"
        android:visibility="gone" />

    <ListView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/transparent"
        android:cacheColorHint="#00000000"
        android:divider="@null" />

</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingTop="7dp"
    android:paddingBottom="7dp"
    android:background="#ededed"
    android:paddingLeft="@dimen/padding_search_bar"
    android:paddingRight="@dimen/padding_search_bar" >

    <EditText
      	android:paddingTop="5dp"
        android:paddingBottom="5dp"
        android:paddingLeft="5dp"
        android:id="@+id/query"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:background="@drawable/seabar_input"
        android:drawableLeft="@drawable/search_bar_icon_normal"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:textColorHint="#b3b3b3"
        android:textSize="16sp"
        android:layout_marginLeft="4dp"
        android:layout_marginRight="4dp"
        android:singleLine="true"/>

    <ImageButton
        android:id="@+id/search_clear"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_marginRight="3dp"
        android:background="@android:color/transparent"
        android:padding="6dp"
        android:src="@drawable/search_clear"
        android:visibility="invisible" />

</RelativeLayout>

可以简单,最顶端是一个Title,接下来是一个自定义的搜索栏,还有一个错误提示栏,不过默认状况下是不显示的,最下面就是这个界面最重要的组成了------ListView。

@Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        if (savedInstanceState != null && savedInstanceState.getBoolean("isConflict", false))
            return;
        inputMethodManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
        errorItem = (RelativeLayout) getView().findViewById(R.id.rl_error_item);
        errorText = (TextView) errorItem.findViewById(R.id.tv_connect_errormsg);
        // 添加会话列表
        conversationList.addAll(loadConversationsWithRecentChat());
        listView = (ListView) getView().findViewById(R.id.list);
        adapter = new ChatAllHistoryAdapter(getActivity(), 1, conversationList);
        // 设置adapter
        listView.setAdapter(adapter);
        final String st2 = getResources().getString(R.string.Cant_chat_with_yourself);
        listView.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                EMConversation conversation = adapter.getItem(position);
                String username = conversation.getUserName();
                if (username.equals(DemoApplication.getInstance().getUserName()))
                    Toast.makeText(getActivity(), st2, 0).show();
                else {
                    // 进入聊天页面
                    Intent intent = new Intent(getActivity(), ChatActivity.class);
                    if (conversation.isGroup()) {
                        // it is group chat
                        intent.putExtra("chatType", ChatActivity.CHATTYPE_GROUP);
                        intent.putExtra("groupId", username);
                    } else {
                        // it is single chat
                        intent.putExtra("userId", username);
                    }
                    startActivity(intent);
                }
            }
        });
        // 注册上下文菜单
        registerForContextMenu(listView);
        listView.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // 隐藏软键盘
                hideSoftKeyboard();
                return false;
            }
        });
        // 搜索框
        query = (EditText) getView().findViewById(R.id.query);
        String strSearch = getResources().getString(R.string.search);
        query.setHint(strSearch);
        // 搜索框中清除button
        clearSearch = (ImageButton) getView().findViewById(R.id.search_clear);
        query.addTextChangedListener(new TextWatcher() {
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                adapter.getFilter().filter(s);
                if (s.length() > 0) {
                    clearSearch.setVisibility(View.VISIBLE);
                } else {
                    clearSearch.setVisibility(View.INVISIBLE);
                }
            }
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }
            public void afterTextChanged(Editable s) {
            }
        });
        clearSearch.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                query.getText().clear();
                hideSoftKeyboard();
            }
        });
    }
// 隐藏软键盘
	void hideSoftKeyboard() {
		if (getActivity().getWindow().getAttributes().softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) {
			if (getActivity().getCurrentFocus() != null)
				inputMethodManager.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
		}
	}

在onActivityCreated方法中,最界面的逻辑处理以及数据的初始化过程,先从SDK提供的方法获取会话,然后显示出来,并且设置相应的项目点击事件。以及查询和软键盘的相应处理。

其中对会话列表还设置了上下文菜单,可以对选择的某条会话进行删除操作。

@Override
	public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
		super.onCreateContextMenu(menu, v, menuInfo);
		// if(((AdapterContextMenuInfo)menuInfo).position > 0){ m,
		getActivity().getMenuInflater().inflate(R.menu.delete_message, menu);
		// }
	}

	@Override
	public boolean onContextItemSelected(MenuItem item) {
		boolean handled = false;
		boolean deleteMessage = false;
		if (item.getItemId() == R.id.delete_message) {
			deleteMessage = true;
			handled = true;
		} else if (item.getItemId() == R.id.delete_conversation) {
			deleteMessage = false;
			handled = true;
		}
		EMConversation tobeDeleteCons = adapter.getItem(((AdapterContextMenuInfo) item.getMenuInfo()).position);
		// 删除此会话
		EMChatManager.getInstance().deleteConversation(tobeDeleteCons.getUserName(), tobeDeleteCons.isGroup(), deleteMessage);
		InviteMessgeDao inviteMessgeDao = new InviteMessgeDao(getActivity());
		inviteMessgeDao.deleteMessage(tobeDeleteCons.getUserName());
		adapter.remove(tobeDeleteCons);
		adapter.notifyDataSetChanged();

		// 更新消息未读数
		((MainActivity) getActivity()).updateUnreadLabel();

		return handled ? true : super.onContextItemSelected(item);
	}

当删除会话后调用Main中的updateUnreadLabel更新未读消息数。

/**
	 * 获取所有会话
	 * 
	 * @param context
	 * @return +
	 */
	private List<EMConversation> loadConversationsWithRecentChat() {
		// 获取所有会话,包括陌生人
		Hashtable<String, EMConversation> conversations = EMChatManager.getInstance().getAllConversations();
		// 过滤掉messages size为0的conversation
		/**
		 * 如果在排序过程中有新消息收到,lastMsgTime会发生变化 影响排序过程,Collection.sort会产生异常
		 * 保证Conversation在Sort过程中最后一条消息的时间不变 避免并发问题
		 */
		List<Pair<Long, EMConversation>> sortList = new ArrayList<Pair<Long, EMConversation>>();
		synchronized (conversations) {
			for (EMConversation conversation : conversations.values()) {
				if (conversation.getAllMessages().size() != 0) {
					sortList.add(new Pair<Long, EMConversation>(conversation.getLastMessage().getMsgTime(), conversation));
				}
			}
		}
		try {
			// Internal is TimSort algorithm, has bug
			sortConversationByLastChatTime(sortList);
		} catch (Exception e) {
			e.printStackTrace();
		}
		List<EMConversation> list = new ArrayList<EMConversation>();
		for (Pair<Long, EMConversation> sortItem : sortList) {
			list.add(sortItem.second);
		}
		return list;
	}
	/**
	 * 根据最后一条消息的时间排序
	 * 
	 * @param usernames
	 */
	private void sortConversationByLastChatTime(List<Pair<Long, EMConversation>> conversationList) {
		Collections.sort(conversationList, new Comparator<Pair<Long, EMConversation>>() {
			@Override
			public int compare(final Pair<Long, EMConversation> con1, final Pair<Long, EMConversation> con2) {
				if (con1.first == con2.first) {
					return 0;
				} else if (con2.first > con1.first) {
					return 1;
				} else {
					return -1;
				}
			}
		});
	}

获得所有会话信息,并按照时间顺序进行排列。

//当点击MAIN界面中其他Tab的时候会隐藏当前Fragment,调用此方法,并且刷新界面
	@Override
	public void onHiddenChanged(boolean hidden) {
		super.onHiddenChanged(hidden);
		this.hidden = hidden;
		if (!hidden) {
			refresh();
		}
	}
//当重新显示,并且没有隐藏的话,刷新。
	@Override
	public void onResume() {
		super.onResume();
		if (!hidden && !((MainActivity) getActivity()).isConflict) {
			refresh();
		}
	}
	/**
	 * 刷新页面, 刷新的时候重新获取会话列表。
	 */
	public void refresh() {
		conversationList.clear();
		conversationList.addAll(loadConversationsWithRecentChat());
		if (adapter != null)
			adapter.notifyDataSetChanged();
	}
在界面改变之后删除之前数据,重新显示。

	@Override
	public void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		if (((MainActivity) getActivity()).isConflict) {
			outState.putBoolean("isConflict", true);
		} else if (((MainActivity) getActivity()).getCurrentAccountRemoved()) {
			outState.putBoolean(Constant.ACCOUNT_REMOVED, true);
		}
	}
保存账号信息。至此,会话列表就完成了,其中比较简单。


环信SDK使用的简单Demo 实现了环信SDK的简单的使用方法,主要提供文本信息的消息列表和即时会话功能。 立即下载

相关推荐

Android环信即时通讯简单DEMO

一个集成环信的即时通讯demo,简单的注册环信账号,登录进行聊天,聊天页面使用环信提供的EaseUI

环信easeui集成:坑总结2018

环信EaseUI 集成,集成不做描述,看文档即可,下面主要谈一些对easeui的个性化需求修改。 该篇文章将解决的问题: 1、如何将App用户体系的用户名和用户头像 显示于环信的easeui 2、如何从library中调用app中的方法? 3、easeui头像都是方形的,如果修改为圆型显示? 4、环信用户注册问题:环信用户注册需要交给服务器注册用户的同时去注册 5...

defukwanmcth26174的博客 470

Android基于环信聊天的Demo

该资源用于简单的环信注册、登录聊天功能的实现

环信UI开源Demo情景分析六、主界面

终于来到正题了,这个应用最核心的地方,老规矩,先来看看清单里面的配置: <activity android:name=".activity.MainActivity" android:launchMode="singleTask" android:screenOrientation="p

2542

SDM量化噪声等效到PLL输出的传递函数推导

在历年文章或书本中少见SDM量化噪声等效到PLL输出的传递函数推导。需了解SDM量化噪声的本质,配合欧拉方程简化,并将Z域转化成S域。最终结合断环处等效到PLL输出的传递函数,方可完成。

u010486560的博客 1409

SBP依赖计算中的蝴蝶效应:一个Prefab修改如何触发全量重建?

本文深入探讨了Unity中SBP(Scriptable Build Pipeline)依赖计算的蝴蝶效应,解析了Prefab修改如何触发全量重建的机制。通过分析Asset与Object的层级关系、依赖计算的三种维度及CacheEntry系统,揭示了全量重建的根本原因,并提供了依赖可视化工具开发、优化策略与最佳实践,帮助开发者提升构建效率。

weixin_29015051的博客 445

环信UI开源Demo情景分析十二、聊天界面(四)

在这一章咱们来分析一下聊天界面中消息的显示,MessageAdapter。 public MessageAdapter(Context context, String username, int chatType) { this.username = username; this.context = context; inflater = LayoutInflater.from(c

1704

单细胞marker基因表达密度图-(还有一个包装函数)

我们借助Nebulosa,将上面的过程包装为一个函数,还是那句话,受累麻烦的事我们来解决,您轻松即可,先看看函数参数:需要注意的是,如果你只想框选某一类celltype,理想模式是这群celltype是单独聚类的,没有散落在其他类群,否则将会全部框选,效果不好,建议使用AI/PS添加。需要注意,这里我算是投机取巧了,用了一个和这个作图毫无关系的包ggnetwork,主要的目的是用他的theme_blank()主题,一次性将所有清空,当然也可以自己慢慢写,不过有现成的,为啥不用呢?这质感不就上去了嘛。

qq_42090739的博客 1369

环信UI开源Demo情景分析三、启动界面

在分析启动界面SplashActivity前,先来看看清单文件中对这个界面的设置: <activity android:name=".activity.SplashActivity" android:screenOrientation="portrait" android:theme="@style/h

1581

ctf——writeup

ctf线上赛——第三关地址:http://106.75.86.18:2222提示:ip spoofing——ip伪造首先访问目标地址,一个正常的网页,挺文艺的。上面有些提示。根据上面的提示,我们浏览网页。找了好久,终于找到你。这个跳转链接。(在这个页面下方)我们接着点击这个链接,就跳转到administrator.php这个页面了。看到这个登录页面,就要知道用户名,密码,可是没有怎么办。一开始也试

Child_by_dream的博客 1320

JSSIP实战:5分钟搞定WebRTC电话功能(附完整代码示例)

本文通过JSSIP库实战演示如何在Web应用中快速集成WebRTC电话功能。文章提供了从环境准备、SIP服务器连接到完整代码示例的详细步骤,涵盖用户注册、拨号接听、媒体流处理等核心环节,并针对常见问题给出排查方案,帮助开发者高效实现网页端实时语音通信。

u8v9w0x1y的博客 518

环信UI开源Demo情景分析八、会话界面(补充)

在介绍会话界面的时候忘记了一部分内容,关于会话列表的显示。ChatAllHistoryAdapter。

1466

深入解析SGLang框架:从架构设计到核心组件实现

本文深入解析了SGLang框架的架构设计与核心组件实现。SGLang是一个专为大语言模型推理设计的高效框架,其核心优势在于清晰的分层架构、高效的调度策略以及精细的内存管理。文章详细剖析了其客户端接入、服务器端调度、模型执行引擎及Tokenizer/Detokenizer管理器等关键组件,揭示了其实现高性能推理的内部机制。

coffee的博客 577

环信UI开源Demo情景分析一、项目概述

由于工作需要,目前要开发一款聊天功能的应用,但是一直做的项目都没有设计这方面的东西,所以打算短时间内苦学一下,终于在茫茫网海中找到了一款DEMO,是环信运通讯所开源的一个项目,集成了自家的通讯服务。 再接下来的分析中主要是针对项目中对本地消息处理逻辑的分析,不会过多的参与SDK的相关东西。 想要下载DEMO的童鞋请点这里。

1456

【ArcPy】用Python批量处理大规模地理数据的几何校正

在许多GIS应用中,尤其是在大规模地理数据处理时,几何校正(Geometric Correction)是一个至关重要的任务。它确保了不同来源的地理数据能够正确地对齐和匹配,从而为后续分析提供准确的基础。几何校正的常见应用包括遥感影像的地理配准、矢量数据的投影转换等。几何校正通常包括坐标转换、重采样等步骤。以下示例展示了如何使用arcpy的工具进行几何校正。"""实施几何校正:param input_layer: 输入待校正数据层。

陈书予 1002

完整功能-《网络安全创新实践》:设计并实现一种基于Npcap的网络嗅探器(直接能运行cpp的MFC代码+实验报告)

《网络安全创新实践》:设计并实现一种基于Npcap的网络嗅探器。(直接能跑的MFC)监听所有数据包,以及监听指定IP地址的数据包;(2)能够显示完整的IP数据包首部信息,例如:版本、首部长度、数据包长度、数据包类型(协议字段)、TTL、源IP地址、目的IP地址等;(3)能够显示完整的TCP报文段信息,例如:源端口、目的端口、序号、确认号、数据部分等;(4)能够自动检测SQL注入攻击等Web攻击行为;(5)能够将监听到的数据包信息保存到文件中,以及从文件中读取并显示数据包信息;(6)具有图形化操作界面。

weixin_46531010的博客 661

环信UI开源Demo情景分析五、注册界面

注册界面比较简单,一个账号,两个密码,一个按钮。 <activity android:name=".activity.RegisterActivity" android:screenOrientation="portrait" android:theme="@style/horizont

966

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

环信UI开源Demo情景分析四、登陆界面

接下来咱们来分析下登录界面,根据清单文件的配置不难发现接下来的Activity基本都是竖屏显示,以及与启动界面一样的动画: <activity android:name=".activity.LoginActivity" android:screenOrientation="portrait"

1869

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

环信UI开源Demo情景分析九、聊天界面(一)

从会话列表点击一个会话进入聊天界面,现在咱们先来看看聊天界面的清单配置。 <activity android:name=".activity.ChatActivity" android:launchMode="singleTop" android:screenOrientation="por

1987

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

环信UI开源Demo情景分析十一、聊天界面(三)

前面两章已经了解了大部分功能,不过还有一些东西没有讲到,接下来咱们就继续将剩下的部分讲完。 @Override protected void onDestroy() { super.onDestroy(); activityInstance = null; EMGroupManager.getInstance().removeGroupChangeListener(groupLi

1104

环信UI开源Demo情景分析十、聊天界面(二)

上一章说到了转发消息用户列表界面ForwardMessageActivity,这一章我们接着连看这个功能实现。 <activity android:name=".activity.ForwardMessageActivity" android:screenOrientation="portrait" andr

1463

环信IM SDK使用(三):环信EaseUi库介绍

为了后续更加专注于环信IM SDK本身的介绍,本次文章着重介绍一下环信提供的EaseUi库,EaseUi库可以方便开发者更加方便和快捷的集成和使用环信SDK。 1、EaseUI类提供了SDK初始化的方案。 在EaseUI的init()方法中会检查当前进程是否是主进程,保证SDK只在主进程中初始化。 2、提供了聊天,会话及联系人的fragment,直接使用或者继承扩展,方便开发者使用。 3、提供了文本,文件,图片,定位,视频,音频及Custom IM消息类型。

Heijinbaitu的博客 1367

基于环信sdk在uni-app框架中快速开发一款多平台社交Demo

说在前面:此款 demo 是基于 环信sdk 开发的一款具有单聊、群聊、聊天室、音视频等功能的应用。在此之前我们已经开发完 Vue、react(web端)、微信小程序。这三个热门领域的版本,如有需要源码可以后台留言索取。 安装开发工具 我们选用微信小程序来用做示例(如果选择百度、支付宝安装对应开发者工具即可)、 微信开发者工具建议还是安装最新版的。uni-app的开发也必须安装HBuilderX工具,这个是捆绑的,没得选择。要用uni-app,你必须得装! 工具安装: 微信开发者工..

huan132456765的博客 2513

Android修改环信easyui,EaseUI 使用指南

EaseUI 使用指南简介EaseUI 是一个 UI 库,封装了 IM 功能常用的控件、fragment 等等,旨在帮助开发者快速集成环信 SDK。EaseUI 及 Demo 的 GitHub 下载地址为:注意:因为这是一个 UI 库,后续很可能还会继续改动,新旧版本在 API 的兼容上不会像 IM SDK 那样绝对的兼容。代码导入EaseUI 库的代码是开源的,下载的 SDK 压缩包里面已经包含...

weixin_33664191的博客 1297

环信UI开源Demo情景分析二、清单文件

废话不多说,上代码: <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.easemob.chatuidemo" android:versionCode="12" android:versionName="2.1.8" > <uses-sdk

1289

运行环信Android Demo常见问题以及语音消息播放声音小的解决方法

2.点击位置的点击事件更换 ,demo中的点击事件是在EaseChatFragment下的onExtendMenuItemClick里面官方提供了EaseBaiduMapActivity 这个定位页面。2.在chatfragment中重写位置的点击事件方法startMapLocation或者是直接在EaseChatFragment中直接修改点击事件startMapLocation跳转到高德地图;相机是直接调用的系统的,跟随的是系统的大小,我拍摄15s视频大概18m左右。需要本地库倒入easeimkit。

huan132456765的博客 590
上一篇: 环信UI开源Demo情景分析六、主界面
下一篇: 环信UI开源Demo情景分析八、会话界面(补充)
倾辞
博客等级 码龄14年 33粉丝 45原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值