Android 高仿微信即时聊天 百度云为基础的推
转载请注明出处:http://blog.csdn.net/lmj623565791/article/details/38799363 ,本文出自:【张鸿洋的博客】
一直在仿微信界面,今天最终有幸利用百度云推送仿一仿微信聊天了~~~
首先特别感谢:weidi1989分享的Android之基于百度云推送IM ,大家能够直接下载;省了非常多事哈。本例中也使用了weidi的部分代码。凡是@author way的就是weidi1989的代码~~
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能够直接留言,方便其它学习的童鞋,也方便我了,多谢~~~~~~~~~~~~~~
ps:近期状态不好,我要去喝脉动~~~~
源代码点击下载 大家能够先安装压缩文件中面的apk測试下,这样就能够发现别的伙伴了~~~
源代码点击下载 补充了一下那个BadgeView的项目~~~
版权声明:本文博主原创文章。博客,未经同意不得转载。
Android 高仿微信即时聊天 百度云为基础的推的更多相关文章
- Android 高仿微信实时聊天 基于百度云推送
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38799363 ,本文出自:[张鸿洋的博客] 一直在仿微信界面,今天终于有幸利用百 ...
- Android 高仿微信语音聊天页面高斯模糊效果
目前的应用市场上,使用毛玻璃效果的APP随处可见,比如用过微信语音聊天的人可以发现,语音聊天页面就使用了高斯模糊效果. 先看下效果图: 仔细观察上图,我们可以发现,背景图以用户头像为模板,对其进行了高 ...
- 高仿QQ即时聊天软件开发系列之三登录窗口用户选择下拉框
上一篇高仿QQ即时聊天软件开发系列之二登录窗口界面写了一个大概的布局和原理 这一篇详细说下拉框的实现原理 先上最终效果图 一开始其实只是想给下拉框加一个placeholder效果,让下拉框在未选择未输 ...
- 高仿QQ即时聊天软件开发系列之二登录窗口界面
继上一篇高仿QQ即时聊天软件开发系列之一开端之后,开始做登录窗口 废话不多说,先看效果,只有界面 可能还有一些细节地方没有做,例如那个LOGO嘛,不要在意这些细节 GIF虽短,可是这做起来真难,好吧因 ...
- Android高仿微信(一)——如何消除启动时的白屏
默认情况下,APP启动时会先把屏幕刷成白色,然后才绘制第一个Activity中的View,这两个步骤之间的延迟会造成启动后先看到白屏(时间大概为1秒左右).时间不长,但是我们也看到,一般的APP时不存 ...
- Android 高仿微信头像截取 打造不一样的自定义控件
转载请表明出处:http://blog.csdn.net/lmj623565791/article/details/39761281,本文出自:[张鸿洋的博客] 1.概述 前面已经写了关于检测手势识别 ...
- android高仿微信拍照、多选、预览、删除(去除相片)相冊功能
先声明授人与鱼不如授人与渔,仅仅能提供一个思路,当然须要源代码的同学能够私下有偿问我要源代码:QQ:508181017 工作了将近三年时间了,一直没正儿八经的研究系统自带的相冊和拍照,这回来个高仿微信 ...
- Android 高仿微信6.0主界面 带你玩转切换图标变色
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/41087219,本文出自:[张鸿洋的博客] 1.概述 学习Android少不了模仿 ...
- Android 高仿微信支付键盘
现在很多app的支付.输入密码功能,都已经开始使用自定义数字键盘,不仅更加方便.其效果着实精致. 下面带着大家学习下,如何高仿微信的数字键盘,可以拿来直接用在自身的项目中. 先看下效果图: 1. 自定 ...
随机推荐
- qt qml中PropertyAnimation的几种使用方法
qml文章 qt qml中PropertyAnimation的几种使用方法 动画应用场景有以下几种: 首先如果一个Rectangle.动画是要改变它的x和y值 1,Rectangle一旦被创建,就要移 ...
- OCA读书笔记(11) - 实现Oracle数据库审计
11 Implementing Oracle Database Auditing 描述DBA对于安全和审计的职责使能标准的数据库审计安全审计选项查看审计信息维护审计路径 最小权限原则只在计算机上安装所 ...
- 小议common lisp程序开发流程 - Ever 17 - 博客频道 - CSDN.NET
小议common lisp程序开发流程 - Ever 17 - 博客频道 - CSDN.NET 小议common lisp程序开发流程 分类: lisp 2011-04-17 20:59 1316人阅 ...
- Spring3.0官网文档学习笔记(一)
Part 1 Spring框架概述 Spring是模块化的,在应用中仅仅须要引入你所须要用到的模块的jar包,其余的jar包不用引入. spring框架支持声明式的事务管理,通过RMI或web ser ...
- Cocos2d-x内存管理解说在ios开发中
使用过 Cocos2d-x 都知道,其中有一套自己实现的内存管理机制,不同于一般 C++ 的编写常规,而在使用前,了解其原理是有必要的,网上已经有很多对内部实现详细解说的文章.而对于使用者而言,并不需 ...
- 不起眼的 z-index 却能牵扯出这么大的学问(转)
z-index在日常开发中算是一个比较常用的样式,一般理解就是设置标签在z轴先后顺序,z-index值大的显示在最前面,小的则会被遮挡,是的,z-index的实际作用就是这样. 但是你真的了解z-in ...
- onkeypress事件.onkeydown事件.onkeyup事件
onkeypress事件是在按键開始按的时候发生: onkeydown事件是在按键已经按下的时候发生: onkeyup事件是在按键松开(释放)的时候发生.
- 二、第一个ExtJS程序:helloExtJS
开发前的准备 下载并解压ExtJS包后,能够得到下图的文件文件夹结构: 在实际开发过程中并不须要全部的文件和文件夹,所需的包括例如以下文件夹就可以: 若使用eclipse进行开发,仅仅需将上述文件拷贝 ...
- java中的特殊字符集合
JAVA中转义字符: 1.八进制转义序列:\ + 1到3位5数字:范围'\000'~'\377' \0:空字符 2.Unicode转义字符:\u + 四个 十六进制数字:0~65535 ...
- 用XAML做网页!!—导航栏
原文:用XAML做网页!!-导航栏 这次要完成的是导航栏,这是页面中比较复杂的区域. 先在 Microsoft Expression Design 中绘制导航栏的背景图案: 导出为barback.xa ...