Android 에서 WebSocket 을 사용 하여 메시지 통신 을 실현 하 는 방법 에 대한 상세 한 설명

머리말
메시지 푸 시 기능 은 모 바 일 앱 에 없어 서 는 안 될 기능 중 하나 라 고 할 수 있다.일반적으로 간단 한 푸 시 는 제3자 가 푸 시 하 는 SDK,예 를 들 어 극광 푸 시,전서구 푸 시 등 을 사용 할 수 있 지만 메시지 채 팅 과 같은 신속 성에 대한 요구 가 있 거나 제3자 푸 시 는 업무 수 요 를 만족 시 키 지 못 할 경우 우 리 는 WebSocket 을 사용 하여 메시지 푸 시 기능 을 실현 해 야 한다.
기본 절차
웹 소켓 이 무엇 인지 소개 하지 않 겠 습 니 다.여기 서 사용 하 는 오픈 소스 프레임 워 크 는https://github.com/TakahikoKawasaki/nv-websocket-client입 니 다.
오픈 소스 프로 토 콜 을 바탕 으로 저 희 는 WebSocket 의 연결,등록,심장 박동,메시지 배포,시간 초과 작업 기능 을 밀봉 하고 기본 적 인 절 차 는 다음 과 같 습 니 다.

연결 기능
우선 build.grade 에 설정 을 추가 하 는 항목 을 새로 만 듭 니 다.compile 'com.neovisionaries:nv-websocket-client:2.2'새 웹 소켓 관리 클래스 WsManger

public class WsManager {
 
 private volatile static WsManager wsManger;
 
 private WsManager() {
 }
 
 public static WsManager getWsManger() {
 if (wsManger == null) {
 synchronized (WsManager.class) {
 if (wsManger == null) {
  wsManger = new WsManager();
 }
 }
 }
 return wsManger;
 }
 
 
}
다음 연결 방법 을 추가 합 니 다.웹 소켓 의 상 태 를 세 가지 로 나 누 어 새 Ws Statue 매 거 진 클래스 에 대응 합 니 다.

public enum WsStatus {
 
 /**
 *     
 */
 CONNECT_SUCCESS,
 /**
 *     
 */
 CONNECT_FAIL,
 /**
 *     
 */
 CONNECTING;
}
연결 방법 은 다음 과 같다.

/**
 *                    
 */
public void connect() {
 //WEB_SOCKET_API     url  ,
 // CONNECT_TIMEOUT             5 
 try {
 ws = new WebSocketFactory().createSocket(WEB_SOCKET_API, CONNECT_TIMEOUT)
 //         5
 .setFrameQueueSize(5)
 //                   
 .setMissingCloseFrameAllowed(false)
 //      
 .addListener(new WsListener())
 //    
 .connectAsynchronously();
 } catch (IOException e) {
 e.printStackTrace();
 }
 setStatus(WsStatus.CONNECTING);
}
연결 방법 을 호출 한 후에 연결 의 리 셋 을 보 겠 습 니 다.바로 WsListener 입 니 다.

/**
 * websocket    
 */
private class WsListener extends WebSocketAdapter {
 
 
 @Override
 public void onConnected(WebSocket websocket, Map<String, List<String>> headers) throws Exception {
 Log.d(TAG, "onConnected:     ");
 }
 
 @Override
 public void onConnectError(WebSocket websocket, WebSocketException exception) throws Exception {
 Log.d(TAG, "onConnectError:     ");
 }
 
 @Override
 public void onDisconnected(WebSocket websocket, WebSocketFrame serverCloseFrame,
  WebSocketFrame clientCloseFrame,
  boolean closedByServer) throws Exception {
 Log.d(TAG, "onDisconnected:     ");
 
 }
 
 @Override
 public void onTextMessage(WebSocket websocket, String text) throws Exception {
 Log.d(TAG, "onTextMessage:     :" + text);
 }
}
다음은 연결 방법 을 호출 하 겠 습 니 다.

WsManager.getWsManger().connect();
프로젝트 를 실행 하면 다음 과 같은 인쇄 를 볼 수 있 습 니 다.
 
