您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
   
 
 
     
   
 订阅
  捐助
Android 高仿微信实时聊天 基于百度云推送
 
作者 鸿洋_的BLOG,火龙果软件    发布于 2014-09-17
   次浏览      
 

一直在仿微信界面,今天终于有幸利用百度云推送仿一仿微信聊天了。

1、效果图

核心功能也就上面的两张图了~~~我拿着手机和模拟器聊天,同时感谢群里的兄弟姐妹帮忙测试(好友列表中)。

2、原理

下面通过几个问题来说明下实现的原理:

1、如何实现给某个用户发送消息呢?

其实就是利用百度云提供的REST API,直接通过发送Http请求的形式给某个用户推送一条消息;

网址:http://developer.baidu.com/wiki/index.php?title=docs/cplat/push/api/list

实例:

push_msg

功能

推送消息,该接口可用于推送单个人、一群人、所有人以及固定设备的使用场景。

HTTP请求方式

POST

URL

http[s]://channel.api.duapp.com/rest/2.0/channel/channel

....

2、的确可以实现给某个用户或者一群用户推送消息,那么用户的昵称神马的咋获取的呢,我印象中百度云中没法存这样的数据?

嗯,其实用了一个比较巧妙的方式;在用户首次安装软件的时候,会要求用户填写注册信息,也就是昵称等;当用户填写完毕时,点击登录的时候:

1、发送一条比较特殊的消息,比如这个消息携带一个hello的字段,广播给所有用户;

2、其他用户在收到消息时,首先判断hello这个字段是否有值,有值则说明新用户加入,把该新用户存入本地数据库,然后更新用户列表;

3、其他用户给这个新用户回一条消息,附带一个特殊字段,比如welcome,当新用户收到携带welcome字段的消息时,表明这是对新用户hello的答复,然后将已存在用户添加到该新用户的用户列表。

基本原理就这样了,大家甚至可以利用上述的原理添加一些删除好友的功能;比如当用户点击删除好友,则发送一条特殊消息给被删除的对象,然后对方收到该消息,也将发送发删除。

相信大家在了解原理之后,这个例子瞬间从高大尚变成矮矬穷了,这尼玛,so easy,谁不会啊~~~

3、核心代码解析

由于代码量还是相当大的,也不想拆成几篇博客,所以准备将核心代码进行讲解下,其他的大家自己看源码~

关于这个例子的主界面,可以参考: 高仿微信5.2.1主界面架构 包含消息通知

关于百度云推送的入门,可以参考:Android推送 百度云推送 入门篇

好了,最主要就是收到百度云推送的Receiver

1、onBind

首先是用户第一次登录时候绑定的回调

@Override
public void onBind(final Context context, int errorCode, String appid,
String userId, String channelId, String requestId)
{
String responseString = "onBind errorCode=" + errorCode + " appid="
+ appid + " userId=" + userId + " channelId=" + channelId
+ " requestId=" + requestId;
Log.e(TAG, responseString);
if (errorCode == 0)
{
SharePreferenceUtil util = PushApplication.getInstance()
.getSpUtil();
util.setAppId(appid);
util.setChannelId(channelId);
util.setUserId(userId);

} else
// 如果网络正常,则重试
{
if (NetUtil.isNetConnected(context))
{
T.showLong(context, "启动失败,正在重试...");
new Handler().postDelayed(new Runnable()
{
@Override
public void run()
{
PushManager.startWork(context,
PushConstants.LOGIN_TYPE_API_KEY,
PushApplication.API_KEY);
}
}, 2000);// 两秒后重新开始验证
} else
{
T.showLong(context, R.string.net_error_tip);
}
}
// 回调函数
for (int i = 0; i < bindListeners.size(); i++)
bindListeners.get(i).onBind(userId, errorCode);
}

初次绑定的时候,如果绑定成功则使用SharedPreferences存储userId,channelId等数据
然后回调:bindListeners.get(i).onBind(userId, errorCode);给所有注册该事件的发出通知

下面看listener.onBind

