Android使用Websocket實(shí)現(xiàn)聊天室
最近的項(xiàng)目中要實(shí)現(xiàn)一個聊天的功能,類似于斗魚TV的聊天室功能,與服務(wù)器端人商量后決定用WebSocket來做,但是在這之前我只知道Socket但是聽都沒有聽過WebSocket,但是查看了相關(guān)的材料以后發(fā)現(xiàn)實(shí)現(xiàn)一個聊天室其實(shí)是很簡單的!下面我們先來看看WebSocket。
Autobahn|Android 是由Autobahn開發(fā)一個開源的Java/Android網(wǎng)絡(luò)庫,實(shí)現(xiàn)了WebSocket協(xié)議和Web應(yīng)用程序消息傳輸協(xié)議來創(chuàng)建本地移動的WebSocket/ WAMP的客服端。
WebSocket允許在網(wǎng)絡(luò)上雙向的發(fā)送實(shí)時(shí)消息,WAMP 為客服端增加了一個協(xié)議異步遠(yuǎn)程調(diào)用、推送、訂閱。
WebSocket有以下幾個特點(diǎn)
1.支持 WebSocket RFC6455, Draft Hybi-10+ and WAMP v1
2.支持Android 2.2以上
3.非常好的兼容性
4.高性能的異步設(shè)計(jì)
5.非常容易使用的api
6.與Android app非常好的結(jié)合
7.沒有網(wǎng)絡(luò)操作在UI線程
8.開源
下面是官網(wǎng)給的一段示例代碼
private final WebSocketConnection mConnection = new WebSocketConnection();
private void start() {
final String wsuri = "ws://localhost:9000";
try {
mConnection.connect(wsuri, new WebSocketHandler() {
@Override
public void onOpen() {
Log.d(TAG, "Status: Connected to " + wsuri);
mConnection.sendTextMessage("Hello, world!");
}
@Override
public void onTextMessage(String payload) {
Log.d(TAG, "Got echo: " + payload);
}
@Override
public void onClose(int code, String reason) {
Log.d(TAG, "Connection lost.");
}
});
} catch (WebSocketException e) {
Log.d(TAG, e.toString());
}
}
是不是挺簡單的,在onOpen()方法中做與服務(wù)器連接的操作,onTextMessage()是收到服務(wù)器發(fā)送給客服端的消息,onClose()是與服務(wù)器斷開走的方法,發(fā)送消息用sendTextMessage()。
我是在MsgService 實(shí)現(xiàn)與服務(wù)器的連接與發(fā)送消息的,直接上代碼:
public class MsgService extends Service {
private final IBinder binder = new MsgBinder();
private boolean flag = false;
private WebSocketConnection mConnection;
private Intent intent = new Intent("com.example.communication.RECEIVER");
public void startSocket(String sn) {
final String wsuri = "ws://localhost:9000";
final JSONObject json = new JSONObject();
try {
json.put("type", "command");
json.put("command", "auth");
json.put("key", Constants.API_KEY);
json.put("access_token", UserManager.getInstance().getUser()
.getUserAccessToken());
json.put("user_token", UserManager.getInstance().getUser()
.getLYUserToken());
json.put("sn", sn);
} catch (Exception e) {
e.printStackTrace();
}
try {
mConnection.connect(wsuri, new WebSocketHandler() {
@Override
public void onOpen() {
if (!flag) {
//與服務(wù)器連接認(rèn)證
mConnection.sendTextMessage(json.toString());
} else {
}
}
@Override
public void onTextMessage(String payload) {
intent.putExtra("message", payload);
sendBroadcast(intent);//發(fā)送廣播給Fragment
}
@Override
public void onClose(int code, String reason) {
//連接失敗也把效應(yīng)的提示信息告訴用戶
Map<String, String> map = new HashMap<>();
map.put("status", "failed");
map.put("type", "command");
map.put("command", "auth");
String msg = map.toString();
intent.putExtra("message", msg);
sendBroadcast(intent);
}
});
} catch (WebSocketException e) {
e.printStackTrace();
}
}
//發(fā)送消息的方法
public void sendMessage(String message) {
mConnection.sendTextMessage(message);
}
@Override
public IBinder onBind(Intent intent) {
return binder;
}
@Override
public void onCreate() {
mConnection = new WebSocketConnection();
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
public class MsgBinder extends Binder {
/**
* 獲取當(dāng)前Service的實(shí)例
*
* @return
*/
public MsgService getService() {
return MsgService.this;
}
}
@Override
public void onDestroy() {
super.onDestroy();
mConnection.disconnect();
}
}
下面是Fragment的代碼
public class ChatRoomFragment extends Fragment {
private View view, rootView, headView;
private MsgService msgService;
private UListView chatlist;//因?yàn)镾crollVie與ListView有沖突,重寫了ListView
private static List<ChatMessage> mlist;
private ChatMessage chatMessage;
private ChatMessageAdapter chatMessageAdapter;
private ScrollView scrollView;
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
msgService
.startSocket(((PlayActivity) getActivity()).getSn());
break;
default:
break;
}
}
};
//通過聊天室來更新在線人數(shù)
public interface UpdataOnlineUsersListener {
public void updataOnlineUser(int number);
}
private UpdataOnlineUsersListener mCallback;
private EditText messageEditText;
private Button sendBtn;
private Intent mIntent;
private MsgReceiver msgReceiver;
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d("time", "msg");
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 返回一個MsgService對象
MsgService.MsgBinder binder = (MsgService.MsgBinder) service;
if (binder != null) {
Log.d("time", "msg");
}
msgService = binder.getService();
if (msgService != null) {
Log.d("time", "msg");
Message msg = new Message();
msg.what = 1;
handler.sendMessage(msg);
}
}
};
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_chat_room, container, false);
return view;
}
public void bindChatService() {
getActivity().bindService(mIntent, conn, Context.BIND_AUTO_CREATE);
}
public void destoryChatService() {
getActivity().unbindService(conn);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mCallback = (UpdataOnlineUsersListener) (activity);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// 動態(tài)注冊廣播接收器
msgReceiver = new MsgReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.example.communication.RECEIVER");
getActivity().registerReceiver(msgReceiver, intentFilter);
mIntent = new Intent(getActivity(), MsgService.class);
bindChatService();
chatlist = (UListView) view.findViewById(R.id.chatlist);
messageEditText = (EditText) view.findViewById(R.id.input);
scrollView = (ScrollView) view.findViewById(R.id.scroll);
scrollView.setFocusable(false);
mlist = new ArrayList<ChatMessage>();
chatMessageAdapter = new ChatMessageAdapter(mlist, getActivity());
chatlist.setAdapter(chatMessageAdapter);
chatlist.setVerticalScrollBarEnabled(true);
sendBtn = (Button) view.findViewById(R.id.send);
builder = new AlertDialog.Builder(getActivity());
sendBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
final View view = v;
if (UserManager.getInstance().getUser().getGuest()) {
ToastUtil.getInstance().showToast(getActivity(), getResources().getString(R.string.is_not_login));
} else {
String message = messageEditText.getText().toString();
if (!message.equals("")) {
JSONObject json = new JSONObject();
try {
json.put("type", "message");
json.put("to", "");
json.put("message", message);
} catch (Exception e) {
}
msgService.sendMessage(json.toString());
} else {
Toast.makeText(getActivity(),
getResources().getString(R.string.textisnull),
Toast.LENGTH_SHORT).show();
}
}
HideKeyboard(v);
messageEditText.setText("");
}
});
rootView = (View) view.findViewById(R.id.rootview);
rootView.setFocusable(true);
rootView.setFocusableInTouchMode(true);
rootView.requestFocus();
setRetainInstance(true);
}
//隱藏軟鍵盤
private void HideKeyboard(View v) {
InputMethodManager imm = (InputMethodManager) v.getContext()
.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm.isActive()) {
imm.hideSoftInputFromWindow(v.getApplicationWindowToken(), 0);
}
}
@Override
public void onResume() {
super.onResume();
scrollView.smoothScrollTo(0, 0);
}
//接受服務(wù)端發(fā)送的消息
public class MsgReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String msg = intent.getStringExtra("message");
try {
JSONObject json = new JSONObject(msg);
if (json.getString("type").equals("command")) {
String command = json.getString("command");
if (command.equals("auth")) {
{
chatMessage = new ChatMessage("tips", "服務(wù)器連接中...",
"111", "111");
mlist.add(chatMessage);
chatMessageAdapter.notifyDataSetChanged();
}
if (json.getString("status").equals("success")) {
chatMessage = new ChatMessage("tips", "服務(wù)器連接中成功",
"111", "111");
} else {
chatMessage = new ChatMessage("tips", "服務(wù)器連接中失敗",
"111", "111");
}
mlist.add(chatMessage);
chatMessageAdapter.notifyDataSetChanged();
} else if (command.equals("online_status")) {
int onlineUser = json.getInt("online");
mCallback.updataOnlineUser(onlineUser);
}
} else if (json.getString("type").equals("message")) {
chatMessage = new ChatMessage(json.getString("type"),
json.getString("from"), json.getString("content"),
json.getString("time"));
mlist.add(chatMessage);
chatMessageAdapter.notifyDataSetChanged();
}
Log.d("time", mlist.toString());
} catch (JSONException e) {
e.printStackTrace();
}
chatlist.setSelection(chatMessageAdapter.getCount());//讓ListView滑到最下面
}
}
@Override
public void onDestroy() {
// 停止服務(wù)
getActivity().unbindService(conn);
// 注銷廣播
getActivity().unregisterReceiver(msgReceiver);
super.onDestroy();
}
}
這樣一個簡單的聊天室功能就實(shí)現(xiàn)了直接上圖。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android開發(fā)系列二之窗口Activity的生命周期
這篇文章主要介紹了Android學(xué)習(xí)系列二之窗口Activity的生命周期的相關(guān)資料,需要的朋友可以參考下2016-05-05
Android接入支付寶實(shí)現(xiàn)支付功能實(shí)例
這篇文章主要介紹了Android接入支付寶實(shí)現(xiàn)支付功能實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06
Android的webview支持HTML5的離線應(yīng)用功能詳細(xì)配置
HTML5的離線應(yīng)用功能可以使得WebApp即使在網(wǎng)絡(luò)斷開的情況下仍能正常使用這是個非常有用的功能,但如何使Webivew支持HTML5離線應(yīng)用功能呢,需要的朋友可以參考下2012-12-12
Android自定義控件實(shí)現(xiàn)圓形進(jìn)度CircleProgressBar
這篇文章主要為大家詳細(xì)介紹了Android自定義控件實(shí)現(xiàn)圓形進(jìn)度CircleProgressBar,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05
Flutter 設(shè)置全局字體的實(shí)現(xiàn)
本文主要介紹了Flutter 設(shè)置全局字體的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02
使用android studio導(dǎo)入模塊的兩種方法(超詳細(xì))
這篇文章主要介紹了使用android studio導(dǎo)入模塊的兩種方法,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-09-09
Android App支付系列(二):支付寶SDK接入詳細(xì)指南(附官方支付demo)
本篇文章介紹了Android App支付系列(二):支付寶SDK接入詳細(xì)指南(附官方支付demo) ,有興趣的同學(xué)可以了解一下。2016-11-11
Android編程連接MongoDB及增刪改查等基本操作示例
這篇文章主要介紹了Android編程連接MongoDB及增刪改查等基本操作,簡單介紹了MongoDB功能、概念、使用方法及Android操作MongoDB數(shù)據(jù)庫的基本技巧,需要的朋友可以參考下2017-07-07
Android實(shí)現(xiàn)微信側(cè)滑關(guān)閉頁面效果
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)微信側(cè)滑關(guān)閉頁面效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12
Android中AOP的應(yīng)用實(shí)踐之過濾重復(fù)點(diǎn)擊
這篇文章主要給大家介紹了關(guān)于Android中AOP的應(yīng)用實(shí)踐之過濾重復(fù)點(diǎn)擊的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對各位Android開發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-09-09

