현재 서버에서 이미지를 binary data로 내려주면 클라이언트에서는 데이터를 읽은 후 byte array로 변환하고 있다. 이전에는 DEPRECATED된 volley 라이브러리를 이용해 Request
를 커스텀하게 수정해서 사용했다.
public class ByteArrayRequest extends Request<byte[]> {
private Response.Listener<byte[]> listener;
…
@Override
protected Response<byte[]> parseNetworkResponse(NetworkResponse response) {
return Response.success(response.data, HttpHeaderParser.parseCacheHeaders(response));
}
그리고 요즘에는 volley에서 Retrofit + RxJava 라이브러리로 변경하는 작업을 진행하는 중이다.
@GET(“books”)
Observable<Result<ResponseBody>> getImage(@Query(“id”) String id);
Retrofit으로 byte[]로 데이터 가져오기
Retrofit은 프로덕션에 적용한 지 얼마 안되었지만 Result
에서 result.response()
를 통해 얻은 객체 Response
에는 크게 body()
와 errorBody()
메소드가 있다. 여기에서 body는 ResponseBody
가 되고 errorBody의 경우, 예를 들어 서버에서 404 코드와 에러 메시지가 포함된 에러 JSON 객체를 내려주면 String
으로 받을 수 있다.
ResponseBody
public final InputStream byteStream() {
return source().inputStream();
}
byte[] bytes() {
…
BufferedSource source = source();
byte[] bytes;
try {
bytes = source.readByteArray();
...
}
String string() {
…
BufferedSource source = source();
try {
Charset charset = Util.bomAwareCharset(source, charset());
return source.readString(charset);
…
}
ReponseBody에서 InputStream
을 가져와서 버퍼로 읽는 방법이나 byte[]
또는 String
으로 서버로 받은 body를 가져올 수 있는데 String
으로 binary 데이터를 읽게 되면 어떻게 될까?
String: ����JFIF��C��C��� ��
�����+�}Yϭ�F39M>���������>���;��ˋ��uXʽ�w�ڤx\-[2g��k�S���H���m
[�V?[_W����#��v��}6�[��F�F�%����n�...
정상적인 이미지를 만들 수 없으므로 byte[]
로 스트림에 있는 데이터를 가져와야 한다. 참고로 body.bytes()
는 구현 코드를 살펴보면 body.source().readByteArray()
와 같은 동작이다.
body.source().readByteArray() : [-1, -40, -1, -32, 0, 16, 74, 70, 73, 70, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, -1, -37, 0, 67, 0, 16, 11, 12, 14, 12, 10, 16, 14, 13, 14, 18, 17, 16, 19, 24, 40, 26, 24, 2 … ]
이미지 Bitmap으로 변환하기
BitmapFactory의 decodeStream
InputStream input = body.byteStream();
Bitmap bitmap = BitmapFactory.decodeStream(input);
BitmapFactory의 decodeByteArray
Bitmap bitmap = BitmapFactory.decodeByteArray(body.bytes(), 0, body.bytes().length);
InputStream
이나 byte array
로 사용해서 쉽게 비트맵으로 이미지를 가져올 수 있다. 그리고 ResponseBody
에 있는 BufferedSource
에서 스트림으로 데이터를 읽기 때문에 주의해야 한다.
An elegant part of the java.io design is how streams can be layered for transformations like encryption and compression. Okio includes its own stream types called Source and Sink that work like InputStream and OutputStream – okio wiki 중에서
사실 위의 2번째 코드에서는 정상적으로 이미지를 그릴 수 없다.
byte[] bytes = body.bytes();
bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
그 이유는 body.byte()
를 호출하게 되면 스트림에 있는 데이터를 모두 읽기 때문에 다음 두 번째 호출 body.byte().length
는 0이 되어 정상적인 Bitmap이 생성되지 않는다.
댓글 남기기