/**
* 收到通知
*/
@Override
public void onBind(String userId, int errorCode)
{
Log.e("TAG", "Login Activity onBind ");
if (errorCode == 0)
{
Log.e("TAG", "Login Activity onBind success ");
// 如果绑定账号成功,由于第一次运行,给同一tag的人推送一条新人消息
User u = new User(mSpUtil.getUserId(), mSpUtil.getChannelId(),
mSpUtil.getNick(), mSpUtil.getHeadIcon(), 0);
mUserDB.addUser(u);// 把自己添加到数据库
Message firstSendMsg = new Message(System.currentTimeMillis(), "");
firstSendMsg.setHello("hello");
task = new SendMsgAsyncTask(mGson.toJson(firstSendMsg), "");
task.setOnSendScuessListener(new OnSendScuessListener()
{
@Override
public void sendScuess()
{
if (mLoadingDialog != null && mLoadingDialog.isVisible())
mLoadingDialog.dismiss();
mHandler.removeCallbacks(mConnTimeoutCallback);
finish();
Intent intent = new Intent(LoginActivity.this,
MainActivity.class);
startActivity(intent);
}
});
task.send();
}
}

首先将自己保存到本地数据库,然后发送一个Message给所有的用户,设置一个特殊字段hello;也就是上述的原理分析中的部分~

2、onMessage

收到百度云推送的Receiver中的onMessage

@Override  
public void onMessage(Context context, String message,
String customContentString)
{
String messageString = "收到消息 message=\"" + message
+ "\" customContentString=" + customContentString;
Log.e(TAG, messageString);
Message receivedMsg = PushApplication.getInstance().getGson()
.fromJson(message, Message.class);
// 对接收到的消息进行处理
parseMessage(receivedMsg);

}

/**
* 消息:1、携带hello,表示新人加入,应该自动回复一个world 消息; 2、普通消息;
*
* @param msg
*/
private void parseMessage(Message msg)
{
String userId = msg.getUserId();
// 自己的消息
if (userId
.equals(PushApplication.getInstance().getSpUtil().getUserId()))
return;
if (checkHasNewFriend(msg) || checkAutoResponse(msg))
return;
// 普通消息
UserDB userDB = PushApplication.getInstance().getUserDB();
User user = userDB.selectInfo(userId);
// 漏网之鱼
if (user == null)
{
user = new User(userId, msg.getChannelId(), msg.getNickname(), 0, 0);
userDB.addUser(user);
// 通知监听的面板
for (onNewFriendListener listener : friendListeners)
listener.onNewFriend(user);
}
if (msgListeners.size() > 0)
{// 有监听的时候,传递下去
for (int i = 0; i < msgListeners.size(); i++)
msgListeners.get(i).onNewMessage(msg);
} else
// 当前没有任何监听,即处理后台状态
{
// 将新来的消息进行存储
ChatMessage chatMessage = new ChatMessage(msg.getMessage(), true,
userId, msg.getHeadIcon(), msg.getNickname(), false,
TimeUtil.getTime(msg.getTimeSamp()));
PushApplication.getInstance().getMessageDB()
.add(userId, chatMessage);
showNotify(msg);
}
}

/**
* 检测是否是自动回复
*
* @param msg
*/
private boolean checkAutoResponse(Message msg)
{
String world = msg.getWorld();
String userId = msg.getUserId();
if (!TextUtils.isEmpty(world))
{
User u = new User(userId, msg.getChannelId(), msg.getNickname(),
msg.getHeadIcon(), 0);
PushApplication.getInstance().getUserDB().addUser(u);// 存入或更新好友
// 通知监听的面板
for (onNewFriendListener listener : friendListeners)
listener.onNewFriend(u);

return true;
}
return false;
}

/**
* 检测是否是新人加入
*
* @param msg
*/
private boolean checkHasNewFriend(Message msg)
{
String userId = msg.getUserId();
String hello = msg.getHello();
// 新人发送的消息
if (!TextUtils.isEmpty(hello))
{
Log.e("checkHasNewFriend", msg.getUserId());
// 新人
User u = new User(userId, msg.getChannelId(), msg.getNickname(),
msg.getHeadIcon(), 0);
PushApplication.getInstance().getUserDB().addUser(u);// 存入或更新好友
T.showShort(PushApplication.getInstance(), u.getNick() + "加入");

// 给新人回复一个应答
Message message = new Message(System.currentTimeMillis(), "");
message.setWorld("world");
new SendMsgAsyncTask(PushApplication.getInstance().getGson()
.toJson(message), userId);
// 通知监听的面板
for (onNewFriendListener listener : friendListeners)
listener.onNewFriend(u);

return true;
}

return false;
}

