轉載請標明出處:http://blog.csdn.net/lmj623565791/article/details/38799363 ,本文出自:【張鴻洋的博客】php
一直在仿微信界面,今天終於有幸利用百度雲推送仿一仿微信聊天了~~~java
首先特別感謝:weidi1989分享的Android之基於百度雲推送IM ,你們能夠直接下載;省了不少事哈,本例中也使用了weidi的部分代碼,凡是@author way的就是weidi1989的代碼~~數據庫
核心功能也就上面的兩張圖了~~~我拿着手機和模擬器聊天,同時感謝羣裏的兄弟姐妹幫忙測試(好友列表中)。api
下面經過幾個問題來講明下實現的原理:微信
一、如何實現給某個用戶發送消息呢?網絡
其實就是利用百度雲提供的REST API,直接經過發送Http請求的形式給某個用戶推送一條消息;架構
網址:http://developer.baidu.com/wiki/index.php?title=docs/cplat/push/api/listapp
實例:ide
push_msg
功能
推送消息,該接口可用於推送單我的、一羣人、全部人以及固定設備的使用場景。
HTTP請求方式
POST
URL
http[s]://channel.api.duapp.com/rest/2.0/channel/channel
函數
....
二、的確能夠實現給某個用戶或者一羣用戶推送消息,那麼用戶的暱稱神馬的咋獲取的呢,我印象中百度雲中無法存這樣的數據?
嗯,其實用了一個比較巧妙的方式;在用戶首次安裝軟件的時候,會要求用戶填寫註冊信息,也就是暱稱等;當用戶填寫完畢時,點擊登陸的時候:
一、發送一條比較特殊的消息,好比這個消息攜帶一個hello的字段,廣播給全部用戶;
二、其餘用戶在收到消息時,首先判斷hello這個字段是否有值,有值則說明新用戶加入,把該新用戶存入本地數據庫,而後更新用戶列表;
三、其餘用戶給這個新用戶回一條消息,附帶一個特殊字段,好比welcome,當新用戶收到攜帶welcome字段的消息時,代表這是對新用戶hello的答覆,而後將已存在用戶添加到該新用戶的用戶列表。
基本原理就這樣了,你們甚至能夠利用上述的原理添加一些刪除好友的功能;好比當用戶點擊刪除好友,則發送一條特殊消息給被刪除的對象,而後對方收到該消息,也將發送發刪除。
相信你們在瞭解原理以後,這個例子瞬間從高大尚變成矮矬窮了,這尼瑪,so easy,誰不會啊~~~
因爲代碼量仍是至關大的,也不想拆成幾篇博客,因此準備將核心代碼進行講解下,其餘的你們本身看源碼~
關於這個例子的主界面,能夠參考: 高仿微信5.2.1主界面架構 包含消息通知
關於百度雲推送的入門,能夠參考:Android推送 百度雲推送 入門篇
好了,最主要就是收到百度雲推送的Receiver
首先是用戶第一次登陸時候綁定的回調
[java] view plaincopy
@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
[java] view plaincopy
/**
* 收到通知
*/
@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;也就是上述的原理分析中的部分~
收到百度雲推送的Receiver中的onMessage
[java] view plaincopy
@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);
}
/**
* 消息:一、攜帶hello,表示新人加入,應該自動回覆一個world 消息; 二、普通消息;
*
* @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;
}
當收到一個新的消息:
一、首先判斷是否是本身發的,是,忽略;
二、判斷是否攜帶hello字段,表明新人加入,攜帶,則保存到好友列表,且回覆一個攜帶welcome字段的消息;
三、判斷是否包含welcome字段,包含,存入好友列表
四、不是一、二、3則確定是普通消息,將消息保存到本地數據庫,而後爲全部設置消息監聽的發送回調便可~
MainTabFriends.java用戶列表中收到新消息的回調:
[java] view plaincopy
/**
* 收到新消息時
*/
@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();
}
一、若是是本身發的不作任何處理
二、若是當前消息發送用戶已有未讀消息,則更新該用戶未讀消息個數(用戶Item上顯示未讀消息通知數),更新全部未讀消息總和(朋友Tab上顯示未讀消息總和),而後存儲該消息
三、刷新界面
ChattingActivity.java聊天界面的新消息回調
[java] view plaincopy
@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的項目~~~