1项目中接口需要使用socket网络请求,大概有十几个接口。之前用过rxjava简单封装过些简单的http请求的接口,
现在也想按照那种思维模式老封装一下。总体思路是发送数据时传一个bean过去,接收时直接返回已经解析好的
bean,用面向对象的方法编程。如果像以前一样一个工具类中写死好多socket请求的方法,这样耦合性太强,牵一发动全身。 所以使用rxjava 2.0小小封装一下。
package com.socketutil;
import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Arrays;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
/**
* Created by admin on 2018/8/3.
*/
public class RxSocket {
static RxSocket rxSocket;
OutputStream outputStream = null;
Socket socket = null;
InputStream inputStream = null;
/** 读取数据超时时间 */
final int READ_TIMEOUT = 15 * 1000;
/** 连接超时时间 */
final int CONNECT_TIMEOUT = 5 * 1000;
final String IP = "218.29.74.138";
final int PORT = 11274;
final String TAG = "RxSocket-->",SUCCEED="初始化成功",TIMEOUT="连接超时",SEND_ERROR="发送数据异常";
/** 网络返回的监听 */
SocketListener observer;
public boolean isCancle = false;
private RxSocket() {
Observable.just("")
.subscribeOn(Schedulers.io())
.subscribeOn(AndroidSchedulers.mainThread())
.doOnNext(s -> initSocket(IP, PORT))
.subscribe(s -> Log.d(TAG, SUCCEED));
}
public static RxSocket getInstance() {
if (rxSocket == null) {
rxSocket = new RxSocket();
}
return rxSocket;
}
/**
* 初始化蓝牙通信,需要放在子线程
* @param ip {@link RxSocket#IP} ip地址
* @param port {@link RxSocket#PORT} 端口号
*/
private void initSocket(String ip,int port) throws Exception{
try {
socket = new Socket();
socket.setSoTimeout(READ_TIMEOUT);
Log.d(TAG, ip+":"+port);
socket.connect(new InetSocketAddress(InetAddress.getByName(ip),port),CONNECT_TIMEOUT);
outputStream = socket.getOutputStream();
inputStream = socket.getInputStream();
} catch (IOException e) {
Log.d(TAG, TIMEOUT);
e.printStackTrace();
throw new Exception(TIMEOUT);
}
}
/**
* 发送数据
* @return 接口返回的数据
*/
private String sendData(String data) throws Exception{
StringBuilder result = new StringBuilder("");
try {
outputStream.write(data.getBytes("UTF-8"));
byte[] b = new byte[1024];
int reads = inputStream.read(b);
while (reads > 0) {
byte[] bytes = Arrays.copyOfRange(b, 8, reads);
String temp = new String(bytes);
result.append(temp);
reads = 0;
b = new byte[1024];
reads = inputStream.read(b);
}
Log.d(TAG, result.toString());
return result.toString();
} catch (Exception e) {
Log.d(TAG, e.getMessage());
e.printStackTrace();
throw new Exception(SEND_ERROR);
}
}
/**
* 取消所有的请求
* @param isCancle true:取消访问 false:允许访问
*/
public void cancleAll(boolean isCancle) {
this.isCancle = isCancle;
observer.cancleListen();
}
/**
* socket 发送数据,并返回数据
* @param baseRequestBean 可以一次发送多个请求
* (后期可以添加重试机制)
*/
public void request(BaseRequestBean ...baseRequestBean) {
if (observer!=null)
Observable.fromArray(baseRequestBean)
.subscribeOn(Schedulers.io())
.filter(baseRequestBean1 -> isCancle)
.map(baseRequestBean1 -> {
String result = sendData(baseRequestBean1.get());
if (result.length()>0 && isCancle)
baseRequestBean1.parseData(result);
return baseRequestBean1;
})
.filter(baseRequestBean1 -> isCancle)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(observer);
}
/**
* 设置网络返回的监听
* @param listener
*/
public void setResultListener(SocketListener listener) {
this.observer = listener;
}
}
//注册请求的回调
RxSocket.getInstance().setResultListener(new SocketListener(){
@Override
public void onSuccess(BaseRequestBean bean){
if(bean.method.eqals(login.method)){
}else if(bean.method.eqals(login3.method)){
}
}
@Override
public void onExecption(Throwable throwable){
}
})
//定义解析的bean
class LoginRes {
String name;
}
//定义请求的bean,可以写成一个类 把泛型写上
class Login extends BaseRequestBean{
public Login(){
super();
}
@Override
String getRequsetData() {
return "BBFFAAA";
}
@Override
LoginRes parseData(String data) {
//解析规则,并返回对应的bean
return new LoginRes();
}
@Override
String methods() {
return "login";
}
}
//只有1个网络请求
Login login = new Login();
RxSocket.getInstance().request(login);
//多个网络请求
RxSocket.getInstance().request(login,login1,login2,login3);
对于异常处理全部内部捕捉了,这个不是一个好策略,应该直接抛处理给rxjava,并应该在onError方法中
根据不同逻辑不同处理。如果大家需要使用的话还是建议先按照自己的需求改造下,再使用,有可能有bug
其他的类也一起放上来
/**
* Created by admin on 2018/8/3.
*/
public interface SupplierHeader {
/**
* Gets a result.
* @return a result
*/
T getHeader();
}
/**
* Created by admin on 2018/8/3.
*/
public interface Supplier {
/**
* Gets a result.
* @return a result
*/
T get();
}
/**
* Created by admin on 2018/8/3.
*/
public abstract class SocketListener implements Observer {
abstract void onSuccess(BaseRequestBean bean);
abstract void onExecption(Throwable throwable);
Disposable disposable;
@Override
public void onSubscribe(Disposable disposable) {
this.disposable = disposable;
}
@Override
public void onNext(BaseRequestBean bean) {
onSuccess(bean);
}
@Override
public void onError(Throwable throwable) {
onExecption(throwable);
}
@Override
public void onComplete() {
}
/**
* 取消socket 监听
*/
public void cancleListen() {
if (disposable!=null && !disposable.isDisposed()) {
disposable.dispose();
}
}
}
/**
* Created by admin on 2018/8/3.
* Socket 请求和返回的鸡肋
* 1:请求时组织请求的数据
* 2:解析时根据返回的数据相应解析
*/
public abstract class BaseRequestBean implements Supplier,Consumer,SupplierHeader {
abstract String getRequsetData();
abstract T parseData(String data);
public T resultBean; //解析结果的bean
public String method;//标记请求
String methods();//标记请求
public BaseRequestBean (){
method=methods();
}
/**
* socket 发送数据的回掉接口
* @return 需要发送的数据
*/
@Override
public String get() {
return getRequsetData();
}
/**
* 接收socket 返回的数据回掉;
* @param s
* @throws Exception
*/
@Override
public void accept(String s) throws Exception {
parseData(s);
}
/**
* Socket请求头接口
* @return socket报文头
*/
@Override
public String getHeader() {
return null;
}
}