0
点赞
收藏
分享

微信扫一扫

Android WebSocket实现即时通讯功能


文章目录

  • ​​简介​​
  • ​​基本使用​​
  • ​​后台运行​​
  • ​​从Service中更新Activity的UI​​
  • ​​总结流程​​
  • ​​心跳检测和重连​​
  • ​​资源下载​​


这篇文章是参考简书作者

​ChaoYoung​​的

​​Android WebSocket实现即时通讯功能​​ 写的,不过侧重点是如何使用 Websocket,通过阅读本篇文章你可以学到目录中的内容,重点不放在即时通讯

简介

WebSocket,简而言之,就是一个可以建立长连接的全双工(full-duplex)通信协议,允许服务器端主动发送信息给客户端

对于使用websocket协议,Android端已经有些成熟的框架了,现在学习一下Java-WebSocket这个开源框架

​​GitHub地址​​

基本使用

1、引入

implementation "org.java-websocket:Java-WebSocket:1.4.0"

2、加入权限

<uses-permission android:name="android.permission.INTERNET" />

3、新建客户端类

新建一个客户端类并继承WebSocketClient,需要实现它的四个抽象方法和构造函数

public class JWebsocketClient extends WebSocketClient {

public JWebsocketClient(URI serverUri) {
//super(serverUri);
super(serverUri,new Draft_6455());
//构造方法中的new Draft_6455()代表使用的协议版本,这里可以不写或者写成这样即可
}

@Override
public void onOpen(ServerHandshake handshakedata) {
//websocket连接开启时调用
}

@Override
public void onMessage(String message) {
//接收到消息时调用
}

@Override
public void onClose(int code, String reason, boolean remote) {
//连接断开时调用
}

@Override
public void onError(Exception ex) {
//连接出错时调用
}
}

4、建立websocket连接

建立连接只需要初始化此客户端再调用连接方法,需要注意的是WebSocketClient对象是不能重复使用的,所以不能重复初始化,其他地方只能调用当前这个Client

