前面已经把功能都写清楚了,这儿稍做总结,并介绍一下运用办法。
小结
整个模块主要写了五个文件,如下:
- BaseRequest
- BaseResponse
- ResponseCallback
- ConnectService
- ConnectManager
其间 ResponseCallback 时回调接口,另外是恳求基类和回复基类,ConnectService 负责 socket 的接纳发送工作,ConnectManager 负责向外暴漏,并提供线程转化、超时操控等功能。
简略运用
这儿简略说一下运用,涉及到数据协议的界说,无论是恳求仍是回复,类型如下:
- 0 – 4 音讯类型
- 4 – 8 音讯流水号
- 8 – 12 后边数据域长度
- 12 + 具体数据
由上面自界说的数据协议,咱们来设计恳求类、回复类,并简略运用下。
恳求类
public class SwitchFanRequest extends BaseRequest {
public SwitchFanRequest(ResponseCallback presenter) {
this.requestMsgType = ID_FAN_REQ ;
this.responseMsgType = ID_FAN_RSP;
this.data = getByteData();
this.callback = presenter;
setStartTime(System.currentTimeMillis());
setThreshold(5000);
//isSendOut = false; //仅注册
//wantNumb = -1; //表示接纳无限制
}
@Override
public byte[] getByteData() {
byte[] bytes = new byte[16];
ByteBuffer buffer = ByteBuffer.wrap(bytes);
buffer.putInt(requestMsgType);
buffer.putInt(Utils.generateSerialNumber());
buffer.putInt(4);
//风扇开关 0 - 关 1 - 开
int open = MyApplication.config.isFanOpen ? 1 : 0;
buffer.putInt(open);
//log...
return bytes;
}
}
这是一个打开设备开关的恳求,结构函数中设置数据,重写 getByteData 函数将数据转化成字节数组,可以在这打印日志.
回复类
public class SwitchFanResponse extends BaseResponse {
public int isOpen;
public String code;
public static SwitchFanResponse parseResponse(BaseResponse response) {
SwitchFanResponse switchFanResponse = new SwitchFanResponse();
switchFanResponse.responseMsgType = response.responseMsgType;
switchFanResponse.serialNumber = response.serialNumber;
switchFanResponse.data = response.data;
//转化数据
switchFanResponse.parseData();
return switchFanResponse;
}
@Override
protected void parseData() {
resultCode = 1;
//获取 int 型数据
isOpen = ByteBuffer.wrap(data,0, 4).getInt();
//获取字符串数据,包括中文
try {
Charset charset = Charset.forName("GB2312");
CharsetDecoder decoder = charset.newDecoder();
code = decoder.decode(ByteBuffer.wrap(data, 4, 100)).toString();
if (code.contains("\0")){
code = code.substring(0, code.indexOf("\0"));
}
} catch (CharacterCodingException e) {
e.printStackTrace();
}
//log...
}
}
这是一个打开设备开关的回复,由于我不想每个回复类都去序列化,所以基类序列化后,通过基类得到对应子类就可以。运用静态的 parseResponse 办法,将基类转化为子类,运用的时候自己注意下别用错子类了就可以。
为了演示,我这假设会回复一些数据,大致便是 int 型和字符串类型吧,运用办法看代码。
初始化
@Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
bindConnectService();
}
@Override
public void onTerminate() {
unbindConnectService();
super.onTerminate();
}
private void bindConnectService() {
ConnectManager.getInstance().bindConnectService(this);
//HxzSimulateUtil.startSimulate();
}
private void unbindConnectService() {
ConnectManager.getInstance().unbindConnectService(this);
HxzManager.getInstance().unbindConnectService(context);
}
直接再 Application 中发动 ConnectService,这样就可以发送音讯了。
发送音讯
ConnectManager manager = ConnectManager.getInstance();
//获取初始化参数
manager.setUpSocketConfigure(getSocketConfigure());
manager.sendMessage(new ConnectRequest(new ResponseCallback() {
@Override
public void onResponse(BaseResponse response) {
//从基类回复转化,得到具体子类回复
ConnectResponse response = ConnectResponse.parseResponse(response);
mLoginView.onLogin(response.xxx);
}
//默许办法,可写可不写,看需要
// @Override
// public void onError(int requestMsgType) {
// mLoginView.onError();
// }
//
// @Override
// public void onTimeout(int requestMsgType) {
// mLoginView.onTimeout();
// }
}));
//获取初始化参数
private Bundle getSocketConfigure() {
Bundle bundle = new Bundle();
bundle.putString("IP", "192.168.1.110");
bundle.putInt("PORT", 2050);
bundle.putInt("WAIT", 5000);
byte[] bytes = new byte[12];
ByteBuffer buffer = ByteBuffer.wrap(bytes);
buffer.putInt(ID_CONNECT_REQ);
buffer.putInt(Utils.generateSerialNumber());
buffer.putInt(0);
bundle.putByteArray("ConnectData", bytes);
return bundle;
}
这儿便是拿到 ConnectManager 后,初始化衔接参数(一次就好),并发送恳求,上面是衔接时候的用法,后边就简略多了:
ConnectManager.getInstance().sendMessage(new SwitchFanRequest(response -> {
SwitchFanResponse res = SwitchFanResponse.parseResponse(response);
int isOpen = res.isOpen;
String code = res.code;
...
}));
结合默许办法可写可不写,onError、onTimeout 不写之后,配合 lambda 表达式,几行代码就可以搞定 socket 通信,看上面代码简略不简略!!!
结语
这儿便是整个 socket 通信模块的运用了,咱们一步一步将各个功能实现,最终将这个 socket 通信缩短为几行代码,仍是挺有成就感的。
end