代码地址如下:
http://www.demodashi.com/demo/11645.html

我的博客地址

之前一直想实现聊天的功能,但是感觉有点困难,今天看了环信的API,就利用下午的时间动手试了试,然后做了一个小Demo。

因为没有刻意去做聊天软件,花的时间也不多,然后界面就很简单,都是一些基本知识,如果觉得功能简单,可以自行添加,我这就不多介绍了。

照例先来一波动态演示:

功能很简单,注册用户 --> 用户登录 --> 选择聊天对象 --> 开始聊天

使用到的知识点:

  1. RecyclerView
  2. CardView
  3. 环信的API的简单使用

依赖的库

compile 'com.android.support:appcompat-v7:24.2.1'
compile 'com.android.support:cardview-v7:24.1.1'
compile 'com.android.support:recyclerview-v7:24.0.0'    

1、聊天页面

首先是看了郭神的《第二行代码》做了聊天界面,用的是RecyclerView

#### a. 消息类的封装 ####

public class MSG {public static final int TYPE_RECEIVED = 0;//消息的类型:接收public static final int TYPE_SEND = 1;    //消息的类型:发送private String content;//消息的内容private int type;      //消息的类型public MSG(String content, int type) {this.content = content;this.type = type;}public String getContent() {return content;}public int getType() {return type;}
}

#### b. RecyclerView子项的布局 ####

<LinearLayoutandroid:id="@+id/ll_msg_left"android:layout_width="wrap_content"android:layout_height="wrap_content"<!-- 设置点击效果为水波纹(5.0以上) -->android:background="?android:attr/selectableItemBackground"android:clickable="true"android:focusable="true"android:orientation="horizontal"android:padding="2dp"><android.support.v7.widget.CardViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"app:cardCornerRadius="20dp"app:cardPreventCornerOverlap="false"app:cardUseCompatPadding="true"><ImageViewandroid:layout_width="50dp"android:layout_height="50dp"android:scaleType="centerCrop"android:src="@mipmap/man" /></android.support.v7.widget.CardView><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/message_left"android:orientation="horizontal"><TextViewandroid:id="@+id/tv_msg_left"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:layout_margin="10dp"android:textColor="#fff" /></LinearLayout></LinearLayout>

这是左边的部分,至于右边应该也就简单了。我用CardView把ImageView包裹起来,这样比较好看。效果如下:

