客户端与服务器端交互数据需要进行通信,本文介绍安卓客户端是如何与服务器端进行通信的,包括客户端连接服务器端、客户端向服务器端发送请求、将请求信息封装成请求单元、将请求单元存放到队列、从队列中获取请求单元并执行请求。主要的步骤为:”客户端配置请求服务器的ip地址”、“”客户端向服务器端发送请求”、“将一个请求封装成请求单元HttpRequestUnit”、“将请求单元放到一个队列中,开启一个线程执行队列中的请求”、“HttpRequestManager类负责缓存和获取HttpRequestThread对象”。
1、客户端配置请求服务器的ip地址。
设置服务器的IP地址,如果是在自己的电脑运行服务器项目,那就设置成电脑的ip地址,然后客户端和电脑要连接同一个网络,确保在同一局域网。
(1)打开cmd命令行窗口,输入ipconfig命令查看电脑的本机ip地址。
(2)在Configuration类配置服务器ip地址。
public final class Configuration {
public static final String APP_Config_Key_env = "env";
public static final String SERVER_IP_DEV = "https://dev.wx.bxit.vip/";
public static final String SERVER_IP_SIT = "https://sit.wx.bxit.vip/";
public static final String SERVER_IP_UAT = "https://uat.wx.bxit.vip/";
public static final String SERVER_IP_PRODUCTION = "https://account.prosalesbox.cn/";
public static String HTTP_IP = "http://192.168.123.144/";//运行Pos_Local测试时,要确保与Pos在同一局域网;搞清楚NBR的IP是多少,并填写在这里
2、客户端向服务器端发送请求。
(1)创建请求体RequestBody对象。
RequestBody body = new FormBody.Builder()
.add(staff.field.getFIELD_NAME_phone(), staff.getPhone())
.build();
(2)创建Request对象。
Request request = new Request.Builder()
.url(Configuration.HTTP_IP + "staff/getTokenEx.bx")
.addHeader(BaseHttpBO.COOKIE, GlobalController.getInstance().getSessionID())
.post(body)
.build();
(3)发送请求。
httpEvent.setStatus(BaseEvent.EnumEventStatus.EES_Http_ToDo);
HttpRequestUnit hru1 = new StaffGetToken();
hru1.setRequest(request);
hru1.setTimeout(TIME_OUT);
hru1.setbPostEventToUI(true);
hru1.setEvent(httpEvent);
HttpRequestManager.getCache(HttpRequestManager.EnumDomainType.EDT_Communication).pushHttpRequest(hru1);
3、将一个请求封装成请求单元HttpRequestUnit。
HttpRequestUnit定义为一个请求单元,它实现了okhttp3.Call接口,实现了请求成功和请求失败的回调方法onResponse和onFailure:
public abstract class HttpRequestUnit implements Callback
(1) 请求成功后执行onResponse方法。
获取到服务器返回的数据,做下一步处理:
@Override
public void onResponse(Call call, Response response) throws IOException {
log.info("请求后返回的response:" + response);
dateEnd = new Date(System.currentTimeMillis() + NtpHttpBO.TimeDifference);
if (isTimeout(call)) {
event.setLastErrorCode(ErrorInfo.EnumErrorCode.EC_Timeout);
return;
}
log.info(" Http onResponse,收到服务器的响应");
if (NtpHttpBO.bForNtpOnly) {// 在同步的时候设置POS接收到答复的时间,用于POS机与服务器同步时间
event.setData(new Date(System.currentTimeMillis() + NtpHttpBO.TimeDifference).getTime());
NtpHttpBO.bForNtpOnly = false;
}
event.setLastErrorCode(ErrorInfo.EnumErrorCode.EC_NoError);
if (bPostEventToUI) {
event.setRequestType(getEnumRequestType());
event.setResponseData(response.body().string());
event.setResponse(response);
//...设置Event状态???
EventBus.getDefault().post(event);
}
}
(2)请求失败后执行onFailure方法。
@Override
public void onFailure(Call call, IOException e) {
this.event.setEventProcessed(true); //终止UI层的等待
//...
log.info(" Http onFailure,向服务器发送请求失败。异常信息:" + e.getMessage());
dateEnd = new Date(System.currentTimeMillis() + NtpHttpBO.TimeDifference); //用于计算超时
if (isTimeout(call)) {
event.setLastErrorCode(ErrorInfo.EnumErrorCode.EC_Timeout);
} else {
event.setLastErrorCode(ErrorInfo.EnumErrorCode.EC_OtherError);
}
this.event.setLastErrorMessage(BaseHttpBO.ERROR_MSG_Network);
//
GlobalController.getInstance().setSessionID(null);
//
EventBus.getDefault().post(event);
}
4、将请求单元放到一个队列中,开启一个线程执行队列中的请求。
HttpRequestThread 继承了 Thread,负责将一个个HttpRequestUnit放到队列当中,并且开启一个线程,不停的从队列中获取HttpRequestUnit,执行请求:
public class HttpRequestThread extends Thread {
protected Queue<HttpRequestUnit> queue;
(1)将请求单元HttpRequestUnit放到队列queue中。
public void pushHttpRequest(HttpRequestUnit hu) {
if (hu != null) {
lock.writeLock().lock();
queue.offer(hu);
lock.writeLock().unlock();
}
synchronized (this) {
notify();
}
}
(2)启动线程的run方法,执行doTask()方法。
@Override
public void run() {
while (atomicInteger.get() != SIGNAL_ThreadExit) {
lock.writeLock().lock();
doTask();
lock.writeLock().unlock();
synchronized (this) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
log.info("线程:" + this.getName() + "已经退出");
}
(3)doTask方法从队列中获取请求单元HttpRequestUnit,并交给okhttp3.OkHttpClient对象执行请求。
protected void doTask() {
while (!queue.isEmpty()) {
lock.writeLock().lock();
HttpRequestUnit hu = queue.poll();
if (hu == null) {
lock.writeLock().unlock();
break;
}
hu.setDateStart(new Date(System.currentTimeMillis() + NtpHttpBO.TimeDifference));
GlobalController.client.newCall(hu.getRequest()).enqueue(hu);
lock.writeLock().unlock();
}
}
(4)client为okhttp3.OkHttpClient对象。
//设置OKHttp的超时时间
public static OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(HTTP_REQ_Timeout, TimeUnit.SECONDS)
.readTimeout(HTTP_REQ_Timeout, TimeUnit.SECONDS)
.writeTimeout(HTTP_REQ_Timeout, TimeUnit.SECONDS)
.build();
5、HttpRequestManager类负责缓存和获取HttpRequestThread对象。
public class HttpRequestManager {
public enum EnumDomainType {
EDT_Communication("EDT_Communication", 0), //
EDT_Authentication("EDT_Authentication", 1);
……
private static HashMap<EnumDomainType, HttpRequestThread> list = new HashMap<EnumDomainType, HttpRequestThread>();
public static void register(EnumDomainType ect, HttpRequestThread bc) {
list.put(ect, bc);
}
public static HttpRequestThread getCache(EnumDomainType ect) {
return list.get(ect);
}