여기 서 우리 가 해 야 할 일 은 연결 이 실패 하거나 연결 이 끊 긴 리 셋 을 받 으 면 다시 연결 해 야 한 다 는 것 입 니 다.우 리 는 연결 방법 을 다시 호출 하면 됩 니 다.또한 세 번 의 리 셋 이 실패 하면 우 리 는 업무 중 에 인 터 페 이 스 를 호출 하여 데 이 터 를 얻 을 수 있 고 데이터 가 손실 되 지 않도록 할 수 있 습 니 다.이 디 테 일 은 생략 합 니 다.
프로 토 콜 패키지
이 프로 토 콜 은 다음 과 같 습 니 다.

{
 "action":"",
 "requestChild":{
 "clientType":"",
 "id":""
 }
}

심장 박동,전송 요청 은 모두 클 라 이언 트 가 주동 적 으로 요청 을 보 내 는 것 에 속 합 니 다.요청 결과 에 대해 우 리 는 성공 과 실패,시간 초과 로 나 눌 수 있 습 니 다.전송 시간 초과 에 대해 우 리 는 서버 의 어떠한 답장 도 받 을 수 없 기 때문에 보 낸 후에 시간 초과 작업 대기 열 에 보 내야 합 니 다.요청 이 성공 하면 작업 을 시간 초과 대기 열 에서 제거 해 야 합 니 다.시간 초과 대기 열 에서 작업 을 가 져 와 다시 요청 합 니 다.
시간 초과 작업 대기 열 에 성공,실패,시간 초과 가 있 습 니 다.
우 리 는 상기 협의 에 따라 대응 하 는 실체 류 를 추가 하고 Builder 디자인 모델 을 사용한다.

public class Request {
 
 /**
 *   
 */
 private String action;
 
 /**
 *    
 */
 private RequestChild req;
 
 
 /**
 *     
 */
 private transient int reqCount;
 
 /**
 *      
 */
 private transient int timeOut;
 
 
 public Request() {
 }
 
 
 public Request(String action, int reqCount, int timeOut, RequestChild req) {
 this.action = action;
 this.req = req;
 this.reqCount = reqCount;
 this.timeOut = timeOut;
 }
 
 
 public static class Builder {
 //action     
 private String action;
 //               
 private RequestChild req;
 //         
 private int reqCount;
 //    
 private int timeOut;
 
 public Builder action(String action) {
 this.action = action;
 return this;
 }
 
 
 public Builder req(RequestChild req) {
 this.req = req;
 return this;
 }
 
 
 public Builder reqCount(int reqCount) {
 this.reqCount = reqCount;
 return this;
 }
 
 public Builder timeOut(int timeOut) {
 this.timeOut = timeOut;
 return this;
 }
 
 public Request build() {
 return new Request(action, reqCount, timeOut, req);
 }
 
 }
}
 


public class RequestChild {
 
 /**
 *     
 */
 private String clientType;
 
 
 /**
 *        id
 */
 private String id;
 
 public RequestChild(String clientType, String id) {
 this.clientType = clientType;
 this.id = id;
 }
 
 public RequestChild() {
 }
 
 
 public static class Builder {
 private String clientType;
 private String id;
 
 public RequestChild.Builder setClientType(String clientType) {
 this.clientType = clientType;
 return this;
 }
 
 
 public RequestChild.Builder setId(String id) {
 this.id = id;
 return this;
 }
 
 
 public RequestChild build() {
 return new RequestChild(clientType, id);
 }
 
 }
 
 
}
요청 을 보 내 는 방법 은 다음 과 같 습 니 다.

/**
 *     
 *
 * @param request    
 * @param reqCount     
 * @param requestListern     
 */
private void senRequest(Request request, final int reqCount, final RequestListern requestListern) {
 if (!isNetConnect()) {
 requestListern.requestFailed("     ");
 return;
 }
 
}
다음 과 같이 반전 을 요청 합 니 다.

public interface RequestListern {
 
 /**
 *     
 */
 void requestSuccess();
 
 /**
 *     
 *
 * @param message         
 */
 void requestFailed(String message);
}
이어서 우 리 는 요청 을 시간 초과 대기 열 에 놓 아야 한다.새 시간 초과 작업 클래스 는 요청 파라미터,요청 리 셋,작업 스케줄 링 에 대응한다.

public class TimeOutTask {
 
 
 /**
 *     
 */
 private Request request;
 
 /**
 *     
 */
 private RequestCallBack requestCallBack;
 
