android Socket IO Random Chat - Repository, Api Image Send

2022. 12. 1. 21:22android/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 에 대해 마무리 하겠습니다.