(미완) [Android/Kotlin] 안드로이드에서 node.js 서버로 사진 이미지...

(미완) [Android/Kotlin] 안드로이드에서 node.js 서버로 사진 이미지...

구현하고자 하는 것

안드로이드에서 서버인 node.js 로 갤러리에서 사진 이미지파일을 선택해

서버로 이미지파일 자체를 보내

서버에 이미지가 저장되는 것.

처음 보는 것들이 많아 글이 길어져서

1단계와 2단계로 나누어 쓰겠다

1단계. 갤러리에서 이미지 파일 가져와서 서버에 보내는 형태로 만들기

과정

이미지 uri 가져옴(폰 내의 경로) : result.data.clipData.getItemAt(i).uri 이미지 bitmap가져옴 : BitmapFactory.decodeFile( uri값.toString ) 오류

E/BitmapFactory: Unable to decode stream: java.io.FileNotFoundException: content:/media/external/images/media/84 (No such file or directory)

uri로 비트맵 데이터를 가져오는 과정에서 없는 디렉토리라고 함.....

-> 절대경로를 가져오는 걸로 바꿔볼까?

-> 저 오류 메세지를 구글링해 보니까 내가 uri값이라고 받은 저 media/external/images/media/84 부분은 파일경로가 아니라고 함... uri가 안드로이드에서 파일 경로를 나타내는 형식 이라매???? 아닌거? -> 마지막 동그라미 참고

https://stackoverflow.com/questions/48579302/bitmapfactory-unable-to-decode-stream-java-io-filenotfoundexception-open-fail 이거대로 해봤는데 inputStream을 decodeFile에 넣는 부분에서 이상함. 다른 방법 찾아봄

https://stackoverflow.com/questions/60755040/e-bitmapfactory-unable-to-decode-stream-java-io-filenotfoundexception-no-such 이것도 해보려다가 그동안 봐왔던 방법이랑 너무 다르고 아 뭔가 너무 돌아가는 느낌이라... 아예 다시 찾아봤다

★★ https://stickode.com/detail.html?no=1631 가 친절한 주석들과 함께 내가 시도해 볼 만한.. 내가 하려던 거랑 유사한 코드라 시도해보기로 함

위 글에 나온 방법에서 uri로 절대경로를 가져오는 코드는 내가 다른 곳에서도 본 거 였는데 옛날 자료고 자바 코드라 그런지 쓸 수가 없었다. 코틀린에서 uri로 이미지 절대경로 가져오는 법을 다시 찾아봤다. https://machine-woong.tistory.com/174

