环信SDK调用实现即时聊天功能


最近在做个项目,需要用到即时通信的功能,选定了环信的IM云来实现,关于环信IM的SDK接口,自己研究了一天,基本的功能实现了一下,这里PO出来demo。

因为只是为了验证sdk的实现,所以界面设计的比较丑,还请谅解。还有,只用到了文本消息,所以选取的sdk版本是2.X。


具体的下载链接见文末。


先上图

环信SDK调用实现即时聊天功能_第1张图片


首先是一张消息列表,列表中的项目包括用户头像、用户名和最后一条消息显示。

第二张是会话,简单点来写,每一个项的list view的adapter都没有设置,只是简单的显示消息。点击button向对方发送“呵呵呵”的消息。

下面来阐述详细的实现。



step 1: 在manifest文件中添加users-permission 和appkey的service

这里的permission内容可以从环信文档中获取,大致如下

   <!-- 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" />

另外的service需要的apply如下,这里选取的是环信提供的默认appkey

<!-- 设置环信应用的appkey -->
    	<meta-data android:name="EASEMOB_APPKEY"  android:value="easemob-demo#chatdemoui" />
    	<!-- 声明sdk所需的service SDK核心功能-->
    	<service android:name="com.easemob.chat.EMChatService" />

然后将sdk文件复制到libs文件夹中即可。这样就完成了SDK的导入工作


step 2: 环信账号登录

在登录之前,要在主的application文件中加上一条语句:

EMChat.getInstance().init(this);
保证app在首次打开时就初始化EMChat实例

然后,登录环信账号,这里需要用到当前的appkey注册到的账号和密码,我自己注册的测试用例的登录过程如下:

package com.example.demo;

import com.easemob.EMCallBack;
import com.easemob.chat.EMChatManager;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends Activity {
	
	public static final String UA = "blyang";
	public static final String PA = "bing";

	public static final String UB = "yangbingliang";
	public static final String PB = "bing";

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		login(UA, PA);
		
	}
	
	private void login(String userName, String password){
		EMChatManager.getInstance().login(userName, password, new EMCallBack(){

			@Override
			public void onError(int arg0, String arg1) {
				
				Toast.makeText(MainActivity.this, "error", Toast.LENGTH_LONG).show();
			}

			@Override
			public void onProgress(int arg0, String arg1) {
				// TODO Auto-generated method stub
			}

			@Override
			public void onSuccess() {
				// TODO Auto-generated method stub
				runOnUiThread(new Runnable(){
					@Override
					public void run() {
						Toast.makeText(MainActivity.this, "success", Toast.LENGTH_LONG).show();						
					}
				});
				
				//从本地DB加载到程序中
				EMChatManager.getInstance().loadAllConversations();
				startActivity(new Intent(MainActivity.this, Container.class));
				finish();
				
			}
			
		});
	}

}

登录的过程就是调用EMChatManager来实现,登录成功后,进行相关的操作。这里在登录成功后,加入了一句:

//从本地DB加载到程序中
EMChatManager.getInstance().loadAllConversations();
是为了保证从本地数据库中取出历史所有的conversation对象并加载出来


step 3: 将历史对话数据加载成消息列表的形式

首先创建一个conversationList 的List对象,然后将最近的所有会话添加到这个list中,最后,调用消息列表展示到adapter,将数据传入并展示出来。具体到代码和注释如下:

package com.example.demo;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Hashtable;
import java.util.List;

import com.easemob.chat.EMChatManager;
import com.easemob.chat.EMConversation;

import android.app.Fragment;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;

public class ChatHistoryFragment extends Fragment{
	
	//所有的会话列表
	private List<EMConversation> conversationList = new ArrayList<EMConversation>();
	
