[전] 안 드 로 이 드 와 서버 의 상호작용 대 용량 데이터 문 제 를 해결 합 니 다.
데이터 가 너무 큰 문 제 를 해결 하 는 가장 직관 적 인 방법 은 바로 데 이 터 를 압축 하 는 것 이다.서버 는 전달 해 야 할 데 이 터 를 먼저 압축 한 다음 에 안 드 로 이 드 클 라 이언 트 에 보 냅 니 다. 안 드 로 이 드 클 라 이언 트 는 압축 된 데 이 터 를 받 아 압축 을 풀 고 압축 전의 데 이 터 를 얻 습 니 다.
만약 에 안 드 로 이 드 클 라 이언 트 와 서버 의 상호작용 데이터 가 특정한 압축 알고리즘 을 거 친 데이터 여야 한다 고 규정 하면 이런 '규정' 은 구체 적 인 상황 에 따라 정 해진 유연성 을 잃 게 된다.필 자 는 Http 프로 토 콜 을 패 키 징 하여 전송 할 데 이 터 를 동적 으로 선택 하여 압축 해 야 하 는 지, 클 라 이언 트 도 동적 으로 식별 하여 서버 가 보 내 고 싶 은 데 이 터 를 정리 하고 얻 을 수 있 는 지 를 계획 합 니 다.Android 클 라 이언 트 가 서버 에 특정한 데 이 터 를 요청 합 니 다. 이 데 이 터 는 압축 을 거 쳐 전달 하 는 것 이 적당 할 수도 있 고 원생 데 이 터 를 전달 하 는 것 이 적당 할 수도 있 습 니 다.즉, 필 자 는 하나의 협 의 를 설계 하고 자 한다. 이런 협 의 는 데 이 터 를 전송 하 는 데 적용 되 는 데이터 양 이 동태 적 으로 전환 되 고 작은 데이터 일 수도 있 으 며 데이터 양 이 많은 빅 데이터 일 수도 있다 (빅 데 이 터 는 압축 을 거 쳐 야 한다).
추상 적 으로 말 할 수 있 으 니 실제 상황 으로 설명 하 겠 습 니 다.
제 프로젝트 의 실제 상황 은 이 렇 습 니 다. 이 프로젝트 는 안 드 로 이 드 펀드 클 라 이언 트 를 만 드 는 것 입 니 다. 안 드 로 이 드 클 라 이언 트 는 서버 에 특정한 펀드 의 역사 동향 정 보 를 요청 합 니 다. 제 안 드 로 이 드 클 라 이언 트 가 로 컬 캐 시 를 실 현 했 기 때문에 데 이 터 를 전달 하 는 크기 가 매우 큽 니 다.만약 에 로 컬 캐 시 의 역사 동향 정보의 최신 날짜 가 5 월 5 일이 고 서버 의 역사 동향 정보의 최신 날짜 가 5 월 7 일이 라면 서버 는 5 월 6 일과 5 월 7 일 이틀 간 의 동향 정 보 를 보 내 는 것 과 같이 이 데 이 터 는 매우 작 아서 압축 할 필요 가 없다.(제 가 사용 하 는 압축 알고리즘 은 데이터 양 이 너무 적은 데이터 압축 이 이상 적 이지 않 고 데이터 양 이 너무 적은 데 이 터 를 압축 한 데 이 터 는 압축 전의 데이터 보다 클 것 입 니 다)그러나 안 드 로 이 드 클 라 이언 트 는 어떤 펀드 에 대해 캐 시 정보 가 없 을 수도 있 습 니 다. 그러면 서버 가 보 낸 데 이 터 는 지난 3, 4 년 간 의 역사적 동향 정보 가 될 것 입 니 다. 이 데 이 터 는 약간 클 라 이언 트 가 압축 해서 전달 해 야 합 니 다. 그러면 클 라 이언 트 는 같은 요청 으로 얻 은 데이터 에 대해 압축 된 데이터 인지 압축 되 지 않 은 데이터 인지 어떻게 판단 합 니까?
필자 가 사용 하 는 솔 루 션 은 데 이 터 를 전달 하 는 첫 번 째 바이트 를 표지 바이트 로 하고 이 데 이 터 를 압축 했 는 지 여 부 를 표시 하 는 것 입 니 다. 데 이 터 를 전달 하 는 인 코딩 문제 도 표시 할 수 있 습 니 다. Android 는 받 은 데이터 (바이트 배열) 에 대해첫 번 째 바이트 의 데 이 터 를 먼저 판단 하면 대표 적 인 데이터 형식 과 인 코딩 정보 에 따라 해당 하 는 조작 을 할 수 있 습 니 다. 그렇게 많은 말 을 했 으 니 실제 코드 를 보 는 것 보다 빨리 이해 하지 못 할 수도 있 습 니 다. 먼저 압축 알고리즘 입 니 다. 여기 서 필 자 는 jdk 자체 의 zip 압축 알고리즘 을 사용 합 니 다.
package com.chenjun.utils.compress;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
public class Compress {
private static final int BUFFER_LENGTH = 400;
// , ,
public static final int BYTE_MIN_LENGTH = 50;
//
public static final byte FLAG_GBK_STRING_UNCOMPRESSED_BYTEARRAY = 0;
public static final byte FLAG_GBK_STRING_COMPRESSED_BYTEARRAY = 1;
public static final byte FLAG_UTF8_STRING_COMPRESSED_BYTEARRAY = 2;
public static final byte FLAG_NO_UPDATE_INFO = 3;
/**
*
*
* @param is
* @param os
* @throws Exception
*/
public static void compress(InputStream is, OutputStream os)
throws Exception {
GZIPOutputStream gos = new GZIPOutputStream(os);
int count;
byte data[] = new byte[BUFFER_LENGTH];
while ((count = is.read(data, 0, BUFFER_LENGTH)) != -1) {
gos.write(data, 0, count);
}
gos.finish();
gos.flush();
gos.close();
}
/**
*
*
* @param is
* @param os
* @throws Exception
*/
public static void decompress(InputStream is, OutputStream os)
throws Exception {
GZIPInputStream gis = new GZIPInputStream(is);
int count;
byte data[] = new byte[BUFFER_LENGTH];
while ((count = gis.read(data, 0, BUFFER_LENGTH)) != -1) {
os.write(data, 0, count);
}
gis.close();
}
/**
*
*
* @param data
* @return
* @throws Exception
*/
public static byte[] byteCompress(byte[] data) throws Exception {
ByteArrayInputStream bais = new ByteArrayInputStream(data);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//
compress(bais, baos);
byte[] output = baos.toByteArray();
baos.flush();
baos.close();
bais.close();
return output;
}
/**
*
*
* @param data
* @return
* @throws Exception
*/
public static byte[] byteDecompress(byte[] data) throws Exception {
ByteArrayInputStream bais = new ByteArrayInputStream(data);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//
decompress(bais, baos);
data = baos.toByteArray();
baos.flush();
baos.close();
bais.close();
return data;
}
}
외부 호출 방법 은 by teCompress () 와 by teDecompress () 입 니 다.byte 배열 을 수신 합 니 다. byte Compress 는 데이터 압축 방법 입 니 다. 압축 된 배열 의 데 이 터 를 되 돌려 줍 니 다. byte Decompress 는 데이터 압축 해제 방법 으로 압축 해 제 된 byte 배열 의 데 이 터 를 되 돌려 줍 니 다. FLAG GBK STRING COMPRESSED BYTEARRAY 는 서버 가 전달 하 는 데 이 터 는 GBK 인 코딩 문자열 이 압축 된 바이트 배열 임 을 표시 합 니 다. 다른 상수 도 그 이름 에 따라 정리 할 수 있 습 니 다.풀이. (여기 서 한 마디 더 하면 인 코딩 방식 과 압축 여 부 를 가 진 표지 위 치 를 분리 하 는 것 이 좋 습 니 다. 예 를 들 어 표지 바이트 의 앞 네 자 리 를 표지 인 코딩 방식 의 위치 로 정의 하고 뒤에 네 자 리 를 압축 여부 나 다른 정보의 표지 위치 로 표시 하 며 위치 와 또는 방식 으로 표지 위 치 를 판단 하 는 것 이 좋 습 니 다. 필 자 는 여기 서 게 으 름 을 피 워 서 바로 이렇게 썼 습 니 다.)
다음은 데 이 터 를 전달 하 는 방법 (압축 여 부 를 판단) 입 니 다. 저 는 Struts 1 프레임 워 크 를 사용 하여 Action 에서 데 이 터 를 조직 하고 해당 하 는 처리 (압축 또는 압축 하지 않 음) 를 하여 보 냅 니 다.
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
JjjzForm jjjzForm = (JjjzForm) form;
//
ArrayList<Jjjz> jjjzs = null;
//
Gson gson = new Gson();
String jsonStr = gson.toJson(jjjzs, jjjzs.getClass());
byte[] resultOriginalByte = jsonStr.getBytes();
//
ByteArrayOutputStream resultBuffer = new ByteArrayOutputStream();
OutputStream os = null;
try {
os = response.getOutputStream();
// 50 ,
if(resultOriginalByte.length < Compress.BYTE_MIN_LENGTH){
byte flagByte = Compress.FLAG_GBK_STRING_UNCOMPRESSED_BYTEARRAY;
resultBuffer.write(flagByte);
resultBuffer.write(resultOriginalByte);
}
else{
byte flagByte = Compress.FLAG_GBK_STRING_COMPRESSED_BYTEARRAY;
resultBuffer.write(flagByte);
resultBuffer.write(Compress.byteCompress(resultOriginalByte));
}
resultBuffer.flush();
resultBuffer.close();
//
os.write(resultBuffer.toByteArray());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally{
try {
os.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return null;
}
제 가 미리 보 낸 데 이 터 는 JSon 형식의 문자열 (GBK 인 코딩) 입 니 다. 이 문자열 의 길 이 를 판단 합 니 다. (압축 에 적합 한 지 판단 합 니 다) 압축 에 적합 하면 버퍼 바이트 배열 (ByteArray OutputStream resultBuffer)FLAG GBK STRING COMPRESSED BYTEARRAY 의 첫 번 째 바이트 에 FLAG GBK STRING STRING BYTEARRAY 를 채 우 고, 마지막 으로 출력 흐름 에 버퍼 바이트 배열 을 기록 하고, 흐름 을 닫 습 니 다. 압축 에 적합 하지 않 으 면 보 낸 데이터 의 첫 번 째 바이트 에 FLAG GBK STRING UNCOMPRESSED BYTEARRAY 를 채 우 고, JSon 문자열 의 바이트 배열 을 직접 채 웁 니 다.데이터 버퍼 바이트 배열 을 저장 하고 출력 흐름 을 기록 하 며 흐름 을 닫 습 니 다.
마지막 으로 Android 클 라 이언 트 의 분석 입 니 다. 위의 Compress 압축 보조 클래스 를 Android 프로젝트 에 복사 하면 됩 니 다. 다음은 Http 요청 후 받 은 바이트 배열 데 이 터 를 분석 합 니 다. (Android 클 라 이언 트 가 Http 를 사용 하여 서버 에 데 이 터 를 요청 하 는 방법 은 이전 블 로 그 를 참고 하 십시오.)
byte[] receivedByte = EntityUtils.toByteArray(httpResponse.getEntity());
String result = null;
//
if (receivedByte[0] == Compress.FLAG_GBK_STRING_UNCOMPRESSED_BYTEARRAY) {
result = new String(receivedByte, 1, receivedByte.length - 1, EXCHANGE_ENCODING);
}
else if (receivedByte[0] == Compress.FLAG_GBK_STRING_COMPRESSED_BYTEARRAY) {
byte[] compressedByte = new byte[receivedByte.length - 1];
for (int i = 0; i < compressedByte.length; i++) {
compressedByte[i] = receivedByte[i + 1];
}
byte[] resultByte = Compress.byteDecompress(compressedByte);
result = new String(resultByte, EXCHANGE_ENCODING);
}
여기 서 마지막 으로 얻 은 result 는 서버 가 실제로 보 낼 내용 입 니 다.
결함 반성: 모든 디자인 에 결함 이 있 습 니 다. 저 는 이렇게 Http 프로 토 콜 을 패키지 로 만 들 었 습 니 다. Http 의 데이터 부분의 첫 번 째 바 이 트 는 실제 데이터 가 아니 라 표지 바이트 입 니 다. 이렇게 하면 이 인터페이스의 재 활용 성 을 낮 출 수 있 습 니 다. JSon 문자열 을 통일 적 으로 보 내 는 Action 은 웹 페이지 (Ajax) 에 보 낼 수 있 습 니 다.또는 다른 클 라 이언 트 가 사용 할 경우, 패 키 징 압축 을 거 친 후, 이 패 키 징 을 식별 할 수 있 는 클 라 이언 트 만 이 인 터 페 이 스 를 사용 할 수 있 습 니 다. 웹 페이지 (Ajax) 는 분석 할 수 없 으 며, 이 Action 은 Ajax 에서 사용 할 수 없습니다.
구체 적 인 개발 과정 에서 구체 적 인 상황 에 따라 정 해 야 합 니 다. 데이터 양 이 적 으 면 표준 Http 프로 토 콜 을 사용 하 는 것 을 권장 합 니 다. 즉, 문자열 을 직접 보 내 고 압축 과 패 키 징 을 하지 않 는 것 입 니 다. 데이터 양 이 너무 많 으 면 상기 방법 을 사용 하 는 것 을 권장 합 니 다.
안 드 로 이 드 애플 리 케 이 션 에 있어 서 어떤 데이터 가 빅 데이터 라 고 할 수 있 느 냐 는 블 로 거들 의 질문 이 있 습 니 다. 이 빅 데이터 의 경 계 는 고정 적 인 것 이 아니 라 10k 이상 이나 100 k 이상 이 빅 데이터 라 고 할 수 있 는 것 이 아니 라 여러 가지 장단 점 으로 평가 되 는 것 이 라 고 생각 합 니 다. 우선 제 가 디자인 한 이 협 의 는 빅 데이터 와 작은 데이터 의 동적 전환 에 적용 되 는 상황 입 니 다.크 고 작은 데이터 경계 에 대한 획 정 은 개발 자 에 게 이 로 움 과 해로 움 을 평가 하도록 맡 깁 니 다. 이 평가 기준 은 다음 과 같은 몇 가지 내용 을 포함해 야 한다 고 생각 합 니 다.
첫째, 압축 알고리즘 의 유효한 임계 점 입 니 다. 압축 할 데이터 가 이 점 보다 커 야 압축 된 데이터 가 더 작 습 니 다. 반대로 압축 된 데 이 터 는 더욱 커 집 니 다. 제 가 사용 하 는 zip 알고리즘 은 이 점 이 50 바이트 정도 일 것 입 니 다. 따라서 제 응용 프로그램 에서 대 수 를 50 바이트 이상 의 데이터 로 정의 합 니 다.
두 번 째: 압축 과 압축 해제 비용 입 니 다. 서버 는 데 이 터 를 압축 해 야 합 니 다. 클 라 이언 트 는 데 이 터 를 압축 해 야 합 니 다. 이것 은 모두 CPU 비용 이 필요 합 니 다. 특히 서버 는 요 구 량 이 많 으 면 모든 응답 데 이 터 를 압축 해 야 합 니 다. 서버 의 성능 을 떨 어 뜨 려 야 합 니 다. 우 리 는 이러한 상황 을 상상 할 수 있 습 니 다. 원생 데 이 터 는 50 바이트 만 있 고 압축 이 끝나 면 40 바이트 가 있 습 니 다. 그러면우 리 는 CPU 를 소모 하여 우리 지역 의 10 개의 바이트 로 압축 할 필요 가 있 는 지 생각해 야 합 니까?
종합 적 으로 이 협 의 는 크기 데이터 의 동적 전환 데이터 전송 에 적합 하지만 빅 데이터 와 작은 데이터 의 분할 점 (얼마나 큰 데 이 터 를 압축 해 야 하 는 지, 얼마나 아래 의 데 이 터 를 압축 할 필요 가 없 는 지 정의 하 는 것) 을 합 리 적 으로 선택 하 는 것 은 잘 평가 해 야 한다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.