环信官方Demo源码分析及SDK简单应用-主界面的三个fragment-会话界面
环信官方Demo源码分析及SDK简单应用
环信官方Demo源码分析及SDK简单应用-ChatDemoUI3.0
环信官方Demo源码分析及SDK简单应用-LoginActivity
环信官方Demo源码分析及SDK简单应用-主界面的三个fragment-会话界面
环信官方Demo源码分析及SDK简单应用-主界面的三个fragment-通讯录界面
环信官方Demo源码分析及SDK简单应用-主界面的三个fragment-设置界面
环信官方Demo源码分析及SDK简单应用-EaseUI
环信官方Demo源码分析及SDK简单应用-IM集成开发详案及具体代码实现
现在来看具体的主界面的三个Fragment
主界面的三个fragment
会话界面
我们来看会话界面的代码
EaseBaseFragment
看到inputmethdManager要干嘛啊,隐藏键盘。果不其然。
初始化标题头
隐藏和显示标题头
其中还提供了两个方法,隐藏和显示标题头
EaseConversationListFragment
我们来看代码
首先onCreateView(),正常的填充了布局
覆写爷爷的家规,初始化View输入法管理器
我们接着看其他的方法
删除消息并更新未读消息。
好,至此,第一个界面,会话界面到此结束。
我们再来看通讯录界面。
环信官方Demo源码分析及SDK简单应用-主界面的三个fragment-通讯录界面
环信官方Demo源码分析及SDK简单应用-ChatDemoUI3.0
环信官方Demo源码分析及SDK简单应用-LoginActivity
环信官方Demo源码分析及SDK简单应用-主界面的三个fragment-会话界面
环信官方Demo源码分析及SDK简单应用-主界面的三个fragment-通讯录界面
环信官方Demo源码分析及SDK简单应用-主界面的三个fragment-设置界面
环信官方Demo源码分析及SDK简单应用-EaseUI
环信官方Demo源码分析及SDK简单应用-IM集成开发详案及具体代码实现
现在来看具体的主界面的三个Fragment
主界面的三个fragment
会话界面
我们来看会话界面的代码
我们还是挨个来读代码
package com.hyphenate.chatuidemo.ui;
import android.content.Intent;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.easemob.redpacketsdk.constant.RPConstant;
import com.hyphenate.chat.EMClient;
import com.hyphenate.chat.EMConversation;
import com.hyphenate.chat.EMConversation.EMConversationType;
import com.hyphenate.chat.EMMessage;
import com.hyphenate.chatuidemo.Constant;
import com.hyphenate.chatuidemo.R;
import com.hyphenate.chatuidemo.db.InviteMessgeDao;
import com.hyphenate.easeui.model.EaseAtMessageHelper;
import com.hyphenate.easeui.ui.EaseConversationListFragment;
import com.hyphenate.easeui.widget.EaseConversationList.EaseConversationListHelper;
import com.hyphenate.util.NetUtils;
public class ConversationListFragment extends EaseConversationListFragment{
private TextView errorText;
@Override
protected void initView() {
super.initView();
View errorView = (LinearLayout) View.inflate(getActivity(),R.layout.em_chat_neterror_item, null);
errorItemContainer.addView(errorView);
errorText = (TextView) errorView.findViewById(R.id.tv_connect_errormsg);
}
@Override
protected void setUpView() {
super.setUpView();
// register context menu
registerForContextMenu(conversationListView);
conversationListView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
EMConversation conversation = conversationListView.getItem(position);
String username = conversation.conversationId();
if (username.equals(EMClient.getInstance().getCurrentUser()))
Toast.makeText(getActivity(), R.string.Cant_chat_with_yourself, Toast.LENGTH_SHORT).show();
else {
// start chat acitivity
Intent intent = new Intent(getActivity(), ChatActivity.class);
if(conversation.isGroup()){
if(conversation.getType() == EMConversationType.ChatRoom){
// it's group chat
intent.putExtra(Constant.EXTRA_CHAT_TYPE, Constant.CHATTYPE_CHATROOM);
}else{
intent.putExtra(Constant.EXTRA_CHAT_TYPE, Constant.CHATTYPE_GROUP);
}
}
// it's single chat
intent.putExtra(Constant.EXTRA_USER_ID, username);
startActivity(intent);
}
}
});
//red packet code : 红包回执消息在会话列表最后一条消息的展示
conversationListView.setConversationListHelper(new EaseConversationListHelper() {
@Override
public String onSetItemSecondaryText(EMMessage lastMessage) {
if (lastMessage.getBooleanAttribute(RPConstant.MESSAGE_ATTR_IS_RED_PACKET_ACK_MESSAGE, false)) {
String sendNick = lastMessage.getStringAttribute(RPConstant.EXTRA_RED_PACKET_SENDER_NAME, "");
String receiveNick = lastMessage.getStringAttribute(RPConstant.EXTRA_RED_PACKET_RECEIVER_NAME, "");
String msg;
if (lastMessage.direct() == EMMessage.Direct.RECEIVE) {
msg = String.format(getResources().getString(R.string.msg_someone_take_red_packet), receiveNick);
} else {
if (sendNick.equals(receiveNick)) {
msg = getResources().getString(R.string.msg_take_red_packet);
} else {
msg = String.format(getResources().getString(R.string.msg_take_someone_red_packet), sendNick);
}
}
return msg;
} else if (lastMessage.getBooleanAttribute(RPConstant.MESSAGE_ATTR_IS_TRANSFER_PACKET_MESSAGE, false)) {
String transferAmount = lastMessage.getStringAttribute(RPConstant.EXTRA_TRANSFER_AMOUNT, "");
String msg;
if (lastMessage.direct() == EMMessage.Direct.RECEIVE) {
msg = String.format(getResources().getString(R.string.msg_transfer_to_you), transferAmount);
} else {
msg = String.format(getResources().getString(R.string.msg_transfer_from_you),transferAmount);
}
return msg;
}
return null;
}
});
super.setUpView();
//end of red packet code
}
@Override
protected void onConnectionDisconnected() {
super.onConnectionDisconnected();
if (NetUtils.hasNetwork(getActivity())){
errorText.setText(R.string.can_not_connect_chat_server_connection);
} else {
errorText.setText(R.string.the_current_network);
}
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
getActivity().getMenuInflater().inflate(R.menu.em_delete_message, menu);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
boolean deleteMessage = false;
if (item.getItemId() == R.id.delete_message) {
deleteMessage = true;
} else if (item.getItemId() == R.id.delete_conversation) {
deleteMessage = false;
}
EMConversation tobeDeleteCons = conversationListView.getItem(((AdapterContextMenuInfo) item.getMenuInfo()).position);
if (tobeDeleteCons == null) {
return true;
}
if(tobeDeleteCons.getType() == EMConversationType.GroupChat){
EaseAtMessageHelper.get().removeAtMeGroup(tobeDeleteCons.conversationId());
}
try {
// delete conversation
EMClient.getInstance().chatManager().deleteConversation(tobeDeleteCons.conversationId(), deleteMessage);
InviteMessgeDao inviteMessgeDao = new InviteMessgeDao(getActivity());
inviteMessgeDao.deleteMessage(tobeDeleteCons.conversationId());
} catch (Exception e) {
e.printStackTrace();
}
refresh();
// update unread count
((MainActivity) getActivity()).updateUnreadLabel();
return true;
}
}
public class ConversationListFragment extends EaseConversationListFragment来,我们还是得先去找他爹算账。
public class EaseConversationListFragment extends EaseBaseFragment哎呀,我们再去找他爷爷。
public abstract class EaseBaseFragment extends Fragment爷爷终于正常点是从Android系统类继承下来的了,我们看具体的代码
EaseBaseFragment
package com.hyphenate.easeui.ui;我们还是挨个来看代码,研究他的功能。
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import com.hyphenate.easeui.R;
import com.hyphenate.easeui.widget.EaseTitleBar;
public abstract class EaseBaseFragment extends Fragment{
protected EaseTitleBar titleBar;
protected InputMethodManager inputMethodManager;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
inputMethodManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
//noinspection ConstantConditions
titleBar = (EaseTitleBar) getView().findViewById(R.id.title_bar);
initView();
setUpView();
}
public void showTitleBar(){
if(titleBar != null){
titleBar.setVisibility(View.VISIBLE);
}
}
public void hideTitleBar(){
if(titleBar != null){
titleBar.setVisibility(View.GONE);
}
}
protected 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);
}
}
protected abstract void initView();
protected abstract void setUpView();
}
@Override隐藏输入法
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
inputMethodManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
//noinspection ConstantConditions
titleBar = (EaseTitleBar) getView().findViewById(R.id.title_bar);
initView();
setUpView();
}
看到inputmethdManager要干嘛啊,隐藏键盘。果不其然。
protected 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);
}
}
初始化标题头
//noinspection ConstantConditions最后初始化标题头,并且让子孙们去实现抽象方法initView和setUpView().
titleBar = (EaseTitleBar) getView().findViewById(R.id.title_bar);
隐藏和显示标题头
其中还提供了两个方法,隐藏和显示标题头
public void showTitleBar(){好了,爷爷的帐算完了,我们来找他儿子。
if(titleBar != null){
titleBar.setVisibility(View.VISIBLE);
}
}
public void hideTitleBar(){
if(titleBar != null){
titleBar.setVisibility(View.GONE);
}
}
EaseConversationListFragment
我们来看代码
package com.hyphenate.easeui.ui;填充布局
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import com.hyphenate.EMConnectionListener;
import com.hyphenate.EMConversationListener;
import com.hyphenate.EMError;
import com.hyphenate.chat.EMClient;
import com.hyphenate.chat.EMConversation;
import com.hyphenate.easeui.R;
import com.hyphenate.easeui.widget.EaseConversationList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
/**
* conversation list fragment
*
*/
public class EaseConversationListFragment extends EaseBaseFragment{
private final static int MSG_REFRESH = 2;
protected EditText query;
protected ImageButton clearSearch;
protected boolean hidden;
protected List<EMConversation> conversationList = new ArrayList<EMConversation>();
protected EaseConversationList conversationListView;
protected FrameLayout errorItemContainer;
protected boolean isConflict;
protected EMConversationListener convListener = new EMConversationListener(){
@Override
public void onCoversationUpdate() {
refresh();
}
};
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.ease_fragment_conversation_list, container, false);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
if(savedInstanceState != null && savedInstanceState.getBoolean("isConflict", false))
return;
super.onActivityCreated(savedInstanceState);
}
@Override
protected void initView() {
inputMethodManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
conversationListView = (EaseConversationList) getView().findViewById(R.id.list);
query = (EditText) getView().findViewById(R.id.query);
// button to clear content in search bar
clearSearch = (ImageButton) getView().findViewById(R.id.search_clear);
errorItemContainer = (FrameLayout) getView().findViewById(R.id.fl_error_item);
}
@Override
protected void setUpView() {
conversationList.addAll(loadConversationList());
conversationListView.init(conversationList);
if(listItemClickListener != null){
conversationListView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
EMConversation conversation = conversationListView.getItem(position);
listItemClickListener.onListItemClicked(conversation);
}
});
}
EMClient.getInstance().addConnectionListener(connectionListener);
query.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence s, int start, int before, int count) {
conversationListView.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();
}
});
conversationListView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
hideSoftKeyboard();
return false;
}
});
}
protected EMConnectionListener connectionListener = new EMConnectionListener() {
@Override
public void onDisconnected(int error) {
if (error == EMError.USER_REMOVED || error == EMError.USER_LOGIN_ANOTHER_DEVICE || error == EMError.SERVER_SERVICE_RESTRICTED) {
isConflict = true;
} else {
handler.sendEmptyMessage(0);
}
}
@Override
public void onConnected() {
handler.sendEmptyMessage(1);
}
};
private EaseConversationListItemClickListener listItemClickListener;
protected Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case 0:
onConnectionDisconnected();
break;
case 1:
onConnectionConnected();
break;
case MSG_REFRESH:
{
conversationList.clear();
conversationList.addAll(loadConversationList());
conversationListView.refresh();
break;
}
default:
break;
}
}
};
/**
* connected to server
*/
protected void onConnectionConnected(){
errorItemContainer.setVisibility(View.GONE);
}
/**
* disconnected with server
*/
protected void onConnectionDisconnected(){
errorItemContainer.setVisibility(View.VISIBLE);
}
/**
* refresh ui
*/
public void refresh() {
if(!handler.hasMessages(MSG_REFRESH)){
handler.sendEmptyMessage(MSG_REFRESH);
}
}
/**
* load conversation list
*
* @return
+ */
protected List<EMConversation> loadConversationList(){
// get all conversations
Map<String, EMConversation> conversations = EMClient.getInstance().chatManager().getAllConversations();
List<Pair<Long, EMConversation>> sortList = new ArrayList<Pair<Long, EMConversation>>();
/**
* lastMsgTime will change if there is new message during sorting
* so use synchronized to make sure timestamp of last message won't change.
*/
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;
}
/**
* sort conversations according time stamp of last message
*
* @param conversationList
*/
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.equals(con2.first)) {
return 0;
} else if (con2.first.longValue() > con1.first.longValue()) {
return 1;
} else {
return -1;
}
}
});
}
protected 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);
}
}
@Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
this.hidden = hidden;
if (!hidden && !isConflict) {
refresh();
}
}
@Override
public void onResume() {
super.onResume();
if (!hidden) {
refresh();
}
}
@Override
public void onDestroy() {
super.onDestroy();
EMClient.getInstance().removeConnectionListener(connectionListener);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if(isConflict){
outState.putBoolean("isConflict", true);
}
}
public interface EaseConversationListItemClickListener {
/**
* click event for conversation list
* @param conversation -- clicked item
*/
void onListItemClicked(EMConversation conversation);
}
/**
* set conversation list item click listener
* @param listItemClickListener
*/
public void setConversationListItemClickListener(EaseConversationListItemClickListener listItemClickListener){
this.listItemClickListener = listItemClickListener;
}
}
首先onCreateView(),正常的填充了布局
return inflater.inflate(R.layout.ease_fragment_conversation_list, container, false);继续看代码
判断冲突标志位
@Override
public void onActivityCreated(Bundle savedInstanceState) {
if(savedInstanceState != null && savedInstanceState.getBoolean("isConflict", false))
return;
super.onActivityCreated(savedInstanceState);
}
@OverrideinitView()
protected void initView() {
inputMethodManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
conversationListView = (EaseConversationList) getView().findViewById(R.id.list);
query = (EditText) getView().findViewById(R.id.query);
// button to clear content in search bar
clearSearch = (ImageButton) getView().findViewById(R.id.search_clear);
errorItemContainer = (FrameLayout) getView().findViewById(R.id.fl_error_item);
}
覆写爷爷的家规,初始化View输入法管理器
- 会话列表List
- 查找联系人的输入框
- 清除搜索的按钮
- errorItemContainer 错误标签容器
conversationList.addAll(loadConversationList());conversationListView.init(conversationList);if(listItemClickListener != null){ conversationListView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { EMConversation conversation = conversationListView.getItem(position); listItemClickListener.onListItemClicked(conversation); } });}EMClient.getInstance().addConnectionListener(connectionListener);query.addTextChangedListener(new TextWatcher() { public void onTextChanged(CharSequence s, int start, int before, int count) { conversationListView.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(); }});conversationListView.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { hideSoftKeyboard(); return false; }});我们一句句的看
conversationList.addAll(loadConversationList()); conversationListView.init(conversationList);会话列表添加全部以及数据填充初始化。我们来看具体的方法
/** * load conversation list * * @return */protected List<EMConversation> loadConversationList(){ // get all conversations Map<String, EMConversation> conversations = EMClient.getInstance().chatManager().getAllConversations(); List<Pair<Long, EMConversation>> sortList = new ArrayList<Pair<Long, EMConversation>>(); /** * lastMsgTime will change if there is new message during sorting * so use synchronized to make sure timestamp of last message won't change. */ 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;}loadConversationList()返回一个EMConversation对象List。
// get all conversationsMap<String, EMConversation> conversations = EMClient.getInstance().chatManager().getAllConversations();List<Pair<Long, EMConversation>> sortList = new ArrayList<Pair<Long, EMConversation>>();通过封装的chatManager拿到所有的会话列表
/** * lastMsgTime will change if there is new message during sorting * so use synchronized to make sure timestamp of last message won't change. */synchronized (conversations) { for (EMConversation conversation : conversations.values()) { if (conversation.getAllMessages().size() != 0) { sortList.add(new Pair<Long, EMConversation>(conversation.getLastMessage().getMsgTime(), conversation)); } }}lastMsgTime会随着新消息的到来排序发生改变,所以我们用同步方法确保最新消息的时间戳不发生改变。英文不好,大致是这么个意思。
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;其中还特地注释了一把,算法有点bug。
/** * sort conversations according time stamp of last message * * @param conversationList */ 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.equals(con2.first)) { return 0; } else if (con2.first.longValue() > con1.first.longValue()) { return 1; } else { return -1; } } });根据最新的会话时间戳来排序。我们接着看
List<EMConversation> list = new ArrayList<EMConversation>();for (Pair<Long, EMConversation> sortItem : sortList) { list.add(sortItem.second);}return list;添加完了返回list。
conversationListView.init(conversationList);接着就初始化了。
if(listItemClickListener != null){ conversationListView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { EMConversation conversation = conversationListView.getItem(position); listItemClickListener.onListItemClicked(conversation); } });}然后便是连接接听
EMClient.getInstance().addConnectionListener(connectionListener);添加了一个连接的监听。
protected EMConnectionListener connectionListener = new EMConnectionListener() { @Override public void onDisconnected(int error) { if (error == EMError.USER_REMOVED || error == EMError.USER_LOGIN_ANOTHER_DEVICE || error == EMError.SERVER_SERVICE_RESTRICTED) { isConflict = true; } else { handler.sendEmptyMessage(0); } } @Override public void onConnected() { handler.sendEmptyMessage(1); }};在断开连接时判断用户是否移除,是否在其他设备登陆,或者服务端的服务受到限制,是的话则标记冲突。不是则发送handler空消息。
protected Handler handler = new Handler(){ public void handleMessage(android.os.Message msg) { switch (msg.what) { case 0: onConnectionDisconnected(); break; case 1: onConnectionConnected(); break; case MSG_REFRESH: { conversationList.clear(); conversationList.addAll(loadConversationList()); conversationListView.refresh(); break; } default: break; } }};干嘛啊?调用 onConnectionDisconnected 即连接断开的处理方法
/** * disconnected with server */protected void onConnectionDisconnected(){ errorItemContainer.setVisibility(View.VISIBLE);}即显示错误条。我们再接着看代码
query.addTextChangedListener(new TextWatcher() { public void onTextChanged(CharSequence s, int start, int before, int count) { conversationListView.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(); }});conversationListView.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { hideSoftKeyboard(); return false; }});干了些什么啊?查询、清除搜索、会话列表点击监听。其他方法
/** * connected to server */protected void onConnectionConnected(){ errorItemContainer.setVisibility(View.GONE);}连接后将错误条隐藏
case MSG_REFRESH: { conversationList.clear(); conversationList.addAll(loadConversationList()); conversationListView.refresh(); break; }服务器告诉要刷新了,那么我们就去清楚列表,然后去服务器拿并排序,然后刷新listview。其中该listview为自定义的EaseConversationList。那么儿子齐活了,我们再看孙子ConversationListFragment
package com.hyphenate.chatuidemo.ui;import android.content.Intent;import android.view.ContextMenu;import android.view.ContextMenu.ContextMenuInfo;import android.view.MenuItem;import android.view.View;import android.widget.AdapterView;import android.widget.AdapterView.AdapterContextMenuInfo;import android.widget.AdapterView.OnItemClickListener;import android.widget.LinearLayout;import android.widget.TextView;import android.widget.Toast;import com.easemob.redpacketsdk.constant.RPConstant;import com.hyphenate.chat.EMClient;import com.hyphenate.chat.EMConversation;import com.hyphenate.chat.EMConversation.EMConversationType;import com.hyphenate.chat.EMMessage;import com.hyphenate.chatuidemo.Constant;import com.hyphenate.chatuidemo.R;import com.hyphenate.chatuidemo.db.InviteMessgeDao;import com.hyphenate.easeui.model.EaseAtMessageHelper;import com.hyphenate.easeui.ui.EaseConversationListFragment;import com.hyphenate.easeui.widget.EaseConversationList.EaseConversationListHelper;import com.hyphenate.util.NetUtils;public class ConversationListFragment extends EaseConversationListFragment{ private TextView errorText; @Override protected void initView() { super.initView(); View errorView = (LinearLayout) View.inflate(getActivity(),R.layout.em_chat_neterror_item, null); errorItemContainer.addView(errorView); errorText = (TextView) errorView.findViewById(R.id.tv_connect_errormsg); } @Override protected void setUpView() { super.setUpView(); // register context menu registerForContextMenu(conversationListView); conversationListView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { EMConversation conversation = conversationListView.getItem(position); String username = conversation.conversationId(); if (username.equals(EMClient.getInstance().getCurrentUser())) Toast.makeText(getActivity(), R.string.Cant_chat_with_yourself, Toast.LENGTH_SHORT).show(); else { // start chat acitivity Intent intent = new Intent(getActivity(), ChatActivity.class); if(conversation.isGroup()){ if(conversation.getType() == EMConversationType.ChatRoom){ // it's group chat intent.putExtra(Constant.EXTRA_CHAT_TYPE, Constant.CHATTYPE_CHATROOM); }else{ intent.putExtra(Constant.EXTRA_CHAT_TYPE, Constant.CHATTYPE_GROUP); } } // it's single chat intent.putExtra(Constant.EXTRA_USER_ID, username); startActivity(intent); } } }); //red packet code : 红包回执消息在会话列表最后一条消息的展示 conversationListView.setConversationListHelper(new EaseConversationListHelper() { @Override public String onSetItemSecondaryText(EMMessage lastMessage) { if (lastMessage.getBooleanAttribute(RPConstant.MESSAGE_ATTR_IS_RED_PACKET_ACK_MESSAGE, false)) { String sendNick = lastMessage.getStringAttribute(RPConstant.EXTRA_RED_PACKET_SENDER_NAME, ""); String receiveNick = lastMessage.getStringAttribute(RPConstant.EXTRA_RED_PACKET_RECEIVER_NAME, ""); String msg; if (lastMessage.direct() == EMMessage.Direct.RECEIVE) { msg = String.format(getResources().getString(R.string.msg_someone_take_red_packet), receiveNick); } else { if (sendNick.equals(receiveNick)) { msg = getResources().getString(R.string.msg_take_red_packet); } else { msg = String.format(getResources().getString(R.string.msg_take_someone_red_packet), sendNick); } } return msg; } else if (lastMessage.getBooleanAttribute(RPConstant.MESSAGE_ATTR_IS_TRANSFER_PACKET_MESSAGE, false)) { String transferAmount = lastMessage.getStringAttribute(RPConstant.EXTRA_TRANSFER_AMOUNT, ""); String msg; if (lastMessage.direct() == EMMessage.Direct.RECEIVE) { msg = String.format(getResources().getString(R.string.msg_transfer_to_you), transferAmount); } else { msg = String.format(getResources().getString(R.string.msg_transfer_from_you),transferAmount); } return msg; } return null; } }); super.setUpView(); //end of red packet code } @Override protected void onConnectionDisconnected() { super.onConnectionDisconnected(); if (NetUtils.hasNetwork(getActivity())){ errorText.setText(R.string.can_not_connect_chat_server_connection); } else { errorText.setText(R.string.the_current_network); } } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { getActivity().getMenuInflater().inflate(R.menu.em_delete_message, menu); } @Override public boolean onContextItemSelected(MenuItem item) { boolean deleteMessage = false; if (item.getItemId() == R.id.delete_message) { deleteMessage = true; } else if (item.getItemId() == R.id.delete_conversation) { deleteMessage = false; } EMConversation tobeDeleteCons = conversationListView.getItem(((AdapterContextMenuInfo) item.getMenuInfo()).position); if (tobeDeleteCons == null) { return true; } if(tobeDeleteCons.getType() == EMConversationType.GroupChat){ EaseAtMessageHelper.get().removeAtMeGroup(tobeDeleteCons.conversationId()); } try { // delete conversation EMClient.getInstance().chatManager().deleteConversation(tobeDeleteCons.conversationId(), deleteMessage); InviteMessgeDao inviteMessgeDao = new InviteMessgeDao(getActivity()); inviteMessgeDao.deleteMessage(tobeDeleteCons.conversationId()); } catch (Exception e) { e.printStackTrace(); } refresh(); // update unread count ((MainActivity) getActivity()).updateUnreadLabel(); return true; }}initView()
@Overrideprotected void initView() { super.initView(); View errorView = (LinearLayout) View.inflate(getActivity(),R.layout.em_chat_neterror_item, null); errorItemContainer.addView(errorView); errorText = (TextView) errorView.findViewById(R.id.tv_connect_errormsg);}添加了错误的容器、初始化错误消息控件。
registerForContextMenu(conversationListView);注册上下文菜单
conversationListView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { EMConversation conversation = conversationListView.getItem(position); String username = conversation.conversationId(); if (username.equals(EMClient.getInstance().getCurrentUser())) Toast.makeText(getActivity(), R.string.Cant_chat_with_yourself, Toast.LENGTH_SHORT).show(); else { // start chat acitivity Intent intent = new Intent(getActivity(), ChatActivity.class); if(conversation.isGroup()){ if(conversation.getType() == EMConversationType.ChatRoom){ // it's group chat intent.putExtra(Constant.EXTRA_CHAT_TYPE, Constant.CHATTYPE_CHATROOM); }else{ intent.putExtra(Constant.EXTRA_CHAT_TYPE, Constant.CHATTYPE_GROUP); } } // it's single chat intent.putExtra(Constant.EXTRA_USER_ID, username); startActivity(intent); } }});条目的点击监听其中做了这么些事情:
- 判断用户名是否等于当前登陆用户,是则提示不能跟自己聊天
- 如果是群聊的话,则继续判断是聊天室还是群组,并带值给ChatActivity即聊天界面
- 最后将用户名带上,跳转ChatActivity。
//red packet code : 红包回执消息在会话列表最后一条消息的展示最后是红包回执信息。
conversationListView.setConversationListHelper(new EaseConversationListHelper() {
@Override
public String onSetItemSecondaryText(EMMessage lastMessage) {
if (lastMessage.getBooleanAttribute(RPConstant.MESSAGE_ATTR_IS_RED_PACKET_ACK_MESSAGE, false)) {
String sendNick = lastMessage.getStringAttribute(RPConstant.EXTRA_RED_PACKET_SENDER_NAME, "");
String receiveNick = lastMessage.getStringAttribute(RPConstant.EXTRA_RED_PACKET_RECEIVER_NAME, "");
String msg;
if (lastMessage.direct() == EMMessage.Direct.RECEIVE) {
msg = String.format(getResources().getString(R.string.msg_someone_take_red_packet), receiveNick);
} else {
if (sendNick.equals(receiveNick)) {
msg = getResources().getString(R.string.msg_take_red_packet);
} else {
msg = String.format(getResources().getString(R.string.msg_take_someone_red_packet), sendNick);
}
}
return msg;
} else if (lastMessage.getBooleanAttribute(RPConstant.MESSAGE_ATTR_IS_TRANSFER_PACKET_MESSAGE, false)) {
String transferAmount = lastMessage.getStringAttribute(RPConstant.EXTRA_TRANSFER_AMOUNT, "");
String msg;
if (lastMessage.direct() == EMMessage.Direct.RECEIVE) {
msg = String.format(getResources().getString(R.string.msg_transfer_to_you), transferAmount);
} else {
msg = String.format(getResources().getString(R.string.msg_transfer_from_you),transferAmount);
}
return msg;
}
return null;
}
});
super.setUpView();
我们接着看其他的方法
端口网络则提示没网标签。
@Override
protected void onConnectionDisconnected() {
super.onConnectionDisconnected();
if (NetUtils.hasNetwork(getActivity())){
errorText.setText(R.string.can_not_connect_chat_server_connection);
} else {
errorText.setText(R.string.the_current_network);
}
}
创建上下文菜单
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
getActivity().getMenuInflater().inflate(R.menu.em_delete_message, menu);
}
@Override上下文菜单选择的处理方法
public boolean onContextItemSelected(MenuItem item) {
boolean deleteMessage = false;
if (item.getItemId() == R.id.delete_message) {
deleteMessage = true;
} else if (item.getItemId() == R.id.delete_conversation) {
deleteMessage = false;
}
EMConversation tobeDeleteCons = conversationListView.getItem(((AdapterContextMenuInfo) item.getMenuInfo()).position);
if (tobeDeleteCons == null) {
return true;
}
if(tobeDeleteCons.getType() == EMConversationType.GroupChat){
EaseAtMessageHelper.get().removeAtMeGroup(tobeDeleteCons.conversationId());
}
try {
// delete conversation
EMClient.getInstance().chatManager().deleteConversation(tobeDeleteCons.conversationId(), deleteMessage);
InviteMessgeDao inviteMessgeDao = new InviteMessgeDao(getActivity());
inviteMessgeDao.deleteMessage(tobeDeleteCons.conversationId());
} catch (Exception e) {
e.printStackTrace();
}
refresh();
// update unread count[url=http://www.imgeek.org/article/825308690]环信官方Demo源码分析及SDK简单应用-主界面的三个fragment-通讯录界面[/url]
((MainActivity) getActivity()).updateUnreadLabel();
return true;
}
删除消息并更新未读消息。
好,至此,第一个界面,会话界面到此结束。
我们再来看通讯录界面。
环信官方Demo源码分析及SDK简单应用-主界面的三个fragment-通讯录界面