初始化客户端时需要传入websocket地址(测试地址:ws://echo.websocket.org)

URI uri = URI.create("ws://echo.websocket.org");
JWebsocketClient client = new JWebsocketClient(uri);

连接时可以使用​​connect()​​​方法或​​connectBlocking()​​​方法,建议使用​​connectBlocking()​​方法,它多出一个等待操作,会先连接再发送

运行之后,看到打印了onOpen,说明连接建立了
Android WebSocket实现即时通讯功能_websocket
5、发送消息

if(client!=null && client.isOpen()){
client.send("hello");
}

6、关闭socket连接
关闭连接调用close()方法,最后为了避免重复实例化WebSocketClient对象,关闭时一定要将对象置空

try {
if (null != client) {
client.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
client = null;
}

后台运行

如果希望在后台保持运行,需要的是建一个Service,将websocket的逻辑放入服务中运行,让websocket保持连接

1、新建Service
新建一个 Service,在启动 Service 时实例化 WebSocketClient 对象并建立连接,将上面的代码搬到服务里即可

关于 Service 的教程可以查看【达内课程】Service(上)

所以我们创建 JWebSocketClientService

public class JWebSocketClientService extends Service {
JWebsocketClient client;

@Override
public void onCreate() {
super.onCreate();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//初始化websocket
initSocketClient();
return super.onStartCommand(intent, flags, startId);
}

@Override
public void onDestroy() {
closeConnect();
super.onDestroy();
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}

private void initSocketClient() {
URI uri = URI.create("ws://echo.websocket.org");
client = new JWebsocketClient(uri);
connect();
}

private void connect() {
new Thread() {
@Override
public void run() {
try {
//connectBlocking多出一个等待操作,会先连接再发送,否则未连接发送会报错
client.connectBlocking();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}

private void closeConnect() {
try {
if (null != client) {
client.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
client = null;
}
}
}

在 manifest 中注册

<service android:name=".JWebSocketClientService"/>

在Activity中启动

private void startJWebSClientService() {
Intent intent = new Intent(mContext, JWebSocketClientService.class);
startService(intent);
}

2、Service和Activity之间通讯
从之前讲 Service 的教程:​【达内课程】Service(下)​可知,要进行服务和活动之间的通讯,需要用到Service中的​​onBind()​​方法

public class JWebSocketClientService extends Service {
......
private InnerIBinder mBinder = new InnerIBinder();
......

@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}

private class InnerIBinder extends Binder {
public JWebSocketClientService getService() {
return JWebSocketClientService.this;
}
}

......
}

接下来就需要对应的Activity绑定Service,并获取Service的东西

public class SecondActivity extends AppCompatActivity {
private JWebsocketClient client;
private InnerServiceConnection serviceConnection = new InnerServiceConnection();
private JWebSocketClientService.InnerIBinder binder;
private JWebSocketClientService jWebSClientService;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
//启动service
startJWebSClientService();
//绑定服务
bindService();
}

private void startJWebSClientService() {
Intent intent = new Intent(this, JWebSocketClientService.class);
startService(intent);
}

private void bindService() {
Intent bindIntent = new Intent(this, JWebSocketClientService.class);
bindService(bindIntent, serviceConnection, BIND_AUTO_CREATE);
}

private class InnerServiceConnection implements ServiceConnection {

@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d("Service","onServiceConnected()->当Activity和Service连接");
binder = (JWebSocketClientService.InnerIBinder) service;
jWebSClientService = binder.getService();
client = jWebSClientService.client;
}

@Override
public void onServiceDisconnected(ComponentName name) {
Log.d("Service","onServiceConnected()->当Activity和Service断开连接");
}
}
}

这里首先创建了一个 InnerServiceConnection 匿名类,在里面重写​​onServiceConnected()​​​和​​onServiceDisconnected()​​方法,这两个方法会在活动与服务成功绑定以及连接断开时调用

在​​onServiceConnected()​​​首先得到 InnerIBinder 的实例,有了这个实例便可调用服务的任何public方法,这里调用​​getService()​​方法得到 Service 实例,得到了 Service 实例也就得到了WebSocketClient 对象,也就可以在活动中发送消息了

从Service中更新Activity的UI

当 Service 中接收到消息时需要更新 Activity 中的界面,方法有很多,这里我们利用广播来实现,在对应 Activity 中定义广播接收者,Service 中收到消息发出广播即可

public class SecondActivity extends AppCompatActivity{
......
private ChatMessageReceiver chatMessageReceiver;

@Override
protected void onCreate(Bundle savedInstanceState) {
......
//注册广播
doRegisterReceiver();
}
......

private class ChatMessageReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String message=intent.getStringExtra("message");
}
}

private void doRegisterReceiver() {
chatMessageReceiver = new ChatMessageReceiver();
IntentFilter filter = new IntentFilter("CCTV5");
registerReceiver(chatMessageReceiver, filter);
}
}

关于广播接收者的教程可以参考之前的:【达内课程】BroadcastReceiver(上),广播这里的代码,上边教程讲的很明白,这里不赘述

当 Service 中接收到消息时发出广播,就能在 ChatMessageReceiver 里接收广播了,我们修改 JWebSocketClientService 中代码,为了方便修改代码,重写 JWebsocketClient 的​​onMessage​​方法

private void initSocketClient() {
URI uri = URI.create("ws://echo.websocket.org");
client = new JWebsocketClient(uri){
@Override
public void onMessage(String message) {
Intent intent = new Intent();
intent.setAction("CCTV5");
intent.putExtra("message", message);
sendBroadcast(intent);
}
};
connect();
}

获取广播传过来的消息后即可更新UI

总结流程

由于连接的 websocket 的地址是 ​​"ws://echo.websocket.org"​​,当我们给它发送一个消息“hello”时,它会返回我们一个相同的消息“hello”

所以利用这个我们可以测试发送和接收消息,流程如下

  1. 我们在Activity中增加一个EditText和一个Button,点击Button,向服务器发送消息
  2. 服务器接收到消息后,向我们返回一个相同的消息
  3. 我们这边接收到消息时,JWebSocketClientService 中​​onMessage​​会执行,我们会拿到接收的消息,同时发出广播
  4. Activity中的广播接收器,接收到广播时,就可以更新UI,由于这不是重点,我们简单显示下

Android WebSocket实现即时通讯功能_客户端_02
Activity中修改的代码

//button添加点击事件,向服务器发送消息
btn_send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(client!=null && client.isOpen()){
client.send(et_message.getText().toString());
}
}
});

//接收到广播后,将服务器返回的消息显示出来
private class ChatMessageReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String message=intent.getStringExtra("message");
tv_message.append(message+"\n");
}
}

心跳检测和重连

由于很多不确定因素会导致 websocket 连接断开,例如网络断开,所以需要保证 websocket 的连接稳定性,这就需要加入心跳检测和重连

心跳检测其实就是个定时器,每隔一段时间检测一次,如果连接断开则重连,Java-WebSocket 框架在目前最新版本中有两个重连的方法,分别是​​reconnect()​​​和​​reconnectBlocking()​​,这里同样使用后者

在service中增加以下代码

//    -------------------------------------websocket心跳检测------------------------------------------------
private static final long HEART_BEAT_RATE = 10 * 1000;//每隔10秒进行一次对长连接的心跳检测
private Handler mHandler = new Handler();
private Runnable heartBeatRunnable = new Runnable() {
@Override
public void run() {
Log.e("JWebSocketClientService", "心跳包检测websocket连接状态");
if (client != null) {
if (client.isClosed()) {
reconnectWs();
}
} else {
//如果client已为空,重新初始化连接
initSocketClient();
}
//每隔一定的时间,对长连接进行一次心跳检测
mHandler.postDelayed(this, HEART_BEAT_RATE);
}
};

/**
* 开启重连
*/
private void reconnectWs() {
mHandler.removeCallbacks(heartBeatRunnable);
new Thread() {
@Override
public void run() {
try {
Log.e("JWebSocketClientService", "开启重连");
client.reconnectBlocking();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}

然后在​​onStartCommand​​中开启心跳检测

mHandler.postDelayed(heartBeatRunnable, HEART_BEAT_RATE);//开启心跳检测

运行程序后,每隔10s就会检测是否开启ws
Android WebSocket实现即时通讯功能_ide_03

资源下载

举报

相关推荐

0 条评论