 /**
 * r  
 */
 private ScheduledFuture scheduledFuture;
 
 
 public TimeOutTask(Request request,
  RequestCallBack requestCallBack,
  ScheduledFuture scheduledFuture) {
 this.request = request;
 this.requestCallBack = requestCallBack;
 this.scheduledFuture = scheduledFuture;
 }
 
 public ScheduledFuture getScheduledFuture() {
 return scheduledFuture;
 }
 
 public void setScheduledFuture(ScheduledFuture scheduledFuture) {
 this.scheduledFuture = scheduledFuture;
 }
 
 public Request getRequest() {
 return request;
 }
 
 public void setRequest(Request request) {
 this.request = request;
 }
 
 public RequestCallBack getRequestCallBack() {
 return requestCallBack;
 }
 
 public void setRequestCallBack(RequestCallBack requestCallBack) {
 this.requestCallBack = requestCallBack;
 }
 
}
RequestCallBack 은 시간 초과 작업 의 리 셋 입 니 다.리 셋 을 요청 하 는 것 보다 시간 초과 가 많 을 뿐 입 니 다.시간 초과 처리 메커니즘 이 같 기 때문에 시간 초과 리 셋 을 요청 할 필요 가 없습니다.

public interface RequestCallBack {
 
 /**
 *     
 */
 void requestSuccess();
 
 /**
 *     
 *
 * @param request    
 * @param message        
 */
 void requestFailed(String message, Request request);
 
 /**
 *     
 *
 * @param request    
 */
 void timeOut(Request request);
}
/**
 *       
 */
private ScheduledFuture enqueueTimeout(final Request request, final long timeout) {
 Log.d(TAG, " " + "enqueueTimeout:          :" + request.getAction());
 return executor.schedule(new Runnable() {
 @Override
 public void run() {
 TimeOutTask timeoutTask = callbacks.remove(request.getAction());
 if (timeoutTask != null) {
 timeoutTask.getRequestCallBack().timeOut(timeoutTask.getRequest());
 }
 }
 }, timeout, TimeUnit.MILLISECONDS);
}
시간 초과 작업 의 방법 은 작업 스케줄 을 통 해 정시 에 호출 하 는 것 입 니 다.요청 이 성공 한 후에 우 리 는 시간 초과 작업 을 제거 할 것 입 니 다.시간 초과 시간 이 되면 작업 이 존재 한 다 는 것 은 작업 시간 초과 임 무 를 설명 합 니 다.
매번 작업 은 action 을 키 로 hashMap 에 존재 합 니 다.

private Map<String, CallbackWrapper> callbacks = new HashMap<>();
시간 초과 작업 코드 에 작업 을 넣 으 면 다음 과 같 습 니 다.

final ScheduledFuture timeoutTask = enqueueTimeout(request, request.getTimeOut());
 
final RequestCallBack requestCallBack = new RequestCallBack() {
 @Override
 public void requestSuccess() {
 requestListern.requestSuccess();
 }
 
 @Override
 public void requestFailed(String message, Request request) {
 requestListern.requestFailed(message);
 }
 
 @Override
 public void timeOut(Request request) {
 timeOutHanlder(request);
 }
};
callbacks.put(request.getAction(),
 new CallbackWrapper(request, requestCallBack, timeoutTask));
일반적으로 작업 시간 초과 가 연결 원인 으로 인해 발생 하기 때문에 다시 시도 해 볼 수 있 습 니 다.시간 초과 일 경우 timeOutHanlder(request)를 통 해 다시 시도 할 수 있 습 니 다.방법 은 다시 연결 하고 코드 를 다시 연결 하 는 것 은 연결 코드 와 마찬가지 로 여 기 는 생략 합 니 다.이 작업 을 잘 하면 우 리 는 메 시 지 를 보 낼 수 있 습 니 다.

/**
 *     
 */