#### c. RecyclerView适配器 ####

    public class MsgAdapter extends RecyclerView.Adapter<MsgAdapter.MyViewHolder> {private List<MSG> mMsgList;public MsgAdapter(List<MSG> mMsgList) {this.mMsgList = mMsgList;}@Overridepublic MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {View view = View.inflate(parent.getContext(), R.layout.item_msg, null);MyViewHolder holder = new MyViewHolder(view);return holder;}@Overridepublic void onBindViewHolder(MyViewHolder holder, int position) {MSG msg = mMsgList.get(position);if (msg.getType() == MSG.TYPE_RECEIVED){//如果是收到的消息,显示左边布局,隐藏右边布局holder.llLeft.setVisibility(View.VISIBLE);holder.llRight.setVisibility(View.GONE);holder.tv_Left.setText(msg.getContent());} else if (msg.getType() == MSG.TYPE_SEND){//如果是发送的消息,显示右边布局,隐藏左边布局holder.llLeft.setVisibility(View.GONE);holder.llRight.setVisibility(View.VISIBLE);holder.tv_Right.setText(msg.getContent());}}@Overridepublic int getItemCount() {return mMsgList.size();}static class MyViewHolder extends RecyclerView.ViewHolder{LinearLayout llLeft;LinearLayout llRight;TextView tv_Left;TextView tv_Right;public MyViewHolder(View itemView) {super(itemView);llLeft = (LinearLayout) itemView.findViewById(R.id.ll_msg_left);llRight = (LinearLayout) itemView.findViewById(R.id.ll_msg_right);tv_Left = (TextView) itemView.findViewById(R.id.tv_msg_left);tv_Right = (TextView) itemView.findViewById(R.id.tv_msg_right);}}
}

这部分应该也没什么问题,就是适配器的创建,我之前的文章也讲过 传送门:简单粗暴----RecyclerView

#### d. RecyclerView初始化 ####

就是一些基本的初始化,我就不赘述了,讲一下添加数据的细节处理

    btSend.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {String content = etInput.getText().toString().trim();if (!TextUtils.isEmpty(content)){...//环信部分的发送消息MSG msg = new MSG(content, MSG.TYPE_SEND);mList.add(msg);//当有新消息时,刷新RecyclerView中的显示mAdapter.notifyItemInserted(mList.size() - 1);//将RecyclerView定位到最后一行mRecyclerView.scrollToPosition(mList.size() - 1);etInput.setText("");}}});

至此界面已经结束了,接下来就是数据的读取

2. 环信API的简单应用

官网有详细的API介绍 环信及时通讯V3.0,我这里就简单介绍如何简单集成

#### a. 环信开发账号的注册 ####

环信官网

创建应用得到Appkey后面要用

#### b. SDK导入 ####

你可以直接下载然后拷贝工程的libs目录下

Android Studio可以直接添加依赖

将以下代码放到项目根目录的build.gradle文件里

repositories {maven { url "https://raw.githubusercontent.com/HyphenateInc/Hyphenate-SDK-Android/master/repository" }
}

在你的module的build.gradle里加入以下代码

android {//use legacy for android 6.0useLibrary 'org.apache.http.legacy'
}
dependencies {compile 'com.android.support:appcompat-v7:23.4.0'//Optional compile for GCM (Google Cloud Messaging).compile 'com.google.android.gms:play-services-gcm:9.4.0'compile 'com.hyphenate:hyphenate-sdk:3.2.3'
}

如果想使用不包含音视频通话的sdk,用compile 'com.hyphenate:hyphenate-sdk-lite:3.2.3'

#### c. 清单文件配置 ####

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="Your Package"android:versionCode="100"android:versionName="1.0.0"><!-- Required --><uses-permission android:name="android.permission.VIBRATE" /><uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.RECORD_AUDIO" /><uses-permission android:name="android.permission.CAMERA" /><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /><uses-permission android:name="android.permission.GET_TASKS" /><uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /><uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /><uses-permission android:name="android.permission.WAKE_LOCK" /><uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /><uses-permission android:name="android.permission.READ_PHONE_STATE" /><uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /><applicationandroid:icon="@drawable/ic_launcher"android:label="@string/app_name"android:name="Your Application"><!-- 设置环信应用的AppKey --><meta-data android:name="EASEMOB_APPKEY"  android:value="Your AppKey" /><!-- 声明SDK所需的service SDK核心功能--><service android:name="com.hyphenate.chat.EMChatService" android:exported="true"/><service android:name="com.hyphenate.chat.EMJobService"android:permission="android.permission.BIND_JOB_SERVICE"android:exported="true"/><!-- 声明SDK所需的receiver --><receiver android:name="com.hyphenate.chat.EMMonitorReceiver"><intent-filter><action android:name="android.intent.action.PACKAGE_REMOVED"/><data android:scheme="package"/></intent-filter><!-- 可选filter --><intent-filter><action android:name="android.intent.action.BOOT_COMPLETED"/><action android:name="android.intent.action.USER_PRESENT" /></intent-filter></receiver></application>
</manifest>

APP打包混淆

-keep class com.hyphenate.** {*;}
-dontwarn  com.hyphenate.**

#### d. 初始化SDK ####

在自定义Application的onCreate中初始化

public class MyApplication extends Application {private Context appContext;@Overridepublic void onCreate() {super.onCreate();EMOptions options = new EMOptions();options.setAcceptInvitationAlways(false);appContext = this;int pid = android.os.Process.myPid();String processAppName = getAppName(pid);// 如果APP启用了远程的service,此application:onCreate会被调用2次// 为了防止环信SDK被初始化2次,加此判断会保证SDK被初始化1次// 默认的APP会在以包名为默认的process name下运行,如果查到的process name不是APP的process name就立即返回if (processAppName == null || !processAppName.equalsIgnoreCase(appContext.getPackageName())) {Log.e("--->", "enter the service process!");// 则此application::onCreate 是被service 调用的,直接返回return;}//初始化EMClient.getInstance().init(getApplicationContext(), options);//在做打包混淆时,关闭debug模式,避免消耗不必要的资源EMClient.getInstance().setDebugMode(true);}private String getAppName(int pID) {String processName = null;ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);List l = am.getRunningAppProcesses();Iterator i = l.iterator();PackageManager pm = this.getPackageManager();while (i.hasNext()) {ActivityManager.RunningAppProcessInfo info = (ActivityManager.RunningAppProcessInfo) (i.next());try {if (info.pid == pID) {processName = info.processName;return processName;}} catch (Exception e) {// Log.d("Process", "Error>> :"+ e.toString());}}return processName;}
}

#### e. 注册和登陆 ####

注册要在子线程中执行

//注册失败会抛出HyphenateException
EMClient.getInstance().createAccount(username, pwd);//同步方法EMClient.getInstance().login(userName,password,new EMCallBack() {//回调@Overridepublic void onSuccess() {EMClient.getInstance().groupManager().loadAllGroups();EMClient.getInstance().chatManager().loadAllConversations();Log.d("main", "登录聊天服务器成功!");        }@Overridepublic void onProgress(int progress, String status) {}@Overridepublic void onError(int code, String message) {Log.d("main", "登录聊天服务器失败!");}
});

#### f. 发送消息 ####

//创建一条文本消息,content为消息文字内容,toChatUsername为对方用户或者群聊的id,后文皆是如此
EMMessage message = EMMessage.createTxtSendMessage(content, toChatUsername);
//发送消息
EMClient.getInstance().chatManager().sendMessage(message);

#### g. 接收消息 ####

msgListener = new EMMessageListener() {@Overridepublic void onMessageReceived(List<EMMessage> messages) {//收到消息String result = messages.get(0).getBody().toString();String msgReceived = result.substring(5, result.length() - 1);Log.i(TAG, "onMessageReceived: " + msgReceived);final MSG msg = new MSG(msgReceived, MSG.TYPE_RECEIVED);runOnUiThread(new Runnable() {@Overridepublic void run() {mList.add(msg);mAdapter.notifyDataSetChanged();mRecyclerView.scrollToPosition(mList.size() - 1);}});}@Overridepublic void onCmdMessageReceived(List<EMMessage> messages) {//收到透传消息}@Overridepublic void onMessageRead(List<EMMessage> list) {}@Overridepublic void onMessageDelivered(List<EMMessage> list) {}@Overridepublic void onMessageChanged(EMMessage message, Object change) {//消息状态变动}};

接收消息的监听器分别需要在OnResume()和OnDestory()方法中注册和取消注册

EMClient.getInstance().chatManager().addMessageListener(msgListener);//注册EMClient.getInstance().chatManager().removeMessageListener(msgListener);//取消注册

需要注意的是,当接收到消息,需要在主线程中更新适配器,否则会不能及时刷新出来

项目文件截图:


到此,一个简单的及时聊天Demo已经完成,功能很简单,如果需要添加额外功能的话,可以自行参考官网,官网给出的教程还是很不错的!

最后希望大家能多多支持我,需要你们的支持喜欢!!
基于环信的仿QQ即时通讯的简单实现

代码地址如下:
http://www.demodashi.com/demo/11645.html

注:本文著作权归作者,由demo大师代发,拒绝转载,转载需要作者授权

基于环信的仿QQ即时通讯的简单实现相关推荐

  1. mob sdk vue 短信验证_基于环信SDK的IM即时通讯填坑之路(vue)

    1.这里如果注册异常的type==17则代表已注册,那就直接去登录 2.这里id是依据是否在应用内已登录(自己应用,非环信), 如果是未登录(游客状态)则随机一个 Math.ceil(Math.ran ...

  2. Android基于环信SDK开发IM即时聊天(一)

    2016-09-02更新:可以看一下最新的这篇文章和源码,Android基于环信SDK开发IM即时聊天(二) 目前市面上我了解的做第三方即时聊天SDK的有两家:环信.融云,这里我使用环信SDK来完成即 ...

  3. Android基于环信SDK开发IM即时聊天(二)

    声明1:北京时间现在是2019/6/10,评论里的问题我看到了,这几天我找时间看看源代码问题出在哪,在此感谢大家的监督 声明2:此Demo我是在5.1测试机上测试通过,感谢WTQ_DOMIAN的评论, ...

  4. winform服务器消息推送,winform项目——仿QQ即时通讯程序12:服务端程序补充及优化...

    原标题:winform项目--仿QQ即时通讯程序12:服务端程序补充及优化 上一篇文章大概完成了服务端程序,今天继续做项目的时候发现还有一些功能没有做,还有几处地方不够完善.不做好就会影响客户端程序的 ...

  5. 环信开源计划开启即时通讯云开源平台时代

    12月22日,在"首届移动社交创新价值峰会"上,环信即时通讯云(http://www.easemob.com)发布了被称为"4X100计划"的<环信开源平 ...

  6. android 第三方 im,Android基于环信SDK开发IM即时聊天

    目前市面上我了解的做第三方即时聊天SDK的有两家:环信.融云,这里我使用环信SDK来完成即时聊天的初步开发工作. 下面先奉上1张效果图: 1.开发准备 首先要到环信官网注册开发者账号,目前只有企业账号 ...

  7. 环信sdk android 聊天,Android基于环信SDK开发IM即时聊天

    根据用户移动地图的位置,显示在视野范围内的建筑物,简单的思路是,添加地图监听,当地图移动结束之后,计算出当前屏幕四个角的GeoPoint,根据这4个点,通过mys 目前市面上我了解的做第三方即时聊天S ...

  8. 【181029】FreeEIM 飞鸽传书仿QQ即时通讯软件VC++源代码

    FreeEIM 仿QQ功能的企业即时通讯软件VC++的源代码,最后更新于2010年8月份,完成数据库更改的任务.将聊天记录改用数据库形式,暂且使用Access. 本软件的窗口和功能都与QQ有点相似,可 ...

  9. C++实现飞鸽传书仿QQ即时通讯软件!(源码打包好了!)

    FreeEIM 仿QQ功能的企业即时通讯软件VC++的源代码,最后更新于2010年8月份,完成数据库更改的任务.将聊天记录改用数据库形式,暂且使用Access. 本软件的窗口和功能都与QQ有点相似,可 ...

最新文章

  1. java 贝叶斯抠图_贝叶斯抠图
  2. CentOS7.0重置Root的密码
  3. 多人在线游戏服务器端开发心得(转)
  4. hdu 5077 NAND(打表)2014 Asia regional 鞍山站 H题
  5. unix环境高级编程——文件i/o
  6. Android学习之Shared Preference
  7. 789. 逃脱阻碍者
  8. 心理学家、实验与效应
  9. ELK filebeat和logstash使用:配置单个文件来源、配置多个文件来源
  10. 【world_to_pixel】【wcs_pix2world】世界坐标系和像素坐标系的两种转换方式
  11. Kotlin typealias属性
  12. 如何在WPS2000中插入AutoCad图形文件(转)
  13. 解决:另一个 SqlParameterCollection 中已包含 SqlParameter。
  14. 电商后台管理系统-权限管理模块
  15. ZEMAX光学设计实践
  16. 计算机出错英语翻译,计算机各种错误信息翻译
  17. 没有50W彩礼 女友被强行拽走。Python分析全国彩礼情况,心凉了。
  18. python太极代码_Python : Turtle绘图-太极图(代码)
  19. 路由器交换机设备管理
  20. Unity中使用另一个遮罩方案解决Mask组件的锯齿现象

热门文章

  1. iOS学习系列 - 标签Tag列表的实现
  2. [Visual Stuido SDK] VSPackages
  3. 今天去医院拿宝宝的微量元素检查结果
  4. 使用遇到的问题_聚氯化铝在使用过程中遇到的问题及解决方法
  5. matlab光学远轴光的折射,光学课后习题
  6. 主线程 唤醒_Java等待唤醒机制统计子线程运行时间的方式及其疑问
  7. ul去掉li前面的点_一年级语文上册期末考点:拼音重、难点总结,全面,建议收藏...
  8. Java实现基数排序及其推导过程 Radix Sort
  9. 安装 | Matlab2022a下载及新功能一览
  10. 北斗导航 | 卫星导航基础知识(卫星导航时间系统)