근데 여기서도 deprecated된 부분이 있어 해결방법을 찾아봤는데 이 deprecated된 부분을 대체하기 위해서는 결국 사용자가 선택한 이미지 파일을 복사해서 새 경로에 이미지 복사본을 만든 후에 그 파일의 실제경로를 가져와야 한다고 한다. ..^^ (참고 https://stickode.com/detail.html?no=1305)

시도한 방법의 사이트에서 알게 되었는데 uri가 항상 파일경로인 건 아닌가보다.. 이때의 Uri값은, 갤러리앱에서 관리하는 DB정보가 있는데 그 값이라고 한다. 실제 파일 경로가 아니다. Gallery앱의 DB번호라고 한다. (content://--어쩌구--/2854) 업로드를 하려면 이미지의 절대경로(실제 경로)가 필요하다고 한다. (file://---어쩌구--/파일명.png) - 참고 https://stickode.com/detail.html?no=1631 bitmap을 byteArray로 변환함 : ByteArrayOutputStream을 만들어서 bitmap.compress로 ByteArrayOutputStream에 넣고 ByteArrayOutputStream.toByteArray() 함 여기서 R equestBody를 만드는 방법이 대충 두 가지로 갈리는데 이 byteArray로 R equestBody를 만듦 : RequestBody.create( MultiType.parse("image/원하는 확장자", byteArray값) File객체를 만들어 앱 내 저장경로에 byteArray데이터를 저장하고 File객체로 RequestBody를 만듦 : File객체를 만들고 File객체로 FileOutputStream객체를 만든 후 FileOutputStream객체.write(byteArray값) 한 뒤 .flush로 저장함. .close로 FileOutputStream객체 종료함. R equestBody.create( MultiType.parse("image/원하는 확장자", File객체) RequestBody를 MultipartBody.Part.createFormData에 담으면

서버에 보낼 상태인 MultipartBody.Part로 만들기 끝!!

코드

MainActivity.kt

++)

통신에는 retrofit에 @Multipart를 쓴다. (MultipartBody.Part 라는 형태에 이미지를 담아 보낸다.)

가져온 이미지 파일을 RequestBody.create에 MultiType.parse 로 지정하는 타입은 multipart/form-data 와 image/jpg, image/jpeg, image/png, image/* 이렇게 5가지 봤음.

** 나는 4-1말고 4-2 방법을 사용할 건데.. RequestBody에 경로인 File을 담아서 보내는 방법. 그런데 이렇게 했을 때 정말 그냥 File의 경로 정보가 아니라 이미지 파일 자체가 서버에 저장되는 게 맞는지..? 계속 의문이 든다. 공식문서도 찾아보고 블로그 예제들도 찾아봤는데 정확히 어떤 데이터가 전송되어서 어떤 식으로 이미지정보가 서버에 저장되어 작동하는 건지 알 수 없었다. 근데 서버 팀에서 요구한 방법이 4-2이고 이것도 작동은 한다고 하니.. 찝찝한 구석이 있지만 직접 만들어서 실행해보면 해결이 되겠지^^ 일단 만들어보기로 함

2단계. 서버로 보내기(Retrofit 통신)

과정

통신에는 retrofit에 @Multipart를 쓴다. 1단계에서 만든 MultipartBody.Part를 보내자. 이미지와 함께 텍스트 데이터도 보내고 싶다면, 텍스트들을 RequestBody로 만든 후 HashMap형태로 모아 보내야 한다. (**숫자 자료형들은 String으로 변환해야 함)

이 경우 이미지 데이터를 담은 MultiPartBody와 텍스트 데이터를 담은 HashMap 이렇게 두 개를 보내게 된다.

이건 뭐 그냥 Retrofit 통신 하던대로 하면 된다. 파라미터가 두 개라는 것만 다를 뿐.

코드

ServiceApiInterface.kt

RetrofitClient.kt

MainActivity.kt

알게 된 것들과 의문

Bitmap 비트맵 : 안드로이에서 이미지를 표현하기 위해 사용되는 객체로, 메모리의 모든 이미지는 비트맵객체로 관리된다. 프로그래밍으로 비트맵 객체를 직접 만들 수도 있다.

ByteArray : 말 그대로 byte의 배열. byte[]

Bitmap과 ByteArray는 상호변환이 가능하다. -> 왜? 왜 가능하지? 그리고 이미지를 서버로 보낼 때 byteArray로 변환해서 보내는 경우가 많던데 왜 bytearray로 변환하는 거지? bitmap자체로는 보낼수가 없나?

Bitmap과 ByteArray 상호변환 방법

1. Bitmap을 ByteArray로

: ByteArrayOutputStream 인터페이스 생성 - Bitmap.compress(..) 로 비트맵을 압축하여 인터페이스에 넣음 - 인터페이스.toByteArray() 로 byteArray 객체 생성.

2. ByteArray를 Bitmap로

: BitmapFactory.decodeByteArray(..) 로 바로 변환

java.io.File

앱 내부 저장경로에 데이터나 파일을 저장하고 읽어올 때 사용.

파일 데이터 자체를 의미하는 건 아니고 경로를 의미하는 것에 가까움. 해당 경로의 파일에 접근해 여러 작업 가능.

자바코드로 new File(파일명이 포함된 경로) 이렇게 하면 이 객체를 활용해 해당 경로에 접근해(또는 해당 경로에 파일을 생성해) 저장/읽기를 할 수 있음.

저장 시 OutputStream이나 FileOutputStream등을 활용하고, 읽기 시 file객체를 사용해 해당 경로의 파일을 읽어와 어떤 작업을 함.

참고

android 와 node.js 간 이미지 전송 깃허브 레포 https://github.com/1022pkh/ImgUploadTest/blob/e5d8d2e15209fb63880cbcf8b052b37ca85eca27/app/src/main/java/sopt/com/imgtest/MainActivity.java#L177

android 이미지 업/다운로드 블로그 글 https://angangmoddi.tistory.com/236

retrofit과 multipart사용해 글과 이미지 한번에 서버로 보내기 https://velog.io/@1106laura/Retrofit%EC%97%90%EC%84%9C-Multipart-%EC%84%9C%EB%B2%84-%ED%86%B5%EC%8B%A0-with-Kotlin

retrofit과 multipart사용해 글과 이미지 한번에 서버로 보내기2. 이 분은 File이 아니라 ByteArray로 RequestBody를 만듦. https://bubblebubble.tistory.com/15

retrofit과 multipart사용해 이미지 여러장과 텍스트 한번에 서버로 보내기 https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId;=greatsk553&logNo;=221002404453

bitmap과 byteArray 상호 변환 방법 깔끔정리 https://techlog.gurucat.net/44

File 즉 java.io.File 에 대한 설명(코틀린에서의 File도 이 File임) https://dololak.tistory.com/436

okhttp공식문서의 toRequestBody 설명. asRequestBody와 toMediaType도 검색하면 나온다. https://square.github.io/okhttp/4.x/okhttp/okhttp3/-request-body/to-request-body/

from http://onedaythreecoding.tistory.com/42 by ccl(A) rewrite - 2021-09-16 22:28:15