private void timeOutHanlder(Request requset) {
 setStatus(WsStatus.CONNECT_FAIL);
 //       
 Log.d(TAG, "timeOutHanlder:          ");
}
여기까지 우리 의 절 차 는 기본적으로 통할 수 있다.
가슴 이 두근거리다
우선 우 리 는 심장 박동 의 작용 이 무엇 인지 알 아야 한다.심장 박동 은 연결 에 성공 한 후에 고정된 간격 을 통 해 서버 에 문의 하 는 것 이다.현재 아직 온라인 상태 인지,많은 사람들 이 심장 박동 이 실패 하면 우 리 는 다시 연결 되 고 성공 하면 심장 박동 을 계속 하 는 것 이 라 고 말한다.그러나 여기 서 주의해 야 할 것 은 우 리 는 일반적으로 심장 박동 실패 의 반전 을 받 지 못 하고 심장 박동 도 서버 에 데 이 터 를 보 내 는 것 이다.그래서 우 리 는 모든 주동 적 인 요청 을 시간 초과 작업 대기 열 에 두 어야 합 니 다.
따라서 웹 소켓 에 대한 요청 결 과 는 세 가지 가 있 습 니 다.성공,실패,시간 초과,사용자 에 게 성공,실패 만 있 으 면 됩 니 다.
심장 박동,등록 등 요청 한 데이터 가 무엇 인지 에 대해 서 는 서버 와 의 협의 가 어떻게 되 는 지 에 달 려 있 습 니 다.일반적으로 action 과 requestBody 로 나 뉘 는데 협의 형식 은 두 번 째 단계 로 봉 인 했 습 니 다.여기 서 우 리 는 심장 박동 임 무 를 예 로 들 어 위의 포장 을 검증 합 니 다.

/**
 *   
 */
void keepAlive() {
 
 Request request = new Request.Builder()
 .reqCount(0)
 .timeOut(REQUEST_TIMEOUT)
 .action(ACTION_KEEPALIVE).build();
 
 WsManager.getWsManger().senRequest(request, request.getReqCount() + 1, new RequestListern() {
 @Override
 public void requestSuccess() {
 Log.d(TAG, "requestSuccess:        ");
 }
 
 @Override
 public void requestFailed(String message) {
 }
 });
}
저 희 는 10s 간격 으로 심장 박동 미 션 을 한 번 씩 시작 합 니 다.

/**
 *     
 */
public void startKeepAlive() {
 mHandler.postDelayed(mKeepAliveTask, HEART_BEAT_RATE);
}
/**
 *     
 */
private Runnable mKeepAliveTask = new Runnable() {
 
 @Override
 public void run() {
 keepAlive();
 mHandler.removeCallbacks(mKeepAliveTask);
 mHandler.postDelayed(mKeepAliveTask, HEART_BEAT_RATE);
 }
};
프 리 젠 테 이 션 을 편리 하 게 하기 위해 홈 페이지 에 단 추 를 추가 하고 단 추 를 누 르 면 startKeepAlive 방법 을 호출 합 니 다.다음 과 같이 실행 합 니 다. 

심장 박동 이 돌아 오 는 statue 는 300 이 성공 하지 못 한 것 을 볼 수 있 습 니 다.5 초 후에 요청 시간 초과 방법 에 도 착 했 습 니 다.따라서 상태 가 성공 하면 호출 자 에 게 되 돌려 주어 야 합 니 다.

/**
 *        
 *
 * @param action     
 */
void disPatchCallbackWarp(String action, boolean isSuccess) {
 CallbackWrapper callBackWarp = callbacks.remove(action);
 if (callBackWarp == null) {
 Logger.d(TAG+" "+ "disPatchCallbackWarp:       ");
 } else {
 callBackWarp.getScheduledFuture().cancel(true);
 if (isSuccess) {
 callBackWarp.getRequestCallBack().requestSuccess();
 } else {
 callBackWarp.getRequestCallBack().requestFailed("", new Request());
 }
 
 }
}
이렇게 호출 해 야 성공 이나 실 패 를 알 수 있다.
다른 메 시 지 를 보 내 는 것 은 심장 박동 과 마찬가지 로 요청 인자 만 다 를 뿐 Request 인 자 를 수정 하면 됩 니 다.이렇게 해서 우 리 는 협의 와 업무 에 따라 비교적 규범 화 된 웹 소켓 메시지 전송 절 차 를 실현 했다.
 안 드 로 이 드 에서 웹 소켓 을 사용 하여 메시지 통신 을 실현 하 는 방법 에 대한 상세 한 설명 은 여기까지 입 니 다.더 많은 안 드 로 이 드 가 웹 소켓 을 사용 하여 메시지 통신 을 실현 하 는 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 많이 응원 해 주세요!

좋은 웹페이지 즐겨찾기