2022. 12. 1. 21:22ㆍandroid/Random Chatting
1. Repository
interface Repository {
suspend fun uploadImage(imageUri: String, roomName: String, nickname: String, onResult: (Throwable?)->Unit)
}
먼저, 레포지토리 구현을 위한 인터페이스를 만듭니다.
이름은 원하는 이름으로 만들어줍니다. 레포지토리 안에 이미지 업로드하는 함수 uploadImage를 만들겠습니다.
Repository Implementation을 하기 전 Data 패키지에 Retrofit2 API 인터페이스를 추가하겠습니다.
1. 1 의존성
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation(platform("com.squareup.okhttp3:okhttp-bom:4.10.0"))
implementation("com.squareup.okhttp3:okhttp")
implementation("com.squareup.okhttp3:logging-interceptor")
2. API
interface Api {
@Multipart
@POST("/upload")
fun uploadImage(
@Part image: MultipartBody.Part
) : Call<Result>
}
- 레트로핏을 이용한 파일 전송을 위해 Multipart를 사용합니다.
3. RepositoryImplementation
class RepositoryImpl @Inject constructor(
private val api: Api,
private val context: Context
) : Repository {
private val _context = context
private val gson = GsonBuilder()
.setPrettyPrinting()
.create()
override suspend fun uploadImage(imageUri: String, roomName: String, nickname: String, onResult: (Throwable?)->Unit) {
val file = File(imageUri)
val requestFile = file.asRequestBody("image/*".toMediaTypeOrNull())
val body : MultipartBody.Part = MultipartBody.Part.createFormData("image", file.name, requestFile)
api.uploadImage(body).enqueue(object : Callback<Result> {
override fun onResponse(call: Call<Result>, response: Response<Result>) {
val result = response.body()?.result
val uri = response.body()?.imageUri
if(result == 1) {
CoroutineScope(Dispatchers.Default).launch {
if (uri != null) {
sendImage(imageUri = uri, roomName = roomName, nickname = nickname)
}
onResult(null)
}
}
}
override fun onFailure(call: Call<Result>, t: Throwable) {
onResult(t)
}
})
}
private suspend fun sendImage(imageUri: String, roomName: String, nickname: String) {
val messageGson = Message(nickname = nickname, comment = imageUri)
val messageJson = gson.toJson(messageGson)
val data = JSONObject()
data.put("roomName", roomName)
data.put("message", messageJson)
SocketController.mSocket.emit("newImage", data)
}
}
Interface를 상속받아 upload를 작성해줍니다.
uri는 몇 개의 과정을 거칩니다
1. uri로 파일 생성
2. requestbody로 파일 변환
3. multipartBody.part로 변환
4. api로 업로드
서버 ( Node.js ) 로 보낸 파일은 저장을 마치고 다시 안드로이드쪽으로 서버에 저장된 이미지의 URI를 보내줍니다.
받은 이미지의 URI를 상대방 소켓에 보내는 SendImage 함수를 통해 현재 유저가 있는 채팅방에 닉네임과 주소를 Json 으로 변환 후 emit 을 사용하여 Socket에 보냅니다.
SendImage 함수에 있는 data 변수는 "roomName"이 Key인 방이름과 "message"가 키인 보낼 메시지를 가지고 있는 JSON 오브젝트 입니다.
메시지는 자신의 닉네임, 내용을 담고있습니다.
data 를 보내기 전에 당연히 안에 오브젝트를 담게되면 그것 또한 Json 이어야하는걸 잊으시면 안됩니다.
그래서 Message(nickname = , comments = ) 데이터 클래스로 만든 인스턴스도 Json으로 바꿔줍니다.
그 후에 Data 오브젝트에 넣습니다.
4. ViewModel
@HiltViewModel
class ChattingViewModel @Inject constructor(
private val queryImages: QueryImages,
private val repository: Repository
) : ViewModel() {
var state = mutableStateOf(ChattingState())
private set
private val imageUri get() = state.value.imageUri
private var _nickname: String? = null
private var _roomName: String? = null
fun onImageSend(){
viewModelScope.launch {
repository.uploadImage(imageUri, _roomName!!, _nickname!!) { error ->
if(error!= null) {
Log.d("TAG" ,"사진 업로드에 실패하였습니다. 잠시후 다시 시도 해주시길 바랍니다.")
}
}
currentIndex = null
}
}
}
ViewModel 전체가 아닌 일부입니다. onImageSend만 필요해서 일단 그것만 가져왔습니다.
UI 에서 버튼 클릭 이벤트를 주면 그때 이미지를 전송하는 함수입니다.
이렇게 기본적인 Repository 와 API 에 대해 마무리 하겠습니다.
'android > Random Chatting' 카테고리의 다른 글
android Socket IO Random Chat - 전체 구성 (0) | 2022.12.01 |
---|---|
android Socket IO Random Chat - nickname (0) | 2022.11.28 |
android Socket IO Random Chat - Object Socket (0) | 2022.11.26 |
android Socket IO Random Chat - Socket IO 연결 과정 (0) | 2022.11.26 |
andorid socket IO random chat app 글 시작 (0) | 2022.11.26 |