	ChatHistoryAdapter adapter ;
	ListView chatHistoryListView;
	View view;
	
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		
		view = inflater.inflate(R.layout.fragment_conversation_history, container, false);
		return view;
		
	}
	
	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);
		
		
		conversationList.addAll(loadConversationWithRecentChat());
	
		chatHistoryListView = (ListView) view.findViewById(R.id.list);
		
		adapter = new ChatHistoryAdapter(getActivity(), conversationList);
		chatHistoryListView.setAdapter(adapter);
		
		
		chatHistoryListView.setOnItemClickListener(new OnItemClickListener(){

			@Override
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
				EMConversation conversation = (EMConversation) adapter.getItem(position);
				Intent intent = new Intent(getActivity(), Conversation.class);
				intent.putExtra("userName", conversation.getUserName());
				startActivity(intent);
			}
			
		});
		
		
		int count = 0;
		for(int i=0; i<conversationList.size(); i++){
			count += conversationList.get(i).getUnreadMsgCount();
		}
		Log.v("count total", count+"");
		
		
	}
	
	
	/**
	 * 获取所有会话
	 * @return
	 */
	private Collection<? extends EMConversation> loadConversationWithRecentChat() {
		Hashtable<String, EMConversation> conversations = EMChatManager
				.getInstance().getAllConversations();
		
		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{
			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 sortList
	 */
	private void sortConversationByLastChatTime(
			List<Pair<Long, EMConversation>> sortList) {
		Collections.sort(sortList, new Comparator<Pair<Long, EMConversation>>(){

			@Override
			public int compare(Pair<Long, EMConversation> con1,
					Pair<Long, EMConversation> con2) {
				if(con1.first == con2.first){
					return 0;
				}else if(con2.first > con1.first){
					return 1;
				}else{
					return -1;	
				}
			}
		});
	}

	public void refresh(){
		conversationList.clear();
		conversationList.addAll(loadConversationWithRecentChat());
		if(adapter != null){
			adapter.notifyDataSetChanged();
		}
	}
	
	@Override
	public void onResume() {
		super.onResume();
		refresh();
	}

}

这样就完成了消息列表的展示


step 4:进入会话列表

当消息列表展示之后,要在每一个listitem被点击之后进入具体的会话展示区,也就是上图二。

在会话区,首先要注册一个广播监听器,用于接收信息(注意,如果不注册,是无法实时接收信息的)。然后当接收到信息的时候,刷新页面。在离开会话页面的时候,销毁这个广播注册即可。具体的代码和注释如下:

package com.example.demo;

import com.easemob.EMCallBack;
import com.easemob.chat.EMChat;
import com.easemob.chat.EMChatManager;
import com.easemob.chat.EMConversation;
import com.easemob.chat.EMMessage;
import com.easemob.chat.EMMessage.ChatType;
import com.easemob.chat.TextMessageBody;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;

public class Conversation extends Activity{
	
	ListView listView;
	Button button;
	
	private EMConversation conversation;
	
	private ConversationAdapter adapter;
	
	NewMessageBroadcastReceiver msgReceiver; //广播监听器,用于接收消息
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.conversation);
		
		listView = (ListView) findViewById(R.id.conversation_list);
		button = (Button) findViewById(R.id.conversation_btn);
		
		conversation = EMChatManager.getInstance()
				.getConversation(getIntent().getExtras().get("userName").toString());
		
		adapter = new ConversationAdapter(Conversation.this, conversation);
		listView.setAdapter(adapter);
		listView.setSelection(listView.getCount() - 1 );
		
		
		
		registerBroadcast();  //注册广播接收消息
		EMChat.getInstance().setAppInited();  //注册完广播之后,一定要声明这一句
		
		sendMsg();  //发送文本消息
		
		
	}
	
	
	
	/**
	 * 注册一个接收消息的广播
	 */
	private void registerBroadcast(){
		//只有注册了广播才能接收到新消息,目前离线消息,在线消息都是走接收消息的广播(离线消息目前无法监听,在登录以后,接收消息广播会执行一次拿到所有的离线消息)
		msgReceiver = new NewMessageBroadcastReceiver();
		IntentFilter intentFilter = new IntentFilter(EMChatManager.getInstance().getNewMessageBroadcastAction());
		intentFilter.setPriority(3);
		registerReceiver(msgReceiver, intentFilter);
		
//		this.unregisterReceiver(msgReceiver);
	}
	
	
	private class NewMessageBroadcastReceiver extends BroadcastReceiver {
		@Override
		public void onReceive(Context context, Intent intent) {
		    // 注销广播
			abortBroadcast();
	 
			// 消息id(每条消息都会生成唯一的一个id,目前是SDK生成)
			String msgId = intent.getStringExtra("msgid");
			//发送方
			String username = intent.getStringExtra("from");
			// 收到这个广播的时候,message已经在db和内存里了,可以通过id获取mesage对象
			EMMessage message = EMChatManager.getInstance().getMessage(msgId);
			
			if (!username.equals(username)) {
				// 消息不是发给当前会话,return
				return;
			}
			
			conversation.addMessage(message);
			adapter.notifyDataSetChanged();
			listView.setAdapter(adapter);
			listView.setSelection(listView.getCount() - 1);
			
		}
	}
	
	
	/**
	 * 发送文本消息
	 */
	private void sendMsg(){
		button.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				//获取到与聊天人的会话对象。参数username为聊天人的userid或者groupid,后文中的username皆是如此
				EMConversation conversation = EMChatManager.getInstance().getConversation(MainActivity.UB);
				//创建一条文本消息
				EMMessage message = EMMessage.createSendMessage(EMMessage.Type.TXT);
				//设置消息body
				TextMessageBody txtBody = new TextMessageBody("呵呵呵");
				message.addBody(txtBody);
				//设置接收人
				message.setReceipt(MainActivity.UB);
				//把消息加入到此会话对象中
				conversation.addMessage(message);
				
				adapter.notifyDataSetChanged();
				listView.setAdapter(adapter);
				listView.setSelection(listView.getCount() - 1);
				
				//发送消息
				EMChatManager.getInstance().sendMessage(message, new EMCallBack(){

					@Override
					public void onError(int arg0, String arg1) {
						
					}

					@Override
					public void onProgress(int arg0, String arg1) {
						
					}

					@Override
					public void onSuccess() {
						
					}});
				
				
			}
		});
		
	}
	
	
	@Override
	protected void onDestroy() {
		super.onDestroy();
		
		/**
		 * 当前Activity销毁的时候,标记所有信息为已读
		 * 销毁广播
		 */
		conversation.markAllMessagesAsRead();
		this.unregisterReceiver(msgReceiver);
		
	}
	
	
}

当然,这里涉及到list view的adapter,就不详细阐述了,有需求的同学请自行看代码,这里给一个下载链接:


http://download.csdn.net/detail/sinat_22013331/9471469














你可能感兴趣的:(环信SDK调用实现即时聊天功能)