当收到一个新的消息:

1、首先判断是不是自己发的,是,忽略;

2、判断是否携带hello字段,代表新人加入,携带,则保存到好友列表,且回复一个携带welcome字段的消息;

3、判断是否包含welcome字段,包含,存入好友列表

4、不是1、2、3则肯定是普通消息,将消息保存到本地数据库,然后为所有设置消息监听的发送回调即可~

MainTabFriends.java用户列表中收到新消息的回调:

/** 
* 收到新消息时
*/
@Override
public void onNewMessage(Message message)
{
// 如果是自己发送的,则直接返回
if (message.getUserId() == mSpUtils.getUserId())
return;
// 如果该用户已经有未读消息,更新未读消息的个数,并通知更新未读消息接口,最后notifyDataSetChanged
String userId = message.getUserId();
if (mUserMessages.containsKey(userId))
{
mUserMessages.put(userId, mUserMessages.get(userId) + 1);
} else
{
mUserMessages.put(userId, 1);
}
mUnReadedMsgs++;
notifyUnReadedMsg();
// 将新来的消息进行存储
ChatMessage chatMessage = new ChatMessage(message.getMessage(), true,
userId, message.getHeadIcon(), message.getNickname(), false,
TimeUtil.getTime(message.getTimeSamp()));
mApplication.getMessageDB().add(userId, chatMessage);
// 通知listview数据改变
mAdapter.notifyDataSetChanged();
}

1、如果是自己发的不做任何处理

2、如果当前消息发送用户已有未读消息,则更新该用户未读消息个数(用户Item上显示未读消息通知数),更新所有未读消息总和(朋友Tab上显示未读消息总和),然后存储该消息

3、刷新界面

ChattingActivity.java聊天界面的新消息回调

@Override  
public void onNewMessage(Message message)
{

// 获得回复的消息
if (mFromUser.getUserId().equals(message.getUserId()))
{
ChatMessage chatMessage = new ChatMessage();
chatMessage.setComing(true);
chatMessage.setDate(new Date(message.getTimeSamp()));
chatMessage.setMessage(message.getMessage());
chatMessage.setUserId(message.getUserId());
chatMessage.setNickname(message.getNickname());
chatMessage.setReaded(true);
mDatas.add(chatMessage);
mAdapter.notifyDataSetChanged();
mChatMessagesListView.setSelection(mDatas.size() - 1);
// 存入数据库,当前聊天记录
mApplication.getMessageDB().add(mFromUser.getUserId(), chatMessage);
}
}

首先判断是否是正在聊天的用户发的消息,如果是,直接存入数据库,刷新聊天界面;

好了,细节也不展开描述了,大家自己看源码,bug肯定有,发现bug可以直接留言,方便其他学习的童鞋,也方便我了,多谢。

   
次浏览       
 
相关文章

手机软件测试用例设计实践
手机客户端UI测试分析
iPhone消息推送机制实现与探讨
Android手机开发(一)
 
相关文档

Android_UI官方设计教程
手机开发平台介绍
android拍照及上传功能
Android讲义智能手机开发
相关课程

Android高级移动应用程序
Android系统开发
Android应用开发
手机软件测试
最新活动计划
Node+Vue3.0前端全栈开发 7-5 [特惠]
Spring Cloud微服务架构 7-5[特惠]
SysML和EA系统设计与建模 7-26[特惠]
Python、数据分析与机器学习 8-23[特惠]
嵌入式软件架构设计 8-22[线上]
Linux内核编程及设备驱动 7-25[北京]

android人机界面指南
Android手机开发(一)
Android手机开发(二)
Android手机开发(三)
Android手机开发(四)
iPhone消息推送机制实现探讨
手机软件测试用例设计实践
手机客户端UI测试分析
手机软件自动化测试研究报告
更多...   


Android高级移动应用程序
Android应用开发
Android系统开发
手机软件测试
嵌入式软件测试
Android软、硬、云整合


领先IT公司 android开发平台最佳实践
北京 Android开发技术进阶
某新能源领域企业 Android开发技术
某航天公司 Android、IOS应用软件开发
阿尔卡特 Linux内核驱动
艾默生 嵌入式软件架构设计
西门子 嵌入式